diff --git a/share/man/man4/inet6.4 b/share/man/man4/inet6.4 --- a/share/man/man4/inet6.4 +++ b/share/man/man4/inet6.4 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 25, 2020 +.Dd November 12, 2021 .Dt INET6 4 .Os .Sh NAME @@ -341,6 +341,14 @@ .Dv AF_INET6 sockets. Defaults to on. +.It Va ip6.source_address_validation +Boolean: perform source address validation for packets destined for the local +host. +Consider this as following Section 3.2 of RFC3704/BCP84, where we treat local +host as our own infrastructure. +This has no effect on packets to be forwarded, so don't consider it as +anti-spoof feature for a router. +Enabled by default. .El .Ss Interaction between IPv4/v6 sockets By default, 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 @@ -163,6 +163,12 @@ 0, 0, sysctl_netinet6_intr_queue_maxlen, "I", "Maximum size of the IPv6 input queue"); +VNET_DEFINE_STATIC(bool, ip6_sav) = true; +#define V_ip6_sav VNET(ip6_sav) +SYSCTL_BOOL(_net_inet6_ip6, OID_AUTO, source_address_validation, + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_sav), true, + "Drop incoming packets with source address that is a local address"); + #ifdef RSS static struct netisr_handler ip6_direct_nh = { .nh_name = "ip6_direct", @@ -816,6 +822,12 @@ ip6_sprintf(ip6bufd, &ip6->ip6_dst))); goto bad; } + if (V_ip6_sav && !(rcvif->if_flags & IFF_LOOPBACK) && + __predict_false(in6_localip_fib(&ip6->ip6_src, + rcvif->if_fib))) { + IP6STAT_INC(ip6s_badscope); /* XXX */ + goto bad; + } /* Count the packet in the ip address stats */ counter_u64_add(ia->ia_ifa.ifa_ipackets, 1); counter_u64_add(ia->ia_ifa.ifa_ibytes, m->m_pkthdr.len);