From: Quentin Young Date: Fri, 7 Dec 2018 23:36:09 +0000 (+0000) Subject: vrrpd: fix packet encode X-Git-Tag: base_7.2~330^2~140 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=3eca38577afdd262e72740f16e0b1a6057d0aed6;p=mirror%2Ffrr.git vrrpd: fix packet encode * Properly encode VRRP packets * Calculate checksum appropriately * Update signature to provide caller both packet and result length Signed-off-by: Quentin Young --- diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index a5eb40fda8..608be06a0c 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -19,32 +19,48 @@ */ #include -#include "memory.h" -#include "ipaddr.h" +#include "lib/memory.h" +#include "lib/ipaddr.h" +#include "lib/checksum.h" #include "vrrp_packet.h" -/* - * Builds a VRRP packet. - */ -struct vrrp_pkt *vrrp_pkt_build(uint8_t vrid, uint8_t prio, - uint16_t max_adver_int, bool v6, uint8_t numip, - void **ips) +ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, + uint16_t max_adver_int, bool v6, uint8_t numip, + void **ips) { + /* Used for pointer math when filling IPvX field */ + struct in6_addr *v6ptr; + struct in_addr *v4ptr; + size_t addrsz = v6 ? sizeof(struct in6_addr) : sizeof(struct in_addr); - struct vrrp_pkt *pkt = - XCALLOC(MTYPE_TMP, sizeof(struct vrrp_pkt) + addrsz * numip); - - pkt->hdr.version = VRRP_VERSION; - pkt->hdr.type = VRRP_TYPE_ADVERTISEMENT; - pkt->hdr.vrid = vrid; - pkt->hdr.priority = prio; - pkt->hdr.v3.rsvd = 0; - pkt->hdr.v3.adver_int = max_adver_int; - for (uint8_t i = 0; i < numip; i++) - memcpy(&pkt->addrs[i].v4, ips[i], addrsz); - /* FIXME */ - pkt->hdr.chksum = 0; - - return pkt; + size_t pktsize = sizeof(struct vrrp_hdr) + addrsz * numip; + *pkt = XCALLOC(MTYPE_TMP, pktsize); + + v6ptr = (struct in6_addr *) (*pkt)->addrs; + v4ptr = (struct in_addr *) (*pkt)->addrs; + + (*pkt)->hdr.vertype |= VRRP_VERSION << 4; + (*pkt)->hdr.vertype |= VRRP_TYPE_ADVERTISEMENT; + (*pkt)->hdr.vrid = vrid; + (*pkt)->hdr.priority = prio; + (*pkt)->hdr.naddr = numip; + (*pkt)->hdr.v3.adver_int = htons(max_adver_int); + + char buf[INET_ADDRSTRLEN]; + for (int i = 0; i < numip; i++) { + /* If v4, treat as array of v4 addresses */ + inet_ntop(AF_INET, ips[i], buf, sizeof(buf)); + if (!v6) + memcpy(&v4ptr[i], ips[i], addrsz); + else + memcpy(&v6ptr[i], ips[i], addrsz); + inet_ntop(AF_INET, &v4ptr[i], buf, sizeof(buf)); + } + (*pkt)->hdr.chksum = 0; + + uint16_t chksum = in_cksum(*pkt, pktsize); + (*pkt)->hdr.chksum = htons(chksum); + + return pktsize; } diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h index 5ff08f95fe..245fada064 100644 --- a/vrrpd/vrrp_packet.h +++ b/vrrpd/vrrp_packet.h @@ -30,8 +30,12 @@ * Shared header for VRRPv2/v3 packets. */ struct vrrp_hdr { - uint8_t version : 4; - uint8_t type : 4; + /* + * H L H L + * 0000 0000 + * ver type + */ + uint8_t vertype; uint8_t vrid; uint8_t priority; uint8_t naddr; @@ -42,9 +46,13 @@ struct vrrp_hdr { uint8_t adver_int; } v2; struct { - /* advertisement interval (in centiseconds) */ - uint16_t rsvd : 4; - uint16_t adver_int : 12; + /* + * advertisement interval (in centiseconds) + * H L H L + * 0000 000000000000 + * rsvd adver_int + */ + uint16_t adver_int; } v3; }; uint16_t chksum; @@ -60,7 +68,29 @@ struct vrrp_pkt { /* * Builds a VRRP packet. + * + * pkt + * Pointer to store pointer to result buffer in + * + * vrid + * Virtual Router Identifier + * + * prio + * Virtual Router Priority + * + * max_adver_int + * time between ADVERTISEMENTs + * + * v6 + * whether 'ips' is an array of v4 or v6 addresses + * + * numip + * number of IPvX addresses in 'ips' + * + * ips + * array of pointer to either struct in_addr (v6 = false) or struct in6_addr + * (v6 = true) */ -struct vrrp_pkt *vrrp_pkt_build(uint8_t vrid, uint8_t prio, - uint16_t max_adver_int, bool v6, uint8_t numip, - void **ips); +ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, + uint16_t max_adver_int, bool v6, uint8_t numip, + void **ips);