From: Jan Klemkow Subject: Re: dhcp daemon checksum fix To: Alexander Bluhm Cc: tech@openbsd.org, Markus Friedl Date: Fri, 7 Feb 2025 22:40:05 +0100 On Tue, Feb 04, 2025 at 10:32:12PM GMT, Alexander Bluhm wrote: > When sending traffic via vio(4) between guests living within a > single KVM host, the packet checksum is never calculated. A flag > is set to assume the checksum is correct. Our IP stack handles > that correctly but when using bpf(4) userland has to care. > > jan@ has fixed it for dhcpleased a while ago. > > ---------------------------- > revision 1.42 > date: 2024/01/26 21:14:08; author: jan; state: Exp; lines: +17 -12; commitid: nvgEHwLOyfqqyGwh; > Put checksum flags in bpf_hdr to use them in userland dhcpleased. > > Thus, dhcpleased accept non-calculated checksums which were verified by > hardware/hypervisor. > > With tweaks from dlg@ > > ok bluhm@ > mkay tobhe@ > ---------------------------- > > But our other dhcp daemons suffer from the same problem. Below is > the diff for dhcpd(8), dhcrelay(8), and dhcrelay6(8). > > While there, I discovered that checksum calculation is suboptimal. > To verify, calculate the checksum of the received packet and it has > to be 0. That is what RFC 1071 says and our kernel does. > > I did run dhcpleased on a KVM guest and markus@ tested dhcpd. > > If you run any of these daemons on KVM guest, please test. > > ok? I tested and reviewd the dhcpleased part. Works and looks correct. ok jan@ > Index: sbin/dhcpleased/engine.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sbin/dhcpleased/engine.c,v > diff -u -p -r1.55 engine.c > --- sbin/dhcpleased/engine.c 21 Nov 2024 13:35:20 -0000 1.55 > +++ sbin/dhcpleased/engine.c 16 Jan 2025 20:14:10 -0000 > @@ -744,7 +744,7 @@ parse_dhcp(struct dhcpleased_iface *ifac > struct in_addr nameservers[MAX_RDNS_COUNT]; > struct dhcp_route routes[MAX_DHCP_ROUTES]; > size_t rem, i; > - uint32_t sum, usum, lease_time = 0, renewal_time = 0; > + uint32_t lease_time = 0, renewal_time = 0; > uint32_t rebinding_time = 0; > uint32_t ipv6_only_time = 0; > uint8_t *p, dho = DHO_PAD, dho_len, slen; > @@ -850,16 +850,14 @@ parse_dhcp(struct dhcpleased_iface *ifac > p += sizeof(*udp); > rem -= sizeof(*udp); > > - if ((dhcp->csumflags & M_UDP_CSUM_IN_OK) == 0) { > - usum = udp->uh_sum; > - udp->uh_sum = 0; > - > - sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp), > + if ((dhcp->csumflags & M_UDP_CSUM_IN_OK) == 0 && > + udp->uh_sum != 0) { > + udp->uh_sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp), > checksum(p, rem, > checksum((uint8_t *)&ip->ip_src, 2 * sizeof(ip->ip_src), > IPPROTO_UDP + ntohs(udp->uh_ulen))))); > > - if (usum != 0 && usum != sum) { > + if (udp->uh_sum != 0) { > log_warnx("%s: bad UDP checksum", __func__); > return; > }