aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2024-11-12 15:55:50 +0000
committerKristof Provost <kp@FreeBSD.org>2024-11-20 15:52:41 +0000
commite27970ae8fffd7d14cd106efc150e60ae307607a (patch)
treeb00794afb36184450e69f9703ddb3f1ecae77f3d
parent4b65481ac68a99122991fd73583d071c5e27c65a (diff)
netinet: handle blackhole routes
If during ip_forward() we find a blackhole (or reject) route we should stop processing and count this in the 'cantforward' counter, just like we already do for IPv6. Blackhole routes are set to use the loopback interface, so we don't actually incorrectly forward traffic, but we do fail to count it as unroutable. Test this, both for IPv4 and IPv6. Reviewed by: melifaro Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D47529
-rw-r--r--sys/netinet/ip_input.c12
-rwxr-xr-xtests/sys/netinet/forward.sh53
-rwxr-xr-xtests/sys/netinet6/forward6.sh54
3 files changed, 119 insertions, 0 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 82d7acdd0710..e00f3b77c74c 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -942,6 +942,18 @@ ip_forward(struct mbuf *m, int srcrt)
flowid = m->m_pkthdr.flowid;
ro.ro_nh = fib4_lookup(M_GETFIB(m), ip->ip_dst, 0, NHR_REF, flowid);
if (ro.ro_nh != NULL) {
+ if (ro.ro_nh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST)) {
+ IPSTAT_INC(ips_cantforward);
+ m_freem(m);
+ NH_FREE(ro.ro_nh);
+ return;
+ }
+ if (ro.ro_nh->nh_flags & NHF_REJECT) {
+ IPSTAT_INC(ips_cantforward);
+ NH_FREE(ro.ro_nh);
+ icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
+ return;
+ }
ia = ifatoia(ro.ro_nh->nh_ifa);
} else
ia = NULL;
diff --git a/tests/sys/netinet/forward.sh b/tests/sys/netinet/forward.sh
index e16927a27d07..3ae83eb3edc5 100755
--- a/tests/sys/netinet/forward.sh
+++ b/tests/sys/netinet/forward.sh
@@ -259,6 +259,58 @@ fwd_ip_icmp_gw_slow_success_cleanup() {
vnet_cleanup
}
+atf_test_case "fwd_ip_blackhole" "cleanup"
+fwd_ip_blackhole_head() {
+
+ atf_set descr 'Test blackhole routes'
+ atf_set require.user root
+}
+
+fwd_ip_blackhole_body() {
+ jname="v4t-fwd_ip_blackhole"
+
+ vnet_init
+
+ epair=$(vnet_mkepair)
+ epair_out=$(vnet_mkepair)
+
+ ifconfig ${epair}a 192.0.2.2/24 up
+
+ vnet_mkjail ${jname} ${epair}b ${epair_out}b
+ jexec ${jname} ifconfig lo0 127.0.0.1/8 up
+ jexec ${jname} ifconfig ${epair}b 192.0.2.1/24 up
+ jexec ${jname} ifconfig ${epair_out}b 198.51.100.1/24 up
+ jexec ${jname} sysctl net.inet.ip.forwarding=1
+
+ route add default 192.0.2.1
+
+ atf_check -s exit:2 -o ignore \
+ ping -c 1 -t 1 198.51.100.2
+ atf_check -s exit:0 -o match:"0 packets not forwardable" \
+ jexec ${jname} netstat -s -p ip
+
+ # Create blackhole route
+ jexec ${jname} /sbin/route add 198.51.100.2 -blackhole -fib 0
+ jexec ${jname} netstat -rn
+
+ # Include an IP option to ensure slow path
+ atf_check -s exit:2 -o ignore \
+ ping -c 1 -t 1 -R 198.51.100.2
+ atf_check -s exit:0 -o match:"1 packet not forwardable" \
+ jexec ${jname} netstat -s -p ip
+
+ # Now try via the fast path
+ atf_check -s exit:2 -o ignore \
+ ping -c 1 -t 1 198.51.100.2
+ atf_check -s exit:0 -o match:"2 packets not forwardable" \
+ jexec ${jname} netstat -s -p ip
+}
+
+fwd_ip_blackhole_cleanup() {
+
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
@@ -266,6 +318,7 @@ atf_init_test_cases()
atf_add_test_case "fwd_ip_icmp_gw_fast_success"
atf_add_test_case "fwd_ip_icmp_iface_slow_success"
atf_add_test_case "fwd_ip_icmp_gw_slow_success"
+ atf_add_test_case "fwd_ip_blackhole"
}
# end
diff --git a/tests/sys/netinet6/forward6.sh b/tests/sys/netinet6/forward6.sh
index b3ccd30aea62..40d17837d6f2 100755
--- a/tests/sys/netinet6/forward6.sh
+++ b/tests/sys/netinet6/forward6.sh
@@ -466,6 +466,59 @@ fwd_ip6_gu_icmp_gw_ll_slow_success_cleanup() {
vnet_cleanup
}
+atf_test_case "fwd_ip6_blackhole" "cleanup"
+fwd_ip6_blackhole_head() {
+
+ atf_set descr 'Test blackhole routing'
+ atf_set require.user root
+}
+
+fwd_ip6_blackhole_body() {
+ jname="v6t-fwd_ip6_blackhole"
+
+ vnet_init
+
+ epair=$(vnet_mkepair)
+ epair_out=$(vnet_mkepair)
+
+ ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
+
+ vnet_mkjail ${jname} ${epair}b ${epair_out}b
+ jexec ${jname} ifconfig lo0 inet6 ::1/128 up no_dad
+ jexec ${jname} ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
+ jexec ${jname} ifconfig ${epair_out}b inet6 2001:db8:1::1/64 up no_dad
+ jexec ${jname} sysctl net.inet6.ip6.forwarding=1
+
+ route -6 add default 2001:db8::1
+
+ atf_check -s exit:2 -o ignore \
+ ping6 -c 1 -t 1 2001:db8:1::2
+ atf_check -s exit:0 -o match:"0 packets not forwardable" \
+ jexec ${jname} netstat -s -p ip6
+
+ # Create blackhole route
+ jexec ${jname} route -6 add 2001:db8:1::2 -blackhole
+
+ # Force slow path
+ jexec ${jname} sysctl net.inet6.ip6.redirect=1
+ atf_check -s exit:2 -o ignore \
+ ping6 -c 1 -t 1 2001:db8:1::2
+ atf_check -s exit:0 -o match:"1 packet not forwardable" \
+ jexec ${jname} netstat -s -p ip6
+
+ # Now try the fast path
+ jexec ${jname} sysctl net.inet6.ip6.redirect=0
+ atf_check -s exit:2 -o ignore \
+ ping6 -c 1 -t 1 2001:db8:1::2
+ atf_check -s exit:0 -o match:"2 packets not forwardable" \
+ jexec ${jname} netstat -s -p ip6
+}
+
+fwd_ip6_blackhole_cleanup() {
+
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
@@ -475,6 +528,7 @@ atf_init_test_cases()
atf_add_test_case "fwd_ip6_gu_icmp_iface_slow_success"
atf_add_test_case "fwd_ip6_gu_icmp_gw_gu_slow_success"
atf_add_test_case "fwd_ip6_gu_icmp_gw_ll_slow_success"
+ atf_add_test_case "fwd_ip6_blackhole"
}
# end