Implementing pf-scrub no-df bit in a Netfilter Linux Kernel Module hook – IPV4 Packet Header Rewrite

So, I was searching around for the Linux equivalent of the BSD PF firewall rule “scrub-all no-df” and I was expecting that there would be an “iptables mangle prerouting” version – but – no luck! I just wanted to be able to clear this specific bit in the IPv4 packet header with a Linux router so that it would be able to fragment the packets along the inner routes that may have a lower MTU set. Since I couldn’t find anything I made one myself 🙂

Source: https://github.com/stoops/nf_df

Code Snippet

Test Command

ping -c 1 -M do -s 123 1.1.1.1

Packet Capture

As you can see below, the first IPv4 packet (unmodified) contains the DF bit flag set on (0x0000: …. 4000 ….) compared to the modified packet below in the “After Send” section.

Before Send

21:58:39.473143 fe:00:00:00:01:02 > fe:00:00:00:01:01, ethertype IPv4 (0x0800), 
length 165: 1.3.3.7 > 1.1.1.1: ICMP echo request, id 19298, seq 1, length 131
	0x0000:  4500 0097 0000 4000 4001 6348 0103 0307  E.....@[email protected]....
	0x0010:  0101 0101 0800 6735 4b62 0001 0f74 6d63  ......g5Kb...tmc
	0x0020:  0000 0000 2538 0700 0000 0000 1011 1213  ....%8..........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637 3839 3a3b 3c3d 3e3f 4041 4243  456789:;<=>?@ABC
	0x0060:  4445 4647 4849 4a4b 4c4d 4e4f 5051 5253  DEFGHIJKLMNOPQRS
	0x0070:  5455 5657 5859 5a5b 5c5d 5e5f 6061 6263  TUVWXYZ[\]^_`abc
	0x0080:  6465 6667 6869 6a6b 6c6d 6e6f 7071 7273  defghijklmnopqrs
	0x0090:  7475 7677 7879 7a                        tuvwxyz

Before Recv

21:58:39.475300 fe:00:00:00:01:01 > fe:00:00:00:01:02, ethertype IPv4 (0x0800), 
length 165: 1.1.1.1 > 1.3.3.7: ICMP echo reply, id 19298, seq 1, length 131
	0x0000:  4500 0097 d279 0000 3901 d7ce 0101 0101  E....y..9.......
	0x0010:  0103 0307 0000 6f35 4b62 0001 0f74 6d63  ......o5Kb...tmc
	0x0020:  0000 0000 2538 0700 0000 0000 1011 1213  ....%8..........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637 3839 3a3b 3c3d 3e3f 4041 4243  456789:;<=>?@ABC
	0x0060:  4445 4647 4849 4a4b 4c4d 4e4f 5051 5253  DEFGHIJKLMNOPQRS
	0x0070:  5455 5657 5859 5a5b 5c5d 5e5f 6061 6263  TUVWXYZ[\]^_`abc
	0x0080:  6465 6667 6869 6a6b 6c6d 6e6f 7071 7273  defghijklmnopqrs
	0x0090:  7475 7677 7879 7a                        tuvwxyz

Kernel Module

# lsmod | grep -i nf_df
nf_df    16384    0

After Send

21:52:52.646803 fe:00:00:00:01:02 > fe:00:00:00:01:01, ethertype IPv4 (0x0800), 
length 165: 1.3.3.7 > 1.1.1.1: ICMP echo request, id 52199, seq 1, length 131
	0x0000:  4500 0097 0000 0000 4001 a348 0103 0307  [email protected]....
	0x0010:  0101 0101 0800 0e11 cbe7 0001 b472 6d63  .............rmc
	0x0020:  0000 0000 56d8 0900 0000 0000 1011 1213  ....V...........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637 3839 3a3b 3c3d 3e3f 4041 4243  456789:;<=>?@ABC
	0x0060:  4445 4647 4849 4a4b 4c4d 4e4f 5051 5253  DEFGHIJKLMNOPQRS
	0x0070:  5455 5657 5859 5a5b 5c5d 5e5f 6061 6263  TUVWXYZ[\]^_`abc
	0x0080:  6465 6667 6869 6a6b 6c6d 6e6f 7071 7273  defghijklmnopqrs
	0x0090:  7475 7677 7879 7a                        tuvwxyz

After Recv

21:52:52.669611 fe:00:00:00:01:01 > fe:00:00:00:01:02, ethertype IPv4 (0x0800), 
length 165: 1.1.1.1 > 1.3.3.7: ICMP echo reply, id 52199, seq 1, length 131
	0x0000:  4500 0097 79f9 0000 3901 304f 0101 0101  E...y...9.0O....
	0x0010:  0103 0307 0000 1611 cbe7 0001 b472 6d63  .............rmc
	0x0020:  0000 0000 56d8 0900 0000 0000 1011 1213  ....V...........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637 3839 3a3b 3c3d 3e3f 4041 4243  456789:;<=>?@ABC
	0x0060:  4445 4647 4849 4a4b 4c4d 4e4f 5051 5253  DEFGHIJKLMNOPQRS
	0x0070:  5455 5657 5859 5a5b 5c5d 5e5f 6061 6263  TUVWXYZ[\]^_`abc
	0x0080:  6465 6667 6869 6a6b 6c6d 6e6f 7071 7273  defghijklmnopqrs
	0x0090:  7475 7677 7879 7a                        tuvwxyz

Edit: In addition to this Linux kernel nftables module, I found out that there is another one running for IPv4 packet defragmentation which should also be similar to the scrub rule “fragment reassemble”. According to the documentation, if you have any stateful connection tracking rules for layer-4 (for example, postrouting nat rules or prerouting udp ports) then the fragmented packets should get reassembled again. I am looking into the scrub rule “reassemble tcp“…

# lsmod | grep -i defrag
nf_defrag_ipv4 16384 1 nf_conntrack

 

~

 

3 thoughts on “Implementing pf-scrub no-df bit in a Netfilter Linux Kernel Module hook – IPV4 Packet Header Rewrite

  1. Hi,
    nice module, testing it on ubuntu20.04 and have enabled the print to kernel log.
    It looks to be matching on every packet but not stripping the DF flag.

    Log:
    Sep 20 17:29:49 kernel: [666839.469708] PF-MOD-NO-DF: Flags: [16384] Len: [108] src: [82……] dst: [192……]
    Sep 20 17:29:49 kernel: [666839.469751] PF-MOD-NO-DF: Flags: [16384] Len: [108] src: [82……] dst: [192……]

    the flags value is the ntohs(iph->frag_off) value which you AND with 0x4000, but 16384 in oct is 0x40000, or am i wrong?

Leave a comment