Page MenuHomeFreeBSD

D61041.1793453499.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D61041.1793453499.diff

diff --git a/sys/netinet6/ip6_fastfwd.c b/sys/netinet6/ip6_fastfwd.c
--- a/sys/netinet6/ip6_fastfwd.c
+++ b/sys/netinet6/ip6_fastfwd.c
@@ -95,11 +95,13 @@
ip6_tryforward(struct mbuf *m)
{
struct sockaddr_in6 dst;
+ struct in6_addr in_src, in_dst; /* as received */
struct in6_addr pfil_dst; /* before the outbound hooks */
struct nhop_object *nh;
struct m_tag *fwd_tag;
struct ip6_hdr *ip6;
struct ifnet *rcvif;
+ struct mbuf *mcopy = NULL;
uint32_t plen;
int error;
@@ -150,6 +152,8 @@
dst.sin6_family = AF_INET6;
dst.sin6_len = sizeof(dst);
dst.sin6_addr = ip6->ip6_dst;
+ in_src = ip6->ip6_src;
+ in_dst = ip6->ip6_dst;
/*
* Incoming packet firewall processing.
@@ -286,6 +290,19 @@
}
}
passout:
+ /*
+ * A packet leaving through the interface it arrived on could have
+ * gone to the next hop directly, so keep a copy to send its source a
+ * redirect. Not when the route came from a redirect, nor when a
+ * packet filter rewrote the addresses or chose the next hop: the
+ * packets must then keep coming through us.
+ */
+ if (nh->nh_ifp == rcvif && V_ip6_sendredirects &&
+ (nh->nh_flags & NHF_REDIRECT) == 0 &&
+ IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &in_dst) &&
+ IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &in_src))
+ mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
+ M_NOWAIT);
/*
* If TCP/UDP header still needs a valid checksum and interface will not
@@ -320,9 +337,15 @@
if (error != 0) {
in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);
IP6STAT_INC(ip6s_cantforward);
+ if (mcopy != NULL)
+ m_freem(mcopy);
} else {
in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward);
IP6STAT_INC(ip6s_forward);
+ if (mcopy != NULL) {
+ IP6STAT_INC(ip6s_redirectsent);
+ icmp6_redirect_output(mcopy, nh);
+ }
}
return (NULL);
dropin:
@@ -333,5 +356,7 @@
drop:
if (m != NULL)
m_freem(m);
+ if (mcopy != NULL)
+ m_freem(mcopy);
return (NULL);
}
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -668,15 +668,13 @@
}
/*
* Try to forward the packet, but if we fail continue.
- * ip6_tryforward() does not generate redirects, so fall
- * through to normal processing if redirects are required.
* ip6_tryforward() does inbound and outbound packet firewall
* processing. If firewall has decided that destination becomes
* our local address, it sets M_FASTFWD_OURS flag. In this
* case skip another inbound firewall processing and update
* ip6 pointer.
*/
- if (V_ip6_forwarding != 0 && V_ip6_sendredirects == 0
+ if (V_ip6_forwarding != 0
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
&& (!IPSEC_ENABLED(ipv6) ||
IPSEC_CAPS(ipv6, m, IPSEC_CAP_OPERABLE) == 0)
diff --git a/tests/sys/netinet6/redirect.sh b/tests/sys/netinet6/redirect.sh
--- a/tests/sys/netinet6/redirect.sh
+++ b/tests/sys/netinet6/redirect.sh
@@ -111,10 +111,90 @@
vnet_cleanup
}
+# A host whose default router forwards its packets to a better router on the
+# same link.
+send_redirect_setup()
+{
+ vnet_init
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail host ${epair}a
+ vnet_mkjail rtr ${epair}b
+
+ jexec host ifconfig ${epair}a inet6 2001:db8:1::2/64 up
+ jexec rtr ifconfig ${epair}b inet6 2001:db8:1::1/64 up
+ jexec rtr sysctl net.inet6.ip6.forwarding=1
+
+ while [ `jexec host ifconfig ${epair}a inet6 | grep -c tentative` != "0" ]; do
+ sleep 0.1
+ done
+ while [ `jexec rtr ifconfig ${epair}b inet6 | grep -c tentative` != "0" ]; do
+ sleep 0.1
+ done
+
+ rtr_ll=`jexec rtr ifconfig ${epair}b inet6 | awk '$2~/^fe80:/{print$2}' | awk -F% '{print$1}'`
+ jexec host route add -6 default ${rtr_ll}%${epair}a
+
+ jexec rtr ndp -s fe80::5555%${epair}b 00:00:5e:00:53:55
+ jexec rtr route add -6 -net 2001:db8:2::/64 fe80::5555%${epair}b
+}
+
+atf_test_case "send_redirect" "cleanup"
+send_redirect_head()
+{
+ atf_set descr 'Test that a router sends IPv6 redirects'
+ atf_set require.user root
+}
+
+send_redirect_body()
+{
+ send_redirect_setup
+
+ atf_check -s exit:2 -o ignore jexec host ping -6 -c 1 -W 1 2001:db8:2::1
+ atf_check -o match:"1 redirect sent" jexec rtr netstat -s -p ip6
+
+ atf_check -o match:"gateway: fe80::5555%${epair}a\$" \
+ jexec host route -n get -6 2001:db8:2::1
+ atf_check -o match:'flags: <UP,GATEWAY,HOST,DYNAMIC,DONE>' \
+ jexec host route -n get -6 2001:db8:2::1
+}
+
+send_redirect_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "send_redirect_disabled" "cleanup"
+send_redirect_disabled_head()
+{
+ atf_set descr 'Test that net.inet6.ip6.redirect=0 stops IPv6 redirects'
+ atf_set require.user root
+}
+
+send_redirect_disabled_body()
+{
+ send_redirect_setup
+ jexec rtr sysctl net.inet6.ip6.redirect=0
+
+ atf_check -s exit:2 -o ignore jexec host ping -6 -c 1 -W 1 2001:db8:2::1
+ atf_check -o match:"1 packet forwarded" \
+ -o match:"0 redirects sent" jexec rtr netstat -s -p ip6
+
+ atf_check -o match:"gateway: ${rtr_ll}%${epair}a\$" \
+ jexec host route -n get -6 2001:db8:2::1
+}
+
+send_redirect_disabled_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "valid_redirect"
+ atf_add_test_case "send_redirect"
+ atf_add_test_case "send_redirect_disabled"
}
# end
diff --git a/tests/sys/netpfil/pf/forward.sh b/tests/sys/netpfil/pf/forward.sh
--- a/tests/sys/netpfil/pf/forward.sh
+++ b/tests/sys/netpfil/pf/forward.sh
@@ -277,10 +277,54 @@
pft_cleanup
}
+atf_test_case "v6_redirect_rewritten" "cleanup"
+v6_redirect_rewritten_head()
+{
+ atf_set descr 'Test that a packet whose destination pf rewrote gets no redirect'
+ atf_set require.user root
+}
+
+v6_redirect_rewritten_body()
+{
+ pft_init
+
+ epair=$(vnet_mkepair)
+
+ # The host sends to 2001:db8:43::3, which the router rewrites to the
+ # host's own link; the router would redirect the host to the real next
+ # hop for the original destination, but the host never sent to it.
+ ifconfig ${epair}a inet6 2001:db8:42::1/64 up no_dad -ifdisabled
+ vnet_mkjail alcatraz ${epair}b
+ jexec alcatraz ifconfig ${epair}b inet6 2001:db8:42::2/64 up no_dad
+ jexec alcatraz sysctl net.inet6.ip6.forwarding=1
+ jexec alcatraz sysctl net.inet6.ip6.redirect=1
+ jexec alcatraz ndp -s 2001:db8:42::3 00:01:02:03:04:05
+ jexec alcatraz ndp -s 2001:db8:43::3 00:01:02:03:04:06
+ jexec alcatraz route add -6 2001:db8:43::/64 2001:db8:42::3
+ route add -6 2001:db8:43::/64 2001:db8:42::2
+
+ jexec alcatraz pfctl -e
+ pft_set_rules alcatraz "pass"
+ atf_check -s exit:2 -o ignore ping -6 -c 1 -W 1 2001:db8:43::3
+ atf_check -o match:"1 redirect sent" jexec alcatraz netstat -s -p ip6
+
+ pft_set_rules alcatraz \
+ "rdr on ${epair}b inet6 to 2001:db8:43::4 -> 2001:db8:43::3" \
+ "pass"
+ atf_check -s exit:2 -o ignore ping -6 -c 1 -W 1 2001:db8:43::4
+ atf_check -o match:"1 redirect sent" jexec alcatraz netstat -s -p ip6
+}
+
+v6_redirect_rewritten_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4"
atf_add_test_case "v6"
atf_add_test_case "v6_hlim"
atf_add_test_case "v6_hlim_decrement"
+ atf_add_test_case "v6_redirect_rewritten"
}

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 31, 1:31 PM (11 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41264661
Default Alt Text
D61041.1793453499.diff (6 KB)

Event Timeline