From 8071d5c3e30a68d7bb9ca1bbf48b45f64b459a12 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 22 Jan 2019 22:49:58 +0000 Subject: [PATCH] vrrpd: compute VRRPv3 checksum Correctly compute VRRPv3 checksum. Pseudoheaders are used for both IPv4 and IPv6. Signed-off-by: Quentin Young --- vrrpd/vrrp.c | 12 +++++++++--- vrrpd/vrrp.h | 3 +++ vrrpd/vrrp_packet.c | 24 +++++++++++++++++++----- vrrpd/vrrp_packet.h | 4 ++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 93ede7b88f..fcc1cec51c 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -327,7 +327,7 @@ static void vrrp_send_advertisement(struct vrrp_router *r) list_to_array(r->addrs, (void **)addrs, r->addrs->count); - pktlen = vrrp_pkt_build(&pkt, r->vr->vrid, r->priority, + pktlen = vrrp_pkt_build(&pkt, &r->src, r->vr->vrid, r->priority, r->vr->advertisement_interval, r->addrs->count, (struct ipaddr **)&addrs); @@ -347,8 +347,8 @@ static void vrrp_send_advertisement(struct vrrp_router *r) if (sent < 0) { zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID - "Failed to send VRRP Advertisement", - r->vr->vrid); + "Failed to send VRRP Advertisement: %s", + r->vr->vrid, safe_strerror(errno)); } } @@ -523,6 +523,8 @@ done: * router's interface and binds the Tx socket of the VRRP router to that * address. * + * Also sets src field of vrrp_router. + * * r * VRRP router to operate on * @@ -559,10 +561,14 @@ static int vrrp_bind_to_primary_connected(struct vrrp_router *r) switch (r->family) { case AF_INET: + r->src.ipa_type = IPADDR_V4; + r->src.ipaddr_v4 = c->address->u.prefix4; su.sin.sin_family = AF_INET; su.sin.sin_addr = c->address->u.prefix4; break; case AF_INET6: + r->src.ipa_type = IPADDR_V6; + r->src.ipaddr_v6 = c->address->u.prefix6; su.sin6.sin6_family = AF_INET6; su.sin6.sin6_scope_id = ifp->ifindex; su.sin6.sin6_addr = c->address->u.prefix6; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index 98948a76fc..f68ff85224 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -75,6 +75,9 @@ struct vrrp_router { /* macvlan interface */ struct interface *mvl_ifp; + /* Source address for advertisements */ + struct ipaddr src; + /* Socket read buffer */ uint8_t ibuf[IP_MAXPACKET]; diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 5010b4701d..8147da68e0 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -26,6 +26,7 @@ #include "lib/ipaddr.h" #include "lib/memory.h" +#include "vrrp.h" #include "vrrp_packet.h" /* clang-format off */ @@ -49,8 +50,8 @@ const char *vrrp_packet_names[16] = { }; /* clang-format on */ -ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, - uint16_t max_adver_int, uint8_t numip, +ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint8_t vrid, + uint8_t prio, uint16_t max_adver_int, uint8_t numip, struct ipaddr **ips) { bool v6 = IS_IPADDR_V6(ips[0]); @@ -72,11 +73,24 @@ ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, memcpy(aptr, &ips[i]->ip.addr, addrsz); aptr += addrsz; } + (*pkt)->hdr.chksum = 0; - /* FIXME: v6 checksum */ - uint16_t chksum = in_cksum(*pkt, pktsize); - (*pkt)->hdr.chksum = htons(chksum); + if (v6) { + struct ipv6_ph ph = {}; + ph.src = src->ipaddr_v6; + inet_pton(AF_INET6, VRRP_MCASTV6_GROUP_STR, &ph.dst); + ph.ulpl = htons(pktsize); + ph.next_hdr = 112; + (*pkt)->hdr.chksum = in_cksum_with_ph6(&ph, *pkt, pktsize); + } else { + struct ipv4_ph ph = {}; + ph.src = src->ipaddr_v4; + inet_pton(AF_INET, VRRP_MCASTV4_GROUP_STR, &ph.dst); + ph.proto = 112; + ph.len = htons(pktsize); + (*pkt)->hdr.chksum = in_cksum_with_ph4(&ph, *pkt, pktsize); + } return pktsize; } diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h index 7a4a338dae..3a5b161fb7 100644 --- a/vrrpd/vrrp_packet.h +++ b/vrrpd/vrrp_packet.h @@ -115,8 +115,8 @@ struct vrrp_pkt { * array of pointer to either struct in_addr (v6 = false) or struct in6_addr * (v6 = true) */ -ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, - uint16_t max_adver_int, uint8_t numip, +ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, struct ipaddr *src, uint8_t vrid, + uint8_t prio, uint16_t max_adver_int, uint8_t numip, struct ipaddr **ips); /* -- 2.39.5