git: 1817be481b87 - main - Add net.inet6.ip6.source_address_validation

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Fri, 12 Nov 2021 17:07:25 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=1817be481b8703ae86730b151a6f49cc3022930f

commit 1817be481b8703ae86730b151a6f49cc3022930f
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2021-11-12 17:01:13 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2021-11-12 17:01:40 +0000

    Add net.inet6.ip6.source_address_validation
    
    Drop packets arriving from the network that have our source IPv6
    address.  If maliciously crafted they can create evil effects
    like an RST exchange between two of our listening TCP ports.
    Such packets just can't be legitimate.  Enable the tunable
    by default.  Long time due for a modern Internet host.
    
    Reviewed by:            melifaro, donner, kp
    Differential revision:  https://reviews.freebsd.org/D32915
---
 share/man/man4/inet6.4   | 10 +++++++++-
 sys/netinet6/ip6_input.c | 12 ++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/share/man/man4/inet6.4 b/share/man/man4/inet6.4
index 300f98abb196..87c57ea2c3d2 100644
--- 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 @@ mapped address on
 .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
index 30ad9a53006a..2d4e63ca83b6 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -163,6 +163,12 @@ SYSCTL_PROC(_net_inet6_ip6, IPV6CTL_INTRQMAXLEN, intr_queue_maxlen,
     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 @@ passin:
 			    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);