diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -706,6 +706,8 @@ 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 --- a/sbin/ifconfig/af_nd6.c +++ b/sbin/ifconfig/af_nd6.c @@ -66,6 +66,7 @@ [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 --- 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 @@ .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 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -155,6 +155,7 @@ 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 @@ "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 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -230,6 +230,7 @@ &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 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -313,6 +313,7 @@ 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 @@ #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.h b/sys/netinet6/nd6.h --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -95,6 +95,7 @@ #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.c b/sys/netinet6/nd6.c --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -318,8 +318,12 @@ /* 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_rtr.c b/sys/netinet6/nd6_rtr.c --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1711,6 +1711,15 @@ } 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 --- a/tests/sys/netinet6/ndp.sh +++ b/tests/sys/netinet6/ndp.sh @@ -166,6 +166,10 @@ 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 @@ 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" }