diff options
| author | Lexi Winter <ivy@FreeBSD.org> | 2025-05-02 08:40:20 +0100 |
|---|---|---|
| committer | Lexi Winter <ivy@FreeBSD.org> | 2025-05-02 10:25:04 +0100 |
| commit | 407ae28930ef2891f318bcd2251e8401a7d4f431 (patch) | |
| tree | bedeab930347be94dff0d03d48cc323d19d65621 | |
| parent | 2735c20d114f2d53b8a44d4fb7b00ab49280062b (diff) | |
nd6: allow address autoconf to be disabledlf/dev/no_prefixaddr
currently, it's possible to enable SLAAC (accept_rtadv) but disable
automatic default router configuration using the nd6 flag no_radr.
add a new flag, no_prefixaddr, which does the inverse: automatically
configure the default router, but don't configure any IP addresses, even
if an autonomous on-link prefix is advertised.
this decision is made late enough that we still configure the prefix
itself and handle updates to any autoconf addresses that may already
exist on the interface, but we don't configure a new address when we
usually would.
this flag is disabled by default, so existing behaviour is unchanged.
this conforms to RFC 4862 ยง 5.5:
Creation of global addresses as described in this section SHOULD be
locally configurable. However, the processing described below MUST
be enabled by default.
| -rw-r--r-- | sbin/ifconfig/af_inet6.c | 2 | ||||
| -rw-r--r-- | sbin/ifconfig/af_nd6.c | 1 | ||||
| -rw-r--r-- | sbin/ifconfig/ifconfig.8 | 30 | ||||
| -rw-r--r-- | sys/netinet6/in6_proto.c | 5 | ||||
| -rw-r--r-- | sys/netinet6/ip6_input.c | 1 | ||||
| -rw-r--r-- | sys/netinet6/ip6_var.h | 2 | ||||
| -rw-r--r-- | sys/netinet6/nd6.c | 8 | ||||
| -rw-r--r-- | sys/netinet6/nd6.h | 1 | ||||
| -rw-r--r-- | sys/netinet6/nd6_rtr.c | 9 | ||||
| -rwxr-xr-x | tests/sys/netinet6/ndp.sh | 53 |
10 files changed, 107 insertions, 5 deletions
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c index fcd04139a8c1..78342dd68b1d 100644 --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -706,6 +706,8 @@ static struct cmd inet6_cmds[] = { DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags), DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags), DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags), + DEF_CMD("no_prefixaddr",ND6_IFF_NO_PREFIXADDR, setnd6flags), + DEF_CMD("-no_prefixaddr",-ND6_IFF_NO_PREFIXADDR,setnd6flags), DEF_CMD("defaultif", 1, setnd6defif), DEF_CMD("-defaultif", -1, setnd6defif), DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c index 2899ad6a0778..dc01044601b2 100644 --- a/sbin/ifconfig/af_nd6.c +++ b/sbin/ifconfig/af_nd6.c @@ -66,6 +66,7 @@ static const char *ND6BITS[] = { [9] = "IPV6_ONLY", [10] = "IPV6_ONLY_MANUAL", #endif + [11] = "NO_PREFIXADDR", [15] = "DEFAULTIF", }; diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index e3f094a336fb..e24227aec035 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 24, 2025 +.Dd May 2, 2025 .Dt IFCONFIG 8 .Os .Sh NAME @@ -952,8 +952,32 @@ variable .Va net.inet6.ip6.no_radr controls whether this flag is set by default or not. .It Cm -no_radr -Clear a flag -.Cm no_radr . +Clear the +.Cm no_radr +flag. +.It Cm no_prefixaddr +Set a flag to control whether a Router Advertisement message including +an on-link autonomous prefix will result in an IP address in that prefix +being configured automatically. +If this flag is set, an address will not be configured, but a route for +the on-link prefix will be added to the system routing table. +In this case, the administrator should configure a static IP address. +The advertised router will still be added to the Default Router List +unless the +.Cm no_radr +flag is also set. +When the +.Cm accept_rtadv +flag is disabled, this flag has no effect. +The +.Xr sysctl 8 +variable +.Va net.inet6.ip6.no_prefixaddr +controls whether this flag is set by default or not. +.It Cm -no_prefixaddr +Clear the +.Cm no_prefixaddr +flag. .It Cm auto_linklocal Set a flag to perform automatic link-local address configuration when the interface becomes available. diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 8541e19eebf8..2c38558d426b 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -155,6 +155,7 @@ VNET_DEFINE(int, ip6_defhlim) = IPV6_DEFHLIM; VNET_DEFINE(int, ip6_defmcasthlim) = IPV6_DEFAULT_MULTICAST_HOPS; VNET_DEFINE(int, ip6_accept_rtadv) = 0; VNET_DEFINE(int, ip6_no_radr) = 0; +VNET_DEFINE(bool, ip6_no_prefixaddr) = 0; VNET_DEFINE(int, ip6_norbit_raif) = 0; VNET_DEFINE(int, ip6_rfc6204w3) = 0; VNET_DEFINE(int, ip6_hdrnestlimit) = 15;/* How many header options will we @@ -272,6 +273,10 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_NO_RADR, no_radr, "Default value of per-interface flag to control whether routers " "sending ICMPv6 RA messages on that interface are added into the " "default router list"); +SYSCTL_BOOL(_net_inet6_ip6, OID_AUTO, no_prefixaddr, + CTLFLAG_VNET | CTLFLAG_RWTUN, &VNET_NAME(ip6_no_prefixaddr), 0, + "Default value of per-interface flag to control whether ICMPv6 RA " + "messages with a prefix should configure an interface address"); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_NORBIT_RAIF, norbit_raif, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_norbit_raif), 0, "Always set clear the R flag in ICMPv6 NA messages when accepting RA " diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 68e4be66537b..1296d8cd4f51 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -230,6 +230,7 @@ ip6_vnet_init(void *arg __unused) &V_ip6_auto_linklocal); TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv); TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr); + TUNABLE_BOOL_FETCH("net.inet6.ip6.no_prefixaddr", &V_ip6_no_prefixaddr); CK_STAILQ_INIT(&V_in6_ifaddrhead); V_in6_ifaddrhashtbl = hashinit(IN6ADDR_NHASH, M_IFADDR, diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 12b00d4f9934..83d9b1328cdc 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -313,6 +313,7 @@ VNET_DECLARE(struct socket *, ip6_mrouter); /* multicast routing daemon */ VNET_DECLARE(int, ip6_sendredirects); /* send IP redirects when forwarding? */ VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */ VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */ +VNET_DECLARE(bool, ip6_no_prefixaddr); /* No address from RA */ VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA * receiving IF. */ VNET_DECLARE(int, ip6_rfc6204w3); /* Accept defroute from RA even when @@ -324,6 +325,7 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */ #define V_ip6_sendredirects VNET(ip6_sendredirects) #define V_ip6_accept_rtadv VNET(ip6_accept_rtadv) #define V_ip6_no_radr VNET(ip6_no_radr) +#define V_ip6_no_prefixaddr VNET(ip6_no_prefixaddr) #define V_ip6_norbit_raif VNET(ip6_norbit_raif) #define V_ip6_rfc6204w3 VNET(ip6_rfc6204w3) #define V_ip6_hdrnestlimit VNET(ip6_hdrnestlimit) diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 887da1ebe21a..23cba66dae9f 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -318,8 +318,12 @@ nd6_ifattach(struct ifnet *ifp) /* If we globally accept rtadv, assume IPv6 on. */ nd->flags &= ~ND6_IFF_IFDISABLED; } - if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK)) - nd->flags |= ND6_IFF_NO_RADR; + if ((ifp->if_flags & IFF_LOOPBACK) == 0) { + if (V_ip6_no_radr) + nd->flags |= ND6_IFF_NO_RADR; + if (V_ip6_no_prefixaddr) + nd->flags |= ND6_IFF_NO_PREFIXADDR; + } /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 1db1b666c60b..9ece5950eeb8 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -95,6 +95,7 @@ struct nd_ifinfo { #define ND6_IFF_IPV6_ONLY_MANUAL 0x400 #define ND6_IFF_IPV6_ONLY_MASK (ND6_IFF_IPV6_ONLY|ND6_IFF_IPV6_ONLY_MANUAL) #endif +#define ND6_IFF_NO_PREFIXADDR 0x800 #ifdef _KERNEL #define ND_IFINFO(ifp) \ diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 845f9094f4c4..ac7e135735e9 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1711,6 +1711,15 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, } if (ia6_match == NULL && new->ndpr_vltime) { int ifidlen; + struct nd_ifinfo *ndi = ND_IFINFO(ifp); + + /* + * If no_prefixaddr is set, skip creating a new address. Do + * this here after we've already processed any addresses that + * might already exist. + */ + if (ndi->flags & ND6_IFF_NO_PREFIXADDR) + goto end; /* * 5.5.3 (d) (continued) diff --git a/tests/sys/netinet6/ndp.sh b/tests/sys/netinet6/ndp.sh index bac9764ee3c9..fb31a197f094 100755 --- a/tests/sys/netinet6/ndp.sh +++ b/tests/sys/netinet6/ndp.sh @@ -166,6 +166,10 @@ ndp_slaac_default_route_body() { atf_check -o match:"^default[[:space:]]+fe80:" \ jexec ${jname} netstat -rn -6 + # Ensure that we configured an IP address on the interface. + atf_check -o match:"^[[:space:]]+inet6 2001:db8:ffff:1000:.*autoconf" \ + jexec ${jname} ifconfig ${epair0}a + # Get rid of the default route. jexec ${jname} route -6 flush atf_check -o not-match:"^default[[:space:]]+fe80:" \ @@ -188,9 +192,58 @@ ndp_slaac_default_route_cleanup() { vnet_cleanup } +atf_test_case "ndp_slaac_no_prefixaddr" "cleanup" +ndp_slaac_no_prefixaddr_head() { + atf_set descr 'Test SLAAC with nd6 no_prefixaddr option' + atf_set require.user root + atf_set require.progs python3 scapy +} + +ndp_slaac_no_prefixaddr_body() { + local epair0 jname lladdr + + vnet_init + + jname="v6t-ndp_slaac_no_prefixaddr" + + epair0=$(vnet_mkepair) + + vnet_mkjail ${jname} ${epair0}a + + ndp_if_up ${epair0}a ${jname} + ndp_if_up ${epair0}b + atf_check jexec ${jname} ifconfig ${epair0}a \ + inet6 accept_rtadv no_prefixaddr + + # Send an RA advertising a prefix. + atf_check -e ignore python3 $(atf_get_srcdir)/ra.py \ + --sendif ${epair0}b \ + --dst $(ndp_if_lladdr ${epair0}a ${jname}) \ + --src $(ndp_if_lladdr ${epair0}b) \ + --prefix "2001:db8:ffff:1000::" --prefixlen 64 + + # Wait for a default router to appear. + while [ -z "$(jexec ${jname} ndp -r)" ]; do + sleep 0.1 + done + + # Ensure we configured a default route. + atf_check -o match:"^default[[:space:]]+fe80:" \ + jexec ${jname} netstat -rn -6 + + # Ensure that we didn't configure an IP address on the interface. + atf_check -o not-match:"^[[:space:]]+inet6 2001:db8:ffff:1000:.*autoconf" \ + jexec ${jname} ifconfig ${epair0}a +} + +ndp_slaac_no_prefixaddr_cleanup() { + vnet_cleanup +} + atf_init_test_cases() { atf_add_test_case "ndp_add_gu_success" atf_add_test_case "ndp_del_gu_success" atf_add_test_case "ndp_slaac_default_route" + atf_add_test_case "ndp_slaac_no_prefixaddr" } |
