From ca0695dd53ad321d89906d190b93a5898cb40220 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
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