dhcpcd-discuss

Re: udp checksum problems with dhcpcd v8.1.0

Giorgio Dal Molin

Tue Oct 15 14:33:41 2019

> On October 15, 2019 at 4:21 PM Roy Marples <roy@xxxxxxxxxxxx> wrote:
> 
> 
> Hi Giorgio
> On 15/10/2019 09:02, Giorgio Dal Molin wrote:
> > after updating dhcpcd from v8.0.6 to v8.1.0 I'm getting the following udp
> > checksum errors:
> > 
> > ~ # dhcpcd -d eth1
> > dhcpcd-8.1.0 starting
> > eth1: executing `//lib/dhcpcd/dhcpcd-run-hooks' PREINIT
> > eth1: executing `//lib/dhcpcd/dhcpcd-run-hooks' CARRIER
> > DUID 00:04:03:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
> > eth1: IAID d6:14:c2:b9
> > eth1: adding address fe80::e30:7021:c623:ad0f
> > eth1: pltime infinity, vltime infinity
> > eth1: delaying IPv6 router solicitation for 0.1 seconds
> > eth1: delaying IPv4 for 0.2 seconds
> > eth1: soliciting an IPv6 router
> > eth1: delaying Router Solicitation for LL address
> > eth1: soliciting a DHCP lease
> > eth1: sending DISCOVER (xid 0x65e41544), next in 4.7 seconds
> > eth1: checksum failure from 172.18.4.226
> > eth1: sending Router Solicitation
> > eth1: sending DISCOVER (xid 0x65e41544), next in 8.1 seconds
> > eth1: checksum failure from 172.18.4.226
> > eth1: checksum failure from 172.18.4.226
> > eth1: probing for an IPv4LL address
> > eth1: probing for 169.254.78.153
> > eth1: ARP probing 169.254.78.153 (1 of 3), next in 1.4 seconds
> > eth1: sending Router Solicitation
> > eth1: checksum failure from 172.18.4.225
> > eth1: ARP probing 169.254.78.153 (2 of 3), next in 1.6 seconds
> > eth1: ARP probing 169.254.78.153 (3 of 3), next in 2.0 seconds
> > eth1: sending Router Solicitation
> > eth1: using IPv4LL address 169.254.78.153
> > eth1: adding IP address 169.254.78.153/16 broadcast 169.254.255.255
> > eth1: adding route to 169.254.0.0/16
> > eth1: adding default route
> > eth1: ARP announcing 169.254.78.153 (1 of 2), next in 2.0 seconds
> > eth1: executing `//lib/dhcpcd/dhcpcd-run-hooks' IPV4LL
> > forking to background
> > forked to background, child pid 22198
> > 
> > I've bisected this on the git repo to the following commit:
> > 
> > f198ce2b2b1df1febe0cb64ecd023a5ecb1c0bbf is the first bad commit
> > commit f198ce2b2b1df1febe0cb64ecd023a5ecb1c0bbf
> > Author: Roy Marples <roy@xxxxxxxxxxxx>
> > Date: Fri Oct 11 11:24:38 2019 +0100
> > 
> >  BPF: Move validation logic from BPF to consumers
> >  
> >  Even though we program the BPF filter should we trust it?
> >  On Linux at least there is a window between opening the socket,
> >  binding the interface and setting the filter where we receive data.
> >  This data is NOT checked OR flushed and IS returned when reading.
> >  We have no way of flushing it other than reading these packets!
> >  But we don't know if they passed the filter or not ..... so we need
> >  to validate each and every packet that comes through ourselves as well.
> >  Even if Linux does fix this sorry state, who is to say other kernels
> >  don't have bugs causing a similar effect?
> >  
> >  As such, let's strive to keep the filters just for pattern matching
> >  to avoid waking dhcpcd up.
> > 
> >  src/arp.c | 53 ++++++++++++++++++----------
> >  src/bpf.c | 81 ++++---------------------------------------
> >  src/bpf.h | 19 ++++++++++
> >  src/dhcp.c | 108 ++++++++++++++++++++++++++++-----------------------------
> >  src/if-linux.c | 49 +++++++++++++++-----------
> >  5 files changed, 142 insertions(+), 168 deletions(-)
> > 
> > Inspecting the changes to the function 'checksums_valid()' in 'src/dhcp.c' they
> > look a bit messed up:
> > 
> > /* Lengths have already been checked. */
> > static bool
> > 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
> >  };
> >  size_t ip_hlen;
> >  uint16_t udp_len, uh_sum;
> >  struct udphdr *udp;
> >  uint32_t csum;
> > 
> >  if (from != NULL)
> >  from->s_addr = ip->ip_src.s_addr;
> > 
> >  ip_hlen = (size_t)ip->ip_hl * 4;
> >  if (in_cksum(ip, ip_hlen, NULL) != 0)
> >  return false;
> > 
> >  if (flags & BPF_PARTIALCSUM)
> >  return 0;
> > 
> >  udp = (struct udphdr *)(void *)((char *)ip + ip_hlen);
> >  if (udp->uh_sum == 0)
> >  return 0;
> > 
> >  /* 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;
> >  udp->uh_sum = 0;
> >  pseudo_ip.ip_len = udp->uh_ulen;
> >  csum = 0;
> >  in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum);
> >  csum = in_cksum(udp, udp_len, &csum);
> >  return csum == uh_sum;
> > }
> > 
> > you changed it to return a bool but a couple of return 0; were forgotten,
> > a very 'unfortunate circumstance'.
> 
> Yes, I've already pushed some commits, but this patch is the 
> combination. Does it fix it for you?
> 
> Roy

Hi,

a quick test says no! the current master is still broken, v8.0.6 works.

I'll put a couple of debug printf's in the code and find exactly where it
fails.

giorgio

Follow-Ups:
Re: udp checksum problems with dhcpcd v8.1.0Roy Marples
References:
udp checksum problems with dhcpcd v8.1.0Giorgio Dal Molin
Re: udp checksum problems with dhcpcd v8.1.0Roy Marples
Archive administrator: postmaster@marples.name