]> git.puffer.fish Git - matthieu/frr.git/commitdiff
vrrpd: check rx'd advertisement checksum
authorQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 1 Feb 2019 20:54:44 +0000 (20:54 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
And retrieve source address, since we need it anyway.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
vrrpd/vrrp.c
vrrpd/vrrp_packet.c
vrrpd/vrrp_packet.h

index edac0f66cbbca9941d16a7afce975bb2f8e514e4..411c3c7e7b0bfed882143c0b491a85940d124183 100644 (file)
@@ -568,6 +568,7 @@ static int vrrp_read(struct thread *thread)
        bool resched;
        char errbuf[BUFSIZ];
        uint8_t control[64];
+       struct ipaddr src = {};
 
        struct msghdr m;
        struct iovec iov;
@@ -595,8 +596,8 @@ static int vrrp_read(struct thread *thread)
                   r->vr->vrid, family2str(r->family));
        zlog_hexdump(r->ibuf, nbytes);
 
-       pktsize = vrrp_pkt_parse_datagram(r->family, &m, nbytes, &pkt, errbuf,
-                                         sizeof(errbuf));
+       pktsize = vrrp_pkt_parse_datagram(r->family, &m, nbytes, &src, &pkt,
+                                         errbuf, sizeof(errbuf));
 
        if (pktsize < 0) {
                zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
@@ -847,7 +848,9 @@ static int vrrp_socket(struct vrrp_router *r)
                                "Failed to set outgoing multicast hop count to 255; RFC 5798 compliant implementations will drop our packets",
                                r->vr->vrid);
                }
-               ret = setsockopt_ipv6_hoplimit(r->sock_rx, 1);
+
+               /* Request hop limit delivery */
+               setsockopt_ipv6_hoplimit(r->sock_rx, 1);
                if (ret < 0) {
                        zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
                                  "Failed to request IPv6 Hop Limit delivery",
index 2d5129b285eae43a3a5d010c368709cea5dd1aaf..ccfdd8f883bf97e3533ff6cdbc18c4be4d699c2c 100644 (file)
@@ -162,8 +162,8 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt)
 }
 
 ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
-                               struct vrrp_pkt **pkt, char *errmsg,
-                               size_t errmsg_len)
+                               struct ipaddr *src, struct vrrp_pkt **pkt,
+                               char *errmsg, size_t errmsg_len)
 {
        /* Source (MAC & IP), Dest (MAC & IP) TTL validation done by kernel */
        size_t addrsz = (family == AF_INET) ? sizeof(struct in_addr)
@@ -207,6 +207,10 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
 
                /* IP empty packet check */
                VRRP_PKT_VCHECK(pktsize > 0, "IPv4 packet has no payload");
+
+               /* Extract source address */
+               src->ipa_type = IPADDR_V4;
+               src->ipaddr_v4 = ip->ip_src;
        } else if (family == AF_INET6) {
                struct cmsghdr *c;
                for (c = CMSG_FIRSTHDR(m); c != NULL; CMSG_NXTHDR(m, c)) {
@@ -224,6 +228,12 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
 
                *pkt = (struct vrrp_pkt *)buf;
                pktsize = read;
+
+               /* Extract source address */
+               src->ipa_type = IPADDR_V6;
+               struct sockaddr_in6 *sa = m->msg_name;
+               memcpy(&src->ipaddr_v6, &sa->sin6_addr,
+                      sizeof(struct in6_addr));
        } else {
                assert(!"Unknown address family");
        }
@@ -239,6 +249,13 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
        VRRP_PKT_VCHECK(pktsize <= maxsize,
                        "VRRP packet is oversized (%lu > %lu)", pktsize,
                        VRRP_MAX_PKT_SIZE);
+
+       /* Checksum check */
+       uint16_t chksum = vrrp_pkt_checksum(*pkt, pktsize, src);
+       VRRP_PKT_VCHECK((*pkt)->hdr.chksum == chksum,
+                       "Bad VRRP checksum %" PRIu16 "; should be %" PRIu16 "",
+                       (*pkt)->hdr.chksum, chksum);
+
        /* Version check */
        VRRP_PKT_VCHECK(((*pkt)->hdr.vertype >> 4) != 2, "VRPPv2 unsupported");
        VRRP_PKT_VCHECK(((*pkt)->hdr.vertype >> 4) == 3, "Bad version %u",
@@ -249,8 +266,6 @@ ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
        /* # addresses check */
        size_t ves = VRRP_PKT_SIZE(family, (*pkt)->hdr.naddr);
        VRRP_PKT_VCHECK(pktsize == ves, "Packet has incorrect # addresses");
-       /* FIXME: checksum check */
-       /* ... */
 
        /* Addresses check */
        char vbuf[INET6_ADDRSTRLEN];
index ed577ddcfa3aa739808c6b567b371001c9401806..af512877188331a4f3e5b465155f497a7572ae3e 100644 (file)
@@ -165,6 +165,9 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt);
  * read
  *    return value of recvmsg() on VRRP router socket; must be non-negative
  *
+ * src
+ *    Pointer to struct ipaddr to store address of datagram sender
+ *
  * pkt
  *    Pointer to pointer to set to location of VRRP packet within buf
  *
@@ -179,7 +182,7 @@ size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt);
  *    Size of VRRP packet, or -1 upon error
  */
 ssize_t vrrp_pkt_parse_datagram(int family, struct msghdr *m, size_t read,
-                               struct vrrp_pkt **pkt, char *errmsg,
-                               size_t errmsg_len);
+                               struct ipaddr *src, struct vrrp_pkt **pkt,
+                               char *errmsg, size_t errmsg_len);
 
 #endif /* __VRRP_PACKET_H__ */