IPFW IPFW and IPv6 fragments

Hi,

is anyone aware of how to have IPFW to IPv6 reassembly on end-hosts for the purposes of rule checking?

The ipfw() has the reass directive but that is solely for IPv4:
Queue and reassemble IPv4 fragments

I have the following early rule:
Code:
00050 allow ip6 from any to any extension header: fragmentation

which helps but it far less secure than than a validated reassembled packet.

Thanks,
Scott
 
Routers shouldn't fragment IPv6 packets. So there should be nothing to reassemble on a router either

SirDice, you are directed to re-read the OP. But to save you the hassle of getting as far as the second line:

"IPv6 reassembly on end-hosts" should have prevented you wasting your time and mine. I'm not normally so blunt but this is not a first offence.

Fancy taking a second swing?
 
Code:
In order to send a packet larger than a path's MTU, a node may use
   the IPv6 Fragment header to fragment the packet at the source and
   have it reassembled at the destination(s).  However, the use of such
   fragmentation is discouraged in any application that is able to
   adjust its packets to fit the measured path MTU (i.e., down to 1280
   octets).

You shouldn't have fragments in the first place.
 
*sigh*. It's ok to say: "I don't know if IPFW does IPv6 reassembly", which while not adding a lot of value, at least doesn't muddy the thread. You'll agree that four posts later I'm no closer to an answer.

IPv6 packet reassembly is mandatory for IPv6 end-hosts. FreeBSD's IPv6 stack implements such code. I think it's reasonable for a firewall implementation therefore to also perform reassembly. A firewall should pass all sane and administratively permitted packets to the destination application, and in order to do that it should reassemble packets where necessary in order to perform inspection. IPFW does this for IPv4. I don't know if it does for IPv6, and I'm striving to discover an answer.
 
Thanks SirDice. I've bumped that bug-thread as it appears to have gone quiet. I had read it earlier and was hoping that perhaps it had been fixed under a different bug id that I had not seen.
 
You probably need to ask on freebsd-net or freebsd-ipfw mailing lists too. The PR might be overlooked due to its age (it was originally made in 2012).
 
Now finally I arrived here, too. Same problem.
I have the following early rule:
Code:
00050 allow ip6 from any to any extension header: fragmentation

which helps but it far less secure than than a validated reassembled packet.
I don't think that one is a good idea. As I understand it, it does pass any fragmented packet just through, entirely unchecked.

I think, a better approach might be
Code:
reass proto ip4
allow frag proto ip6

That one should, according to the docs, defragment ip4 as normal, and pass subsequent ip6 fragments through unchecked - those without a protocol header. But not the first fragment; that one would be checked normally.
Without the first fragment, the destination should not be able to reassemble, so this should, more or less, be sufficient.

The downside with both approaches, however, is: forward will not work. setfib will not work. filters (e.g. NPTv6) will not work. Anything that modifies or reroutes packets dependent on the distinguished packet content (i.e. port numbers etc.), will not work.

Now my problem is: I run ipfw on every node, and I do reroute and setfib and all those things.

Routers shouldn't fragment IPv6 packets. So there should be nothing to reassemble on a router either.

I read that everywhere. More interesting would be the reason why not. And the only answer I could find on that is: it costs performance. That's an argument, but in my case not relevant. And anyway, the RFC "should" is not an imperative, it means: do only disobey if you are fully able to understand and cope with the consequences.
 
Now finally I arrived here, too. Same problem.

I don't think that one is a good idea. As I understand it, it does pass any fragmented packet just through, entirely unchecked.

I think, a better approach might be
Code:
reass proto ip4
allow frag proto ip6

That one should, according to the docs, defragment ip4 as normal, and pass subsequent ip6 fragments through unchecked - those without a protocol header. But not the first fragment; that one would be checked normally.
I do not believe that to be the case. The first fragment, containing the protocol header, will also have an IPv6 fragment header and will also be allowed unconditionally.
Moreover, there's nothing to guarantee that the entire protocol header is present in the first fragment. (It should be, the minimal IPv6 MTU is 1280, and any sane implementation will fill that, but attackers could do strange things.)

Without the first fragment, the destination should not be able to reassemble, so this should, more or less, be sufficient.
Sadly it's not. The awful choice here, either deny IPv6 fragmentation at all, or open a simple way of bypassing firewall policy, is what motivated me to fix this issue in pf in the first place.

pf fully reassembles the packet before processing it. That fixes the above concerns, but comes at a performance cost. In retrospect, what I should have done was to only inspect the first fragment. Enforce a requirement that the entire protocol header be present in the first packet. (As above, that'll be the case for any remotely sane implementation anyway), and allow any following fragments to pass. That might mean that we allow fragments of a blocked packet through, but as the first fragment will never arrive the destination will never reassemble it, and there's no significant risk.
I read that everywhere. More interesting would be the reason why not. And the only answer I could find on that is: it costs performance. That's an argument, but in my case not relevant.
Performance is the reason, yes. Not fragmenting in routers along the path allows them to implement everything in hardware. Fragmenting is typically handled by the router's software, and this is much, much slower.

Also note that while it's true that routers do not need to care about fragmentation this is not true for firewalls. You really do need to be able to see the protocol headers as a firewall, so it must either reassemble the packet, or require the relevant headers to be in the first packet.
And anyway, the RFC "should" is not an imperative, it means: do only disobey if you are fully able to understand and cope with the consequences.
You can't have your router fragment IPv6 packets along the path. You're going to break path MTU discovery.
 
Hi Kristof, glad to read You! :)

I do not believe that to be the case. The first fragment, containing the protocol header, will also have an IPv6 fragment header and will also be allowed unconditionally.
No, doc clearly says
Such rule would match all not the first fragment datagrams
and this is how it works. I did this for testing, and it got the things through.

I agree that this is not a very safe solution, only slightly better than the one mentioned before.

Sadly it's not. The awful choice here, either deny IPv6 fragmentation at all, or open a simple way of bypassing firewall policy, is what motivated me to fix this issue in pf in the first place.

pf fully reassembles the packet before processing it. That fixes the above concerns, but comes at a performance cost.
Ah. Yes, that's what Andrey's patch in the bug report also does. And it works here. Only, it does not really solve the problem...

Performance is the reason, yes. Not fragmenting in routers along the path allows them to implement everything in hardware. Fragmenting is typically handled by the router's software, and this is much, much slower.
Performance is not the only reason, as I learned yesterday. Inflight de-/refragmentation does just not work in IPv6. And now I am very very curious how You tackle this issue.

Situation :
Code:
       router   --<mtu=1492>--    INTERNET   --<mtu=1480>--   othersite
          |
       client

What happens:
Code:
client# ping -u -c 1 -s 1452 othersite
   PING6(1500=40+8+1452 bytes)
out: IP6 ICMP6, echo request, seq 0, length 1460
in: IP6 ICMP6, packet too big, mtu 1492

## this comes back from router, and it is correct.
## next try:

client# ping -u -c 1 -s 1452 othersite
   PING6(1500=40+8+1452 bytes)
out: frag (0|1440) ICMP6, echo request, seq 0, length 1440
out: frag (1440|20)
in: ICMP6, packet too big, mtu 1480

## this now comes back from INTERNET, and it is also correct
## next try:

client# ping -u -c 1 -s 1452 othersite
   PING6(1500=40+8+1452 bytes)
out: frag (0|1432) ICMP6, echo request, seq 0, length 1432
out: frag (1432|28)
in: ICMP6, packet too big, mtu 1480

Ouch - why does this happen? On the router is this:
[edit: ping -m is ping -u if you're on rel 12 or 13]

Code:
   09760     2     1556 count ipv6-icmp from any to <othersite>
   09765 82551 59384861 divert 8677 // internet(6)[FILTER][suricata]
   09770     1     1500 count ipv6-icmp from any to <othersite>

And the manpage says:
Incoming packet fragments diverted by divert are reassembled before delivery to the socket.

Now it gets interesting: packets that come back from a divert socket are not sent per netinet6/ip6_forward.c, they are sent with netinet6/ip6_output.c. And ip6_output() does (re)fragment.
But, the router can only see it's own mtu=1492. The ICMP6 "packet too big" from INTERNET had been sent to the client, the router cannot know this! So the whole thing is stuck at this point.

If, alternatively, we would send with ip6_forward(), then this would only create another ICMP packet too big, mtu 1492 sent to the client - which doesn't help either.

So this is the reason why inflight de-/refragmentation is not a good idea: if you do it, while everybody else does rather send icmp too-big, then that doesn't interplay.
 
Back
Top