vrrpd: compute VRRPv3 checksum

Correctly compute VRRPv3 checksum. Pseudoheaders are used for both IPv4
and IPv6.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
Quentin Young 2019-01-22 22:49:58 +00:00
parent 17b48d7d11
commit 8071d5c3e3
4 changed files with 33 additions and 10 deletions

View File

@ -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;

View File

@ -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];

View File

@ -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;
}

View File

@ -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);
/*