Page MenuHomeFreeBSD

Add IPv6 support to ipfw reass action
Needs ReviewPublic

Authored by ae on Apr 28 2017, 1:11 PM.

Details

Reviewers
None
Group Reviewers
network
Summary

ipfw firewall has `reass' action that does IP fragments reassembly and then pass the result for further processing.
Currently it works only for IPv4 and it just breaks IPv6 fragments. (See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=170604)

For IPv4 the reass action uses ip_reass() function for reassembly. It produces the large packet, that can be refragmented again in case when firewall acts as router, because IPv4 router typically can do IPv4 fragmentation.

For IPv6 similar approach is not applicable. IPv6 router does not perform IP fragmentation. Thus if reassembled packet is not for our host, it will be dropped by ip6_forward() function.

The solution implemented in this patch is make IPv6 fragmentation for reassembled packets that is going to be forwarded.

I added ip6_reass() function, that is mostly the copy of frag6_input(), but it returns mbuf pointer, instead of next protocol. Also, it saves some information to help make fragmentation later if it is needed. frag6_input() now uses ip6_reass() function.

In ipfw(4) several new functions added:

  • ipfw_reass() does IPv4/IPv6 reassembly if needed. This function is also called from ipfw_divert().
  • ipfw_setnexthop() is used to setup mbuf's fwd_tag.
  • ipfw_ip6_fragment() is used to make IPv6 fragmentation of reassembled packet.

How it is supposed to work:
ipfw reass rule consumes fragments until the last fragment is not received. Then it returns IP_FW_REASS return code to ipfw_check_packet(). ipfw_check_packet() remembers the fact that IPv6 reassembly was done and passes the reassembled packet to the next rule. When next matched rule will be found, we will make the decision about need of refragmentation.

In case of IP_FW_DENY or IP_FW_DIVERT we leave reassembled packet as is.
In case of IP_FW_PASS we check, that there is no fwd_tag. If fwd_tag is present and next hop is our own address, then fragmentation is not needed. When there is no fwd_tag, we check the destination address. For other cases we do IPv6 fragmentation using the maximum fragment size stored in the mbuf's non-persistent storage. Then all fragments are marked with M_SKIP_FIREWALL flag and queued via netisr queue.

Test Plan

I did basic tests when destination address is local and when fragments should be forwarded.
I used this test program to generate fragmented packet

.
On the router I have the rule reass ip6 from any to any in. And used wireshark to see how packet is fragmented and reassembled.

Diff Detail

Event Timeline

Quick glance for 2 minutes says we should probably have a man page change with this?

ae edited the summary of this revision. (Show Details)

Make refragmentation to be working.

In ip6_reass use correct mbuf pointer where to save non-persistent info.
In ipfw_ip6_fragmenr() correctly initialize next header to IPPROTO_FRAGMENT,
since ip6_fragment() does not do this. Also initialize m_pkthdr.rcvif field
for each fragment, because ip6_fragment() resets it to NULL and ip6_input()
assumes it is not NULL.

ae edited the test plan for this revision. (Show Details)

Quick glance for 2 minutes says we should probably have a man page change with this?

Yes. Actually the current description for reass action is not true, and should be fixed.