From ca0695dd53ad321d89906d190b93a5898cb40220 Mon Sep 17 00:00:00 2001 From: Eric Garver Date: Thu, 10 Jan 2019 10:10:12 -0500 Subject: [PATCH 3/3] RFC3964_IPv4: Use filter table instead of raw This allows us to use the reject statement, which is more useful to provide feedback to senders. Fixes: 5afa02271418 ("nftables: support RFC3964_IPv4 filtering") Fixes: b86206ed1590 ("ipXtables: support RFC3964_IPv4 filtering") (cherry picked from commit 44200d0f508a990c5dfff9f480a6206ec507e229) --- src/firewall/core/fw.py | 12 ++- src/firewall/core/ipXtables.py | 24 +++-- src/firewall/core/nftables.py | 20 ++-- src/tests/features/rfc3964_ipv4.at | 159 +++++++++++++++-------------- 4 files changed, 122 insertions(+), 93 deletions(-) diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py index a3089ce70eb8..66f4d9508afa 100644 --- a/src/firewall/core/fw.py +++ b/src/firewall/core/fw.py @@ -822,9 +822,15 @@ class Firewall(object): rules = ipv6_backend.build_rpfilter_rules(self._log_denied) transaction.add_rules(ipv6_backend, rules) - if self._rfc3964_ipv4: - rules = ipv6_backend.build_rfc3964_ipv4_rules() - transaction.add_rules(ipv6_backend, rules) + if self._rfc3964_ipv4: + # Flush due to iptables-restore (nftables) bug tiggered when + # specifying same index multiple times in same batch + # rhbz 1647925 + transaction.execute(True) + transaction.clear() + + rules = ipv6_backend.build_rfc3964_ipv4_rules() + transaction.add_rules(ipv6_backend, rules) else: if use_transaction is None: diff --git a/src/firewall/core/ipXtables.py b/src/firewall/core/ipXtables.py index c5b17aa3a846..1355a473f792 100644 --- a/src/firewall/core/ipXtables.py +++ b/src/firewall/core/ipXtables.py @@ -1320,13 +1320,23 @@ class ip6tables(ip4tables): "2002:e000::/19", # 224.0.0.0/4 (multicast), 240.0.0.0/4 (reserved and broadcast) ] + chain_name = "RFC3964_IPv4" + self.our_chains["filter"].add(chain_name) + rules = [] + rules.append(["-t", "filter", "-N", chain_name]) for daddr in daddr_list: - for chain in ["PREROUTING", "OUTPUT"]: - rules.append(["-t", "raw", "-I", chain, - "-d", daddr, "-j", "DROP"]) - if self._fw._log_denied in ["unicast", "all"]: - rules.append(["-t", "raw", "-I", chain, - "-d", daddr, "-j", "LOG", - "--log-prefix", "\"RFC3964_IPv4_DROP: \""]) + rules.append(["-t", "filter", "-I", chain_name, + "-d", daddr, "-j", "REJECT", "--reject-with", + "addr-unreach"]) + if self._fw._log_denied in ["unicast", "all"]: + rules.append(["-t", "filter", "-I", chain_name, + "-d", daddr, "-j", "LOG", + "--log-prefix", "\"RFC3964_IPv4_REJECT: \""]) + + # Inject into FORWARD and OUTPUT chains + rules.append(["-t", "filter", "-I", "OUTPUT", "3", + "-j", chain_name]) + rules.append(["-t", "filter", "-I", "FORWARD", "4", + "-j", chain_name]) return rules diff --git a/src/firewall/core/nftables.py b/src/firewall/core/nftables.py index 1eb9c3fb94c2..94d8c2b155dc 100644 --- a/src/firewall/core/nftables.py +++ b/src/firewall/core/nftables.py @@ -54,7 +54,7 @@ IPTABLES_TO_NFT_HOOK = { #}, "raw": { "PREROUTING": ("prerouting", -300 + NFT_HOOK_OFFSET), - "OUTPUT": ("output", -300 + NFT_HOOK_OFFSET), + # "OUTPUT": ("output", -300 + NFT_HOOK_OFFSET), }, "mangle": { "PREROUTING": ("prerouting", -150 + NFT_HOOK_OFFSET), @@ -72,7 +72,7 @@ IPTABLES_TO_NFT_HOOK = { "filter": { "INPUT": ("input", 0 + NFT_HOOK_OFFSET), "FORWARD": ("forward", 0 + NFT_HOOK_OFFSET), - # "OUTPUT": ("output", 0 + NFT_HOOK_OFFSET), + "OUTPUT": ("output", 0 + NFT_HOOK_OFFSET), }, } @@ -485,6 +485,9 @@ class nftables(object): default_rules.append("add rule inet %s filter_%s %%%%LOGTYPE%%%% log prefix '\"FINAL_REJECT: \"'" % (TABLE_NAME, "FORWARD")) default_rules.append("add rule inet %s filter_%s reject with icmpx type admin-prohibited" % (TABLE_NAME, "FORWARD")) + # filter, OUTPUT + default_rules.append("add rule inet %s filter_%s oifname lo accept" % (TABLE_NAME, "OUTPUT")) + self.our_chains["inet"]["filter"] = set(["INPUT_ZONES_SOURCE", "INPUT_ZONES", "FORWARD_IN_ZONES_SOURCE", @@ -1260,13 +1263,16 @@ class nftables(object): rule_fragment = ["ip6", "daddr"] + daddr_set if self._fw._log_denied in ["unicast", "all"]: - rule_fragment += ["log", "prefix", "\"RFC3964_IPv4_DROP: \""] - rule_fragment += ["drop"] + rule_fragment += ["log", "prefix", "\"RFC3964_IPv4_REJECT: \""] + rule_fragment += ["reject"] + rule_fragment += self._reject_types_fragment("addr-unreach") rules = [] - for chain in ["PREROUTING", "OUTPUT"]: - rules.append(["insert", "rule", "inet", "%s" % TABLE_NAME, - "raw_%s" % chain] + rule_fragment) + # WARN: index must be kept in sync with build_default_rules() + rules.append(["add", "rule", "inet", "%s" % TABLE_NAME, + "filter_OUTPUT", "index", "0"] + rule_fragment) + rules.append(["add", "rule", "inet", "%s" % TABLE_NAME, + "filter_FORWARD", "index", "1"] + rule_fragment) return rules def build_zone_rich_source_destination_rules(self, enable, zone, rich_rule): diff --git a/src/tests/features/rfc3964_ipv4.at b/src/tests/features/rfc3964_ipv4.at index ea8dd40bb5c3..a93aba192c2c 100644 --- a/src/tests/features/rfc3964_ipv4.at +++ b/src/tests/features/rfc3964_ipv4.at @@ -5,74 +5,70 @@ AT_CHECK([sed -i 's/^RFC3964_IPv4.*/RFC3964_IPv4=yes/' ./firewalld.conf]) FWD_RELOAD m4_if(nftables, FIREWALL_BACKEND, [ - NFT_LIST_RULES([inet], [raw_PREROUTING], 0, [dnl + NFT_LIST_RULES([inet], [filter_FORWARD], 0, [dnl table inet firewalld { - chain raw_PREROUTING { - ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } log prefix "RFC3964_IPv4_DROP: " drop - m4_if(yes, HOST_SUPPORTS_NFT_FIB, [dnl - icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept - meta nfproto ipv6 fib saddr . iif oif missing log prefix "rpfilter_DROP: " drop - ])dnl - jump raw_PREROUTING_ZONES_SOURCE - jump raw_PREROUTING_ZONES + chain filter_FORWARD { + ct state established,related accept + iifname "lo" accept + ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } log prefix "RFC3964_IPv4_REJECT: " reject with icmpv6 type addr-unreachable + jump filter_FORWARD_IN_ZONES_SOURCE + jump filter_FORWARD_IN_ZONES + jump filter_FORWARD_OUT_ZONES_SOURCE + jump filter_FORWARD_OUT_ZONES + ct state invalid log prefix "STATE_INVALID_DROP: " + ct state invalid drop + log prefix "FINAL_REJECT: " + reject with icmpx type admin-prohibited } } ]) - NFT_LIST_RULES([inet], [raw_OUTPUT], 0, [dnl + NFT_LIST_RULES([inet], [filter_OUTPUT], 0, [dnl table inet firewalld { - chain raw_OUTPUT { - ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } log prefix "RFC3964_IPv4_DROP: " drop + chain filter_OUTPUT { + oifname "lo" accept + ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } log prefix "RFC3964_IPv4_REJECT: " reject with icmpv6 type addr-unreachable } } ]) ], [ - IP6TABLES_LIST_RULES([raw], [PREROUTING], 0, [dnl - LOG all ::/0 2002:e000::/19 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:e000::/19 - LOG all ::/0 2002:a9fe::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:a9fe::/32 - LOG all ::/0 2002:c0a8::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:c0a8::/32 - LOG all ::/0 2002:ac10::/28 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:ac10::/28 - LOG all ::/0 2002:7f00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:7f00::/24 - LOG all ::/0 2002:a00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:a00::/24 - LOG all ::/0 2002::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002::/24 - LOG all ::/0 ::ffff:0.0.0.0/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 ::ffff:0.0.0.0/96 - LOG all ::/0 ::/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 ::/96 - ACCEPT icmpv6 ::/0 ::/0 ipv6-icmptype 134 - ACCEPT icmpv6 ::/0 ::/0 ipv6-icmptype 135 - LOG all ::/0 ::/0 rpfilter invert LOG flags 0 level 4 prefix "rpfilter_DROP: " - DROP all ::/0 ::/0 rpfilter invert - PREROUTING_direct all ::/0 ::/0 - PREROUTING_ZONES_SOURCE all ::/0 ::/0 - PREROUTING_ZONES all ::/0 ::/0 + IP6TABLES_LIST_RULES([filter], [RFC3964_IPv4], 0, [dnl + LOG all ::/0 2002:e000::/19 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:e000::/19 reject-with icmp6-addr-unreachable + LOG all ::/0 2002:a9fe::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:a9fe::/32 reject-with icmp6-addr-unreachable + LOG all ::/0 2002:c0a8::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:c0a8::/32 reject-with icmp6-addr-unreachable + LOG all ::/0 2002:ac10::/28 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:ac10::/28 reject-with icmp6-addr-unreachable + LOG all ::/0 2002:7f00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:7f00::/24 reject-with icmp6-addr-unreachable + LOG all ::/0 2002:a00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002:a00::/24 reject-with icmp6-addr-unreachable + LOG all ::/0 2002::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 2002::/24 reject-with icmp6-addr-unreachable + LOG all ::/0 ::ffff:0.0.0.0/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 ::ffff:0.0.0.0/96 reject-with icmp6-addr-unreachable + LOG all ::/0 ::/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_REJECT: " + REJECT all ::/0 ::/96 reject-with icmp6-addr-unreachable ]) - IP6TABLES_LIST_RULES([raw], [OUTPUT], 0, [dnl - LOG all ::/0 2002:e000::/19 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:e000::/19 - LOG all ::/0 2002:a9fe::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:a9fe::/32 - LOG all ::/0 2002:c0a8::/32 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:c0a8::/32 - LOG all ::/0 2002:ac10::/28 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:ac10::/28 - LOG all ::/0 2002:7f00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:7f00::/24 - LOG all ::/0 2002:a00::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002:a00::/24 - LOG all ::/0 2002::/24 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 2002::/24 - LOG all ::/0 ::ffff:0.0.0.0/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 ::ffff:0.0.0.0/96 - LOG all ::/0 ::/96 LOG flags 0 level 4 prefix "RFC3964_IPv4_DROP: " - DROP all ::/0 ::/96 + IP6TABLES_LIST_RULES([filter], [FORWARD], 0, [dnl + ACCEPT all ::/0 ::/0 ctstate RELATED,ESTABLISHED + ACCEPT all ::/0 ::/0 + FORWARD_direct all ::/0 ::/0 + RFC3964_IPv4 all ::/0 ::/0 + FORWARD_IN_ZONES_SOURCE all ::/0 ::/0 + FORWARD_IN_ZONES all ::/0 ::/0 + FORWARD_OUT_ZONES_SOURCE all ::/0 ::/0 + FORWARD_OUT_ZONES all ::/0 ::/0 + LOG all ::/0 ::/0 ctstate INVALID LOG flags 0 level 4 prefix "STATE_INVALID_DROP: " + DROP all ::/0 ::/0 ctstate INVALID + LOG all ::/0 ::/0 LOG flags 0 level 4 prefix "FINAL_REJECT: " + REJECT all ::/0 ::/0 reject-with icmp6-adm-prohibited + ]) + IP6TABLES_LIST_RULES([filter], [OUTPUT], 0, [dnl + ACCEPT all ::/0 ::/0 OUTPUT_direct all ::/0 ::/0 + RFC3964_IPv4 all ::/0 ::/0 ]) ]) @@ -80,35 +76,46 @@ AT_CHECK([sed -i 's/^RFC3964_IPv4.*/RFC3964_IPv4=no/' ./firewalld.conf]) FWD_RELOAD m4_if(nftables, FIREWALL_BACKEND, [ - NFT_LIST_RULES([inet], [raw_PREROUTING], 0, [dnl + NFT_LIST_RULES([inet], [filter_FORWARD], 0, [dnl table inet firewalld { - chain raw_PREROUTING { - m4_if(yes, HOST_SUPPORTS_NFT_FIB, [dnl - icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept - meta nfproto ipv6 fib saddr . iif oif missing log prefix "rpfilter_DROP: " drop - ])dnl - jump raw_PREROUTING_ZONES_SOURCE - jump raw_PREROUTING_ZONES + chain filter_FORWARD { + ct state established,related accept + iifname "lo" accept + jump filter_FORWARD_IN_ZONES_SOURCE + jump filter_FORWARD_IN_ZONES + jump filter_FORWARD_OUT_ZONES_SOURCE + jump filter_FORWARD_OUT_ZONES + ct state invalid log prefix "STATE_INVALID_DROP: " + ct state invalid drop + log prefix "FINAL_REJECT: " + reject with icmpx type admin-prohibited } } ]) - NFT_LIST_RULES([inet], [raw_OUTPUT], 0, [dnl + NFT_LIST_RULES([inet], [filter_OUTPUT], 0, [dnl table inet firewalld { - chain raw_OUTPUT { + chain filter_OUTPUT { + oifname "lo" accept } } ]) ], [ - IP6TABLES_LIST_RULES([raw], [PREROUTING], 0, [dnl - ACCEPT icmpv6 ::/0 ::/0 ipv6-icmptype 134 - ACCEPT icmpv6 ::/0 ::/0 ipv6-icmptype 135 - LOG all ::/0 ::/0 rpfilter invert LOG flags 0 level 4 prefix "rpfilter_DROP: " - DROP all ::/0 ::/0 rpfilter invert - PREROUTING_direct all ::/0 ::/0 - PREROUTING_ZONES_SOURCE all ::/0 ::/0 - PREROUTING_ZONES all ::/0 ::/0 + NS_CHECK([ip6tables -w -n -t filter -L RFC3964_IPv4], 1, [ignore], [ignore]) + IP6TABLES_LIST_RULES([filter], [FORWARD], 0, [dnl + ACCEPT all ::/0 ::/0 ctstate RELATED,ESTABLISHED + ACCEPT all ::/0 ::/0 + FORWARD_direct all ::/0 ::/0 + FORWARD_IN_ZONES_SOURCE all ::/0 ::/0 + FORWARD_IN_ZONES all ::/0 ::/0 + FORWARD_OUT_ZONES_SOURCE all ::/0 ::/0 + FORWARD_OUT_ZONES all ::/0 ::/0 + LOG all ::/0 ::/0 ctstate INVALID LOG flags 0 level 4 prefix "STATE_INVALID_DROP: " + DROP all ::/0 ::/0 ctstate INVALID + LOG all ::/0 ::/0 LOG flags 0 level 4 prefix "FINAL_REJECT: " + REJECT all ::/0 ::/0 reject-with icmp6-adm-prohibited ]) - IP6TABLES_LIST_RULES([raw], [OUTPUT], 0, [dnl + IP6TABLES_LIST_RULES([filter], [OUTPUT], 0, [dnl + ACCEPT all ::/0 ::/0 OUTPUT_direct all ::/0 ::/0 ]) ]) -- 2.18.0