]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
DHCP: Fix strict aliasing of checksumming the pseudo header
authorRoy Marples <roy@marples.name>
Wed, 16 Oct 2019 13:56:21 +0000 (14:56 +0100)
committerRoy Marples <roy@marples.name>
Wed, 16 Oct 2019 13:56:21 +0000 (14:56 +0100)
in_cksum relies on accessing the data by uint16_t blocks.

Because the underlying object we send to in_cksum is struct ip,
we need to use union to allow access by uint16_t so strict aliasing
rules are not broken.

src/dhcp.c

index c989843bcb5da25c0516b46525f45d896e10a742..356b7708a7c9ad8a3c103d8345b8b097cc1ef86d 100644 (file)
@@ -3313,13 +3313,15 @@ checksums_valid(void *packet,
     struct in_addr *from, unsigned int flags)
 {
        struct ip *ip = packet;
-       struct ip pseudo_ip = {
-               .ip_p = IPPROTO_UDP,
-               .ip_src = ip->ip_src,
-               .ip_dst = ip->ip_dst
+       union pip {
+               struct ip ip;
+               uint16_t w[sizeof(struct ip)];
+       } pip = {
+               .ip.ip_p = IPPROTO_UDP,
+               .ip.ip_src = ip->ip_src,
+               .ip.ip_dst = ip->ip_dst,
        };
        size_t ip_hlen;
-       uint16_t udp_len, uh_sum;
        struct udphdr udp;
        char *udpp, *uh_sump;
        uint32_t csum;
@@ -3341,22 +3343,23 @@ checksums_valid(void *packet,
 
        /* UDP checksum is based on a pseudo IP header alongside
         * the UDP header and payload. */
-       udp_len = ntohs(udp.uh_ulen);
-       uh_sum = udp.uh_sum;
+       pip.ip.ip_len = udp.uh_ulen;
+       csum = 0;
 
        /* Need to zero the UDP sum in the packet for the checksum to work. */
        uh_sump = udpp + offsetof(struct udphdr, uh_sum);
        memset(uh_sump, 0, sizeof(udp.uh_sum));
 
-       pseudo_ip.ip_len = udp.uh_ulen;
-       csum = 0;
-       in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum);
-       csum = in_cksum(udpp, udp_len, &csum);
+       /* Checksum psuedo header and then UDP + payload. */
+       in_cksum(pip.w, sizeof(pip.w), &csum);
+       csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum);
 
+#if 0  /* Not needed, just here for completeness. */
        /* Put the checksum back. */
-       memcpy(uh_sump, &uh_sum, sizeof(udp.uh_sum));
+       memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum));
+#endif
 
-       return csum == uh_sum;
+       return csum == udp.uh_sum;
 }
 
 static void