Subject: Bridge + ipf + ipv6 broken
To: NetBSD tech-net mailing list <tech-net@netbsd.org>
From: Julian Coleman <jdc@coris.org.uk>
List: tech-net
Date: 07/21/2003 20:39:55
I'm having problems trying to get bridge + ipf to work with ipv6.  Having
been banging my head against this for a little while, I'm coming to the
conclusion that the way that filtering is implemented in the bridging code
is wrong.

The setup I'm using to test is a sparc 20 with sources from about 7 July
(although I've seen the same symptoms for a while).  Bridged interfaces are
le0 and qe0, and there is an ipv6 uplink via stf0.

With ipf turned on, I see the following:

  ipv6 originated from the bridging machine works.
  tcp6 connections to the bridging machine work (haven't tested UDP6)
  icmp6 replies from the bridging machine fail
  ipv6 traffic through the bridging machine fails, e.g. le0 to stf0 (haven't
    tested le0 to qe0)

With ipf turned off, all ipv6 connections to and through the bridging machine
work.

When I investigated further, I added ipf ipv6 rules that pass and log all
packets.  In both the working and non-working cases, I see packets logged
as passed by ipf.  In the case where the exchange succeeded, I see that ipf
has logged two packets outbound for each packet, for example:

  Jul 21 19:49:02 sparky ipmon[159]: 19:49:02.411722 2x le0 @0:1 p 2001:8b0:76:1:a00:20ff:fe71:e240,telnet -> 2001:8b0:76:1:a00:20ff:fe10:f6f0,49237 PR tcp len 40 35 -AP OUT 

(This double logging also occurs for outbound ipv4 packets.)

In the case where the exchange failed, I only see the outbound packet logged
once, for example:

  Jul 21 19:58:32 sparky ipmon[159]: 19:58:31.568760 le0 @0:1 p 2001:8b0:76:1:a00:20ff:fe71:e240 -> 2001:8b0:76:1:a00:20ff:fe10:f6f0 PR icmpv6 len 40 16 icmpv6 icmpv6type(73)/80 OUT 

Looking through how the bridging code works, both bridge_enqueue() and
bridge_forward() call pfil_run_hooks(), which eventually arrives at
bridge_ipf().  This then calls pfil_run_hooks() with inet_pfil_hook and
inet6_pfil_hook arguments for ipv4 and ipv6, respectively.  When fr_check()
gets to process an ipv6 packet this second time, ip->ip_v is 0.  This causes
it to reject the packet.  Presumably, the mbuf contents have chenged between
the two calls to pfil_run_hooks(), but I can't see where.

So, why does bridge_enqueue() need to call pfil_run_hooks() with
inet_pfil_hook or inet6_pfil_hook arguments?  If this host originated the
packet, these will already have been called by ip_output() and ip6_output(),
respectively.  Isn't it only necessary to call pfil_run_hooks() (or even
bridge_ipf() directly) in bridge_forward()?

One other thing that I've noticed is that adding debug printf()'s to various
bits of the packet handling code sometimes changes the behaviour - I've seen
all ipv6 connections both to and from other hosts fail, even with ipf turned
off, and also fr_check() to report ip-ip_v = 15.

Any pointers or insight would be appreciated.  Even ones pointing out the
completely obvious that I've overlooked.

J

PS.  Does anyone else use bridge + ipv6?  Does it work for you?

-- 
                    My other computer also runs NetBSD
                          http://www.netbsd.org/