From 1f9e444e923b65200aa48a7199654b1001e5a68c Mon Sep 17 00:00:00 2001 From: bluhm Date: Sun, 14 Jul 2024 18:53:39 +0000 Subject: [PATCH] Unlock IPv6 sysctl net.inet6.ip6.forwarding from net lock. Use atomic operations to read ip6_forwarding while processing packets in the network stack. To make clear where actually the router property is needed, use the i_am_router variable based on ip6_forwarding. It already existed in nd6_nbr. Move i_am_router setting up the call stack until all users are independent. The forwarding decisions in pf_test, pf_refragment6, ip6_input do also not interfere. Use a new array ipv6ctl_vars_unlocked to make transition of all the integer sysctls easier. Adapt IPv4 to the new style. OK mvs@ --- sys/net/if.c | 5 +++-- sys/net/pf.c | 4 ++-- sys/net/pf_norm.c | 4 ++-- sys/netinet/ip_carp.c | 5 +++-- sys/netinet/ip_icmp.c | 6 +++--- sys/netinet/ip_input.c | 11 ++++++++--- sys/netinet6/icmp6.c | 10 ++++++---- sys/netinet6/ip6_input.c | 13 ++++++++++--- sys/netinet6/nd6.c | 28 +++++++++++++++------------- sys/netinet6/nd6.h | 4 ++-- sys/netinet6/nd6_nbr.c | 8 ++++---- sys/netinet6/nd6_rtr.c | 6 ++++-- 12 files changed, 62 insertions(+), 42 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index 46e4e8c95f5..e0a9db5144a 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.719 2024/06/20 19:25:42 bluhm Exp $ */ +/* $OpenBSD: if.c,v 1.720 2024/07/14 18:53:39 bluhm Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -3353,6 +3353,7 @@ ifnewlladdr(struct ifnet *ifp) { #ifdef INET6 struct ifaddr *ifa; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); #endif struct ifreq ifrq; short up; @@ -3378,7 +3379,7 @@ ifnewlladdr(struct ifnet *ifp) * Update the link-local address. Don't do it if we're * a router to avoid confusing hosts on the network. */ - if (ip6_forwarding == 0) { + if (!i_am_router) { ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa; if (ifa) { in6_purgeaddr(ifa); diff --git a/sys/net/pf.c b/sys/net/pf.c index fb278db3b14..378bafc2190 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1202 2024/07/12 09:25:27 bluhm Exp $ */ +/* $OpenBSD: pf.c,v 1.1203 2024/07/14 18:53:39 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -7988,7 +7988,7 @@ done: if (pd.dir == PF_IN) { int flags = IPV6_REDIRECT; - switch (ip6_forwarding) { + switch (atomic_load_int(&ip6_forwarding)) { case 2: SET(flags, IPV6_FORWARDING_IPSEC); /* FALLTHROUGH */ diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 4178fe785a1..2bfad7873de 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.232 2024/07/04 12:50:08 bluhm Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.233 2024/07/14 18:53:39 bluhm Exp $ */ /* * Copyright 2001 Niels Provos @@ -1013,7 +1013,7 @@ pf_refragment6(struct mbuf **m0, struct m_tag *mtag, struct sockaddr_in6 *dst, if (ifp == NULL) { int flags = 0; - switch (ip6_forwarding) { + switch (atomic_load_int(&ip6_forwarding)) { case 2: SET(flags, IPV6_FORWARDING_IPSEC); /* FALLTHROUGH */ diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index c6e882f0b90..26139316c66 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.c,v 1.362 2024/06/20 19:25:42 bluhm Exp $ */ +/* $OpenBSD: ip_carp.c,v 1.363 2024/07/14 18:53:39 bluhm Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -1287,9 +1287,10 @@ carp_send_na(struct carp_softc *sc) struct ifaddr *ifa; struct in6_addr *in6; static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); int flags = ND_NA_FLAG_OVERRIDE; - if (ip6_forwarding != 0) + if (i_am_router) flags |= ND_NA_FLAG_ROUTER; TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) { diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index baaa9a210fd..5c5ccde138a 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_icmp.c,v 1.195 2024/07/12 09:25:27 bluhm Exp $ */ +/* $OpenBSD: ip_icmp.c,v 1.196 2024/07/14 18:53:39 bluhm Exp $ */ /* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */ /* @@ -588,9 +588,9 @@ reflect: struct sockaddr_in sgw; struct sockaddr_in ssrc; struct rtentry *newrt = NULL; + int i_am_router = (atomic_load_int(&ip_forwarding) != 0); - if (icmp_rediraccept == 0 || - atomic_load_int(&ip_forwarding) != 0) + if (icmp_rediraccept == 0 || i_am_router) goto freeit; if (code > 3) goto badcode; diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 8797a26b025..1d68e0f6161 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.398 2024/07/12 09:25:27 bluhm Exp $ */ +/* $OpenBSD: ip_input.c,v 1.399 2024/07/14 18:53:39 bluhm Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -111,6 +111,10 @@ LIST_HEAD(, ipq) ipq; int ip_maxqueue = 300; int ip_frags = 0; +const struct sysctl_bounded_args ipctl_vars_unlocked[] = { + { IPCTL_FORWARDING, &ip_forwarding, 0, 2 }, +}; + const struct sysctl_bounded_args ipctl_vars[] = { #ifdef MROUTING { IPCTL_MRTPROTO, &ip_mrtproto, SYSCTL_INT_READONLY }, @@ -1799,8 +1803,9 @@ ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, NET_UNLOCK(); return (error); case IPCTL_FORWARDING: - return (sysctl_int_bounded(oldp, oldlenp, newp, newlen, - &ip_forwarding, 0, 2)); + return (sysctl_bounded_arr( + ipctl_vars_unlocked, nitems(ipctl_vars_unlocked), + name, namelen, oldp, oldlenp, newp, newlen)); default: NET_LOCK(); error = sysctl_bounded_arr(ipctl_vars, nitems(ipctl_vars), diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 2a8950d0a66..04ad1b3e023 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: icmp6.c,v 1.253 2024/06/20 19:25:42 bluhm Exp $ */ +/* $OpenBSD: icmp6.c,v 1.254 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ /* @@ -1228,6 +1228,7 @@ icmp6_redirect_input(struct mbuf *m, int off) char *lladdr = NULL; int lladdrlen = 0; struct rtentry *rt = NULL; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); int is_router; int is_onlink; struct in6_addr src6 = ip6->ip6_src; @@ -1241,7 +1242,7 @@ icmp6_redirect_input(struct mbuf *m, int off) return; /* if we are router, we don't update route by icmp6 redirect */ - if (ip6_forwarding != 0) + if (i_am_router) goto freeit; if (!(ifp->if_xflags & IFXF_AUTOCONF6)) goto freeit; @@ -1366,7 +1367,7 @@ icmp6_redirect_input(struct mbuf *m, int off) /* RFC 2461 8.3 */ nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT, - is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER); + is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER, i_am_router); if (!is_onlink) { /* better router case. perform rtredirect. */ /* perform rtredirect */ @@ -1438,11 +1439,12 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) size_t maxlen; u_char *p; struct sockaddr_in6 src_sa; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); icmp6_errcount(ND_REDIRECT, 0); /* if we are not router, we don't send icmp6 redirect */ - if (ip6_forwarding == 0) + if (!i_am_router) goto fail; /* sanity check */ diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 6952cf632f9..4ab7d8c4578 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.264 2024/07/04 12:50:08 bluhm Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.265 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -416,7 +416,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp) SET(flags, IPV6_REDIRECT); #endif - switch (ip6_forwarding) { + switch (atomic_load_int(&ip6_forwarding)) { case 2: SET(flags, IPV6_FORWARDING_IPSEC); /* FALLTHROUGH */ @@ -1443,12 +1443,15 @@ const u_char inet6ctlerrmap[PRC_NCMDS] = { extern int ip6_mrtproto; #endif +const struct sysctl_bounded_args ipv6ctl_vars_unlocked[] = { + { IPV6CTL_FORWARDING, &ip6_forwarding, 0, 2 }, +}; + const struct sysctl_bounded_args ipv6ctl_vars[] = { { IPV6CTL_DAD_PENDING, &ip6_dad_pending, SYSCTL_INT_READONLY }, #ifdef MROUTING { IPV6CTL_MRTPROTO, &ip6_mrtproto, SYSCTL_INT_READONLY }, #endif - { IPV6CTL_FORWARDING, &ip6_forwarding, 0, 2 }, { IPV6CTL_SENDREDIRECTS, &ip6_sendredirects, 0, 1 }, { IPV6CTL_DEFHLIM, &ip6_defhlim, 0, 255 }, { IPV6CTL_MAXFRAGPACKETS, &ip6_maxfragpackets, 0, 1000 }, @@ -1568,6 +1571,10 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, atomic_inc_long(&rtgeneration); NET_UNLOCK(); return (error); + case IPV6CTL_FORWARDING: + return (sysctl_bounded_arr( + ipv6ctl_vars_unlocked, nitems(ipv6ctl_vars_unlocked), + name, namelen, oldp, oldlenp, newp, newlen)); default: NET_LOCK(); error = sysctl_bounded_arr(ipv6ctl_vars, nitems(ipv6ctl_vars), diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 28bc1b91d50..fce85be1a2c 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.c,v 1.281 2024/06/20 19:25:42 bluhm Exp $ */ +/* $OpenBSD: nd6.c,v 1.282 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $ */ /* @@ -107,8 +107,8 @@ void nd6_slowtimo(void *); void nd6_expire(void *); void nd6_expire_timer(void *); void nd6_invalidate(struct rtentry *); -void nd6_free(struct rtentry *); -int nd6_llinfo_timer(struct rtentry *); +void nd6_free(struct rtentry *, int); +int nd6_llinfo_timer(struct rtentry *, int); struct timeout nd6_timer_to; struct timeout nd6_slowtimo_ch; @@ -264,6 +264,7 @@ nd6_timer(void *unused) { struct llinfo_nd6 *ln, *nln; time_t uptime, expire; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); int secs; NET_LOCK(); @@ -276,7 +277,7 @@ nd6_timer(void *unused) struct rtentry *rt = ln->ln_rt; if (rt->rt_expire && rt->rt_expire <= uptime) - if (nd6_llinfo_timer(rt)) + if (nd6_llinfo_timer(rt, i_am_router)) continue; if (rt->rt_expire && rt->rt_expire < expire) @@ -300,7 +301,7 @@ nd6_timer(void *unused) * Returns 1 if `rt' should no longer be used, 0 otherwise. */ int -nd6_llinfo_timer(struct rtentry *rt) +nd6_llinfo_timer(struct rtentry *rt, int i_am_router) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; struct sockaddr_in6 *dst = satosin6(rt_key(rt)); @@ -346,7 +347,7 @@ nd6_llinfo_timer(struct rtentry *rt) } else atomic_sub_int(&ln_hold_total, len); - nd6_free(rt); + nd6_free(rt, i_am_router); ln = NULL; } break; @@ -362,7 +363,7 @@ nd6_llinfo_timer(struct rtentry *rt) case ND6_LLINFO_PURGE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_free(rt); + nd6_free(rt, i_am_router); ln = NULL; } break; @@ -383,7 +384,7 @@ nd6_llinfo_timer(struct rtentry *rt) nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, &ln->ln_saddr6, 0); } else { - nd6_free(rt); + nd6_free(rt, i_am_router); ln = NULL; } break; @@ -477,6 +478,7 @@ void nd6_purge(struct ifnet *ifp) { struct llinfo_nd6 *ln, *nln; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); NET_ASSERT_LOCKED_EXCLUSIVE(); @@ -492,7 +494,7 @@ nd6_purge(struct ifnet *ifp) rt->rt_gateway->sa_family == AF_LINK) { sdl = satosdl(rt->rt_gateway); if (sdl->sdl_index == ifp->if_index) - nd6_free(rt); + nd6_free(rt, i_am_router); } } } @@ -661,7 +663,7 @@ nd6_invalidate(struct rtentry *rt) * Free an nd6 llinfo entry. */ void -nd6_free(struct rtentry *rt) +nd6_free(struct rtentry *rt, int i_am_router) { struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; struct in6_addr in6 = satosin6(rt_key(rt))->sin6_addr; @@ -671,7 +673,7 @@ nd6_free(struct rtentry *rt) ifp = if_get(rt->rt_ifidx); - if (ip6_forwarding == 0) { + if (!i_am_router) { if (ln->ln_router) { /* * rt6_flush must be called whether or not the neighbor @@ -1031,7 +1033,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) */ void nd6_cache_lladdr(struct ifnet *ifp, const struct in6_addr *from, char *lladdr, - int lladdrlen, int type, int code) + int lladdrlen, int type, int code, int i_am_router) { struct rtentry *rt; struct llinfo_nd6 *ln; @@ -1080,7 +1082,7 @@ nd6_cache_lladdr(struct ifnet *ifp, const struct in6_addr *from, char *lladdr, return; if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { fail: - nd6_free(rt); + nd6_free(rt, i_am_router); rtfree(rt); return; } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 293ccbfb671..b65fad00977 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.h,v 1.99 2023/05/04 06:56:56 bluhm Exp $ */ +/* $OpenBSD: nd6.h,v 1.100 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ /* @@ -134,7 +134,7 @@ void nd6_nud_hint(struct rtentry *); void nd6_rtrequest(struct ifnet *, int, struct rtentry *); int nd6_ioctl(u_long, caddr_t, struct ifnet *); void nd6_cache_lladdr(struct ifnet *, const struct in6_addr *, char *, - int, int, int); + int, int, int, int); int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *); int nd6_need_cache(struct ifnet *); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index b6747312d5b..2e491334501 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_nbr.c,v 1.152 2024/06/20 19:25:42 bluhm Exp $ */ +/* $OpenBSD: nd6_nbr.c,v 1.153 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -108,7 +108,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) struct ifaddr *ifa = NULL; int lladdrlen = 0; int anycast = 0, proxy = 0, tentative = 0; - int i_am_router = (ip6_forwarding != 0); + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); int tlladdr; struct nd_opts ndopts; struct sockaddr_dl *proxydl = NULL; @@ -323,7 +323,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, - 0); + 0, i_am_router); nd6_na_output(ifp, &saddr6, &taddr6, ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | @@ -559,7 +559,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) int is_override; char *lladdr = NULL; int lladdrlen = 0; - int i_am_router = (ip6_forwarding != 0); + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); struct ifaddr *ifa; struct in6_ifaddr *ifa6; struct llinfo_nd6 *ln; diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index d68b7a8ef67..1d4ec431259 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_rtr.c,v 1.170 2023/03/31 19:43:33 bluhm Exp $ */ +/* $OpenBSD: nd6_rtr.c,v 1.171 2024/07/14 18:53:39 bluhm Exp $ */ /* $KAME: nd6_rtr.c,v 1.97 2001/02/07 11:09:13 itojun Exp $ */ /* @@ -73,6 +73,7 @@ nd6_rtr_cache(struct mbuf *m, int off, int icmp6len, int icmp6_type) struct in6_addr saddr6 = ip6->ip6_src; char *lladdr = NULL; int lladdrlen = 0; + int i_am_router = (atomic_load_int(&ip6_forwarding) != 0); struct nd_opts ndopts; char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN]; @@ -157,7 +158,8 @@ nd6_rtr_cache(struct mbuf *m, int off, int icmp6len, int icmp6_type) goto bad; } - nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, icmp6_type, 0); + nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, icmp6_type, 0, + i_am_router); if_put(ifp); freeit: -- 2.20.1