Subject: Re: kern/32874: pf(4)'s route-to feature is not working properly, checksum errors
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Peter Postma <peter@pointless.nl>
List: netbsd-bugs
Date: 02/19/2006 10:35:03
The following reply was made to PR kern/32874; it has been noted by GNATS.

From: Peter Postma <peter@pointless.nl>
To: ndehne@gmail.com
Cc: gnats-bugs@netbsd.org
Subject: Re: kern/32874: pf(4)'s route-to feature is not working properly, checksum errors
Date: Sun, 19 Feb 2006 11:31:37 +0100

 --6TrnltStXW4iwmi0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 On Sun, Feb 19, 2006 at 07:20:00AM +0000, ndehne@gmail.com wrote:
 > >Number:         32874
 > >Category:       kern
 > >Synopsis:       pf(4)'s route-to feature is not working properly, checksum errors
 > >Confidential:   no
 > >Severity:       critical
 > >Priority:       high
 > >Responsible:    kern-bug-people
 > >State:          open
 > >Class:          sw-bug
 > >Submitter-Id:   net
 > >Arrival-Date:   Sun Feb 19 07:20:00 +0000 2006
 > >Originator:     Nino Dehne
 > >Release:        
 > >Organization:
 > >Environment:
 > NetBSD [...] 3.99.15 NetBSD 3.99.15 (WRAP) #0: Sat Feb 18 22:26:43 CET 2006  [...]:/var/tmp/wrap/HEAD/obj/sys/arch/i3
 > 86/compile/WRAP i386
 > 
 > Problem exists on recent 3.0_STABLE as well.
 > >Description:
 > I have a router doing NAT and routing some IPv6 networks. It looks like this:
 >             |<------------ router --------->|
 >              pppoe0-tap0\               sip0 (unused)
 >              pppoe1-tap1--bridge0       sip1-----------LAN
 >              pppoe2-tap2//
 > DSL-----------------sip2/         gif0
 > 
 > The bridge(4)+tap(4) setup is necessary in order to be able to use multiple PPPoE accounts here, see http://blog.gmane.org/gmane.os.netbsd.devel.network/day=20050627.
 > 
 > pppoe0 carries a dynamic IPv4 address and the IPv4 default route as well as a gif0 tunnel with IPv6 net A and the IPv6 default route.
 > 
 > pppoe1 has a static IPv4 address.
 > 
 > pppoe2 has a native IPv6 network B.
 > 
 > In order to properly route outgoing traffic from the static IPv4 address as well as IPv6 network B, I'm using pf(4)'s route-to feature with a rule set that looks like this:
 > 
 > ext4_dyn_if = "pppoe0"
 > ext4_fix_if = "pppoe1"
 > ext6_if     = "pppoe2"
 > ext6_net    = "<IPv6 network B>"
 > ext6_def_if = "gif0"
 > 
 > # disabling scrubbing doesn't make the problem go away
 > scrub in all
 > scrub out all random-id max-mss 1452
 > 
 > pass out quick on $ext4_dyn_if route-to $ext4_fix_if inet from ($ext4_fix_if) to any
 > pass out quick on $ext6_def_if route-to $ext6_if inet6 from $ext6_net to any
 > 
 > Apart from some RFC1918 blocking rules and nat + rdr, the rule set is empty and default-pass.
 > 
 > This works for the IPv6 network B, i.e. traffic from that network is successfully routed out over pppoe2. However, outgoing IPv4 packets from the static address give me checksum errors, no matter what protocol I use (ICMP, UDP, TCP). I used Ethereal between the DSL modem and pppoe1 to visualize the problem.
 > 
 > Notice the lines
 > 
 > 0030  00 00 22 eb f6 43 c1 9d 02 00 08 09 0a 0b 0c 0d
 >                                     ^^ ^^
 > vs.
 > 
 > 0030  00 00 22 eb f6 43 c1 9d 02 00 00 00 0a 0b 0c 0d
 >                                     ^^ ^^
 
 I've attached a patch which might solve this (thanks to Daniel and der Mouse).
 Can you please try it and report to me if it works?
 If it works I'll (finally!) commit it.
 
 Thanks,
 -- 
 Peter Postma
 
 --6TrnltStXW4iwmi0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="pf.patch"
 
 --- pf.c.old	2006-02-19 10:32:29.000000000 +0100
 +++ pf.c	2006-02-18 15:59:37.000000000 +0100
 @@ -5371,9 +5371,6 @@
  	struct pf_addr		 naddr;
  	struct pf_src_node	*sn = NULL;
  	int			 error = 0;
 -#ifdef __NetBSD__
 -	struct tcphdr		 th;
 -#endif
  
  	if (m == NULL || *m == NULL || r == NULL ||
  	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
 @@ -5499,10 +5496,10 @@
  		}
  	}
  #else
 -	m_copydata(m0, sizeof(*ip), sizeof(th), &th);
 -	th.th_sum = 0;
 -	m_copyback(m0, sizeof(*ip), sizeof(th), &th);
 -	in4_cksum(m0, IPPROTO_TCP, sizeof(*ip), m0->m_pkthdr.len - sizeof(*ip));
 +	if (m0->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
 +		in_delayed_cksum(m0);
 +		m0->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
 +	}
  #endif
  
  	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
 @@ -5518,6 +5515,8 @@
  #else
  		ip->ip_sum = 0;
  		ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
 +
 +		m0->m_pkthdr.csum_flags &= ~M_CSUM_IPv4;
  #endif
  #ifdef __OpenBSD__
  		/* Update relevant hardware checksum stats for TCP/UDP */
 
 --6TrnltStXW4iwmi0--