As has been said, you should be sure that blocking fragments is really your goal, and not a method you think is best for your goal, while better methods would exist. Anyway, for what it's worth you must:
use a recent enough kernel. The feature was added in kernel 4.16. CentOS uses 3.10. While many features are backported (starting with nftables which isn't available on a vanilla 3.10 kernel but is on RHEL/CentOS's 3.10), this feature wasn't backported as of latest CentOS 7.6's kernel. Since you're using an "elrepo" 5.0.8 kernel, the feature is present. Here's the feature description and why it exists (mostly for routing, or at least non-stateful/non-NAT firewall routing situations):
netfilter: nf_defrag:
Skip defrag if NOTRACK is set conntrack defrag
is needed only if some module like CONNTRACK or NAT explicitly
requests it. For plain forwarding scenarios, defrag is not needed and
can be skipped if NOTRACK is set in a rule.
Since conntrack defrag is currently higher priority than raw table,
setting NOTRACK is not sufficient. We need to move raw to a higher
priority for iptables only.
This is achieved by introducing a module parameter "raw_before_defrag"
which allows to change the priority of raw table to place it before
defrag. By default, the parameter is disabled and the priority of raw
table is NF_IP_PRI_RAW to support legacy behavior. If the module
parameter is enabled, then the priority of the raw table is set to
NF_IP_PRI_RAW_BEFORE_DEFRAG.
(if needed remove existing raw ip6tables rules, unload and) load the ip6table_raw
module with the parameter raw_before_defrag=1
, so the raw's hook (in PREROUTING) switchs from prio -300 to -450, before defrag's -400.
modprobe ip6table_raw raw_before_defrag=1
which should get a kernel message like ip6table_raw: Enabling raw table before defrag
Now in the raw
table, and probably making sense only in PREROUTING
, ip6tables will be able to see fragments. It can filter them there, or choose to skip conntrack (iptables -t raw -A PREROUTING ... -j CT --notrack
), which as explained in the feature patch, will skip defragmentation too, allowing other chains to handle them (of course not including nat
table's chains nor any other conntrack related feature).
Note that to witness the problem described in a test network namespace, one must first artificially enable conntrack operations for conntrack's dependency with defrag, which isn't activated until first needed. Here's a network namespace example:
ip netns add sender
ip netns add receiver
ip -n sender link add veth0 address 02:00:00:00:00:01 type veth peer netns receiver name veth0 address 02:00:00:00:00:02
ip -n sender link set veth0 up
ip -n receiver link set veth0 up
This works:
# ip netns exec sender ping6 -s 4000 fe80::ff:fe00:2%veth0
PING fe80::ff:fe00:2%veth0(fe80::ff:fe00:2%veth0) 4000 data bytes
4008 bytes from fe80::ff:fe00:2%veth0: icmp_seq=1 ttl=64 time=0.069 ms
^C
After this, it won't work anymore:
ip netns exec receiver ip6tables -A INPUT -m ipv6header --header ipv6-frag --soft -j DROP
Once conntrack is activated in the network namespace with those commands apparently resulting in a no-op:
ip netns exec receiver ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED
ip netns exec receiver ip6tables -D INPUT -m conntrack --ctstate ESTABLISHED
the ipv6 defragmentation is also activated. Now the previous ping will always work, because the rule in INPUT only sees defragmented packets.
With the previously (re)loaded ip6table_raw
module with parameter raw_before_defrag=1
, this will restore fragmented ping's blocking:
ip netns exec receiver ip6tables -t raw -A PREROUTING -m ipv6header --header ipv6-frag --soft -j DROP
Alternatively, interesting packets can be marked as notrack, thus exempting them of conntrack, thus not receiving defrag treatement either, allowing them to be filtered again with the rule in the filter/INPUT
chain. So instead of the previous raw
rule, this would also block the ping packets (3 of them per ping), but this time again in the filter/INPUT
chain:
ip netns exec receiver ip6tables -t raw -A PREROUTING -m ipv6header --header ipv6-frag --soft -j CT --notrack
This is an example only which doesn't make much sense.