Read IPv6 forwarding value only once while processing a packet.
authorbluhm <bluhm@openbsd.org>
Thu, 20 Jun 2024 19:25:42 +0000 (19:25 +0000)
committerbluhm <bluhm@openbsd.org>
Thu, 20 Jun 2024 19:25:42 +0000 (19:25 +0000)
IPv4 uses IP_FORWARDING to pass down a consistent value of
net.inet.ip.forwarding down the stack.  This is needed for unlocking
sysctl.  Do the same for IPv6.

Read ip6_forwarding once in ip6_input_if() and pass down IPV6_FORWARDING
as flags to ip6_ours(), ip6_hbhchcheck(), ip6_forward().  Replace
the srcrt value with IPV6_REDIRECT flag for consistency with IPv4.

To have common syntax with IPv4, use ip6_forwarding == 0 checks
instead of !ip6_forwarding.  This will also make it easier to
implement net.inet6.ip6.forwarding=2 for IPsec only forwarding
later.

In nd6_ns_input() and nd6_na_input() read ip6_forwarding once and
store it in i_am_router.  The variable name has been chosen to avoid
confusion with is_router, which indicates router flag of the packet.
Reading of ip6_forwarding is done independently from ip6_input_if(),
consistency does not really matter.  One is for ND router behavior
the other for forwarding.  Again use the ip6_forwarding != 0 check,
so when ip6_forwarding IPsec only value 2 gets implemented, it will
behave like a router.

OK deraadt@ sashan@ florian@ claudio@

sys/net/if.c
sys/net/pf.c
sys/net/pf_norm.c
sys/netinet/ip_carp.c
sys/netinet6/icmp6.c
sys/netinet6/ip6_forward.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_var.h
sys/netinet6/nd6.c
sys/netinet6/nd6_nbr.c

index 9b97125..46e4e8c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if.c,v 1.718 2024/02/06 00:18:53 bluhm Exp $  */
+/*     $OpenBSD: if.c,v 1.719 2024/06/20 19:25:42 bluhm Exp $  */
 /*     $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $  */
 
 /*
@@ -3378,7 +3378,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) {
+       if (ip6_forwarding == 0) {
                ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa;
                if (ifa) {
                        in6_purgeaddr(ifa);
index ecc6bfe..47ec92d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf.c,v 1.1197 2024/06/07 18:24:16 bluhm Exp $ */
+/*     $OpenBSD: pf.c,v 1.1198 2024/06/20 19:25:42 bluhm Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -7974,12 +7974,15 @@ done:
                        break;
                case AF_INET6:
                        if (pd.dir == PF_IN) {
+                               int flags;
+
                                if (ip6_forwarding == 0) {
                                        ip6stat_inc(ip6s_cantforward);
                                        action = PF_DROP;
                                        break;
                                }
-                               ip6_forward(pd.m, NULL, 1);
+                               flags = IPV6_FORWARDING | IPV6_REDIRECT;
+                               ip6_forward(pd.m, NULL, flags);
                        } else
                                ip6_output(pd.m, NULL, NULL, 0, NULL, NULL);
                        break;
index 571dbf9..8799b84 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf_norm.c,v 1.230 2024/04/22 13:30:22 bluhm Exp $ */
+/*     $OpenBSD: pf_norm.c,v 1.231 2024/06/20 19:25:42 bluhm Exp $ */
 
 /*
  * Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -1011,7 +1011,7 @@ pf_refragment6(struct mbuf **m0, struct m_tag *mtag, struct sockaddr_in6 *dst,
        while ((m = ml_dequeue(&ml)) != NULL) {
                m->m_pkthdr.pf.flags |= PF_TAG_REFRAGMENTED;
                if (ifp == NULL) {
-                       ip6_forward(m, NULL, 0);
+                       ip6_forward(m, NULL, IPV6_FORWARDING);
                } else if ((u_long)m->m_pkthdr.len <= ifp->if_mtu) {
                        ifp->if_output(ifp, m, sin6tosa(dst), rt);
                } else {
index 41e9d34..c6e882f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_carp.c,v 1.361 2024/02/13 12:22:09 bluhm Exp $     */
+/*     $OpenBSD: ip_carp.c,v 1.362 2024/06/20 19:25:42 bluhm Exp $     */
 
 /*
  * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -1287,6 +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 flags = ND_NA_FLAG_OVERRIDE;
+
+       if (ip6_forwarding != 0)
+               flags |= ND_NA_FLAG_ROUTER;
 
        TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
 
@@ -1294,9 +1298,7 @@ carp_send_na(struct carp_softc *sc)
                        continue;
 
                in6 = &ifatoia6(ifa)->ia_addr.sin6_addr;
-               nd6_na_output(&sc->sc_if, &mcast, in6,
-                   ND_NA_FLAG_OVERRIDE |
-                   (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0), 1, NULL);
+               nd6_na_output(&sc->sc_if, &mcast, in6, flags, 1, NULL);
        }
 }
 #endif /* INET6 */
index 058800b..2a8950d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: icmp6.c,v 1.252 2024/04/21 17:32:10 florian Exp $     */
+/*     $OpenBSD: icmp6.c,v 1.253 2024/06/20 19:25:42 bluhm Exp $       */
 /*     $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
 
 /*
@@ -1240,8 +1240,8 @@ icmp6_redirect_input(struct mbuf *m, int off)
        if (ifp == NULL)
                return;
 
-       /* XXX if we are router, we don't update route by icmp6 redirect */
-       if (ip6_forwarding)
+       /* if we are router, we don't update route by icmp6 redirect */
+       if (ip6_forwarding != 0)
                goto freeit;
        if (!(ifp->if_xflags & IFXF_AUTOCONF6))
                goto freeit;
@@ -1442,7 +1442,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
        icmp6_errcount(ND_REDIRECT, 0);
 
        /* if we are not router, we don't send icmp6 redirect */
-       if (!ip6_forwarding)
+       if (ip6_forwarding == 0)
                goto fail;
 
        /* sanity check */
index 13e6037..9daf51f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_forward.c,v 1.118 2024/06/07 18:24:16 bluhm Exp $ */
+/*     $OpenBSD: ip6_forward.c,v 1.119 2024/06/20 19:25:42 bluhm Exp $ */
 /*     $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $    */
 
 /*
@@ -82,7 +82,7 @@
  */
 
 void
-ip6_forward(struct mbuf *m, struct route *ro, int srcrt)
+ip6_forward(struct mbuf *m, struct route *ro, int flags)
 {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        struct route iproute;
@@ -248,8 +248,8 @@ reroute:
                m_freem(m);
                goto freecopy;
        }
-       if (rt->rt_ifidx == m->m_pkthdr.ph_ifidx && !srcrt &&
-           ip6_sendredirects &&
+       if (rt->rt_ifidx == m->m_pkthdr.ph_ifidx &&
+           ip6_sendredirects && !ISSET(flags, IPV6_REDIRECT) &&
            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
                if ((ifp->if_flags & IFF_POINTOPOINT) &&
                    nd6_is_addr_neighbor(&ro->ro_dstsin6, ifp)) {
@@ -305,7 +305,7 @@ reroute:
        } else if (m->m_pkthdr.pf.flags & PF_TAG_REROUTE) {
                /* tag as generated to skip over pf_test on rerun */
                m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
-               srcrt = 1;
+               SET(flags, IPV6_REDIRECT);
                if (ro == &iproute)
                        rtfree(ro->ro_rt);
                ro = NULL;
index 276a35d..de9468e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.262 2024/05/08 13:01:30 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.263 2024/06/20 19:25:42 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -119,9 +119,9 @@ struct cpumem *ip6counters;
 
 uint8_t ip6_soiikey[IP6_SOIIKEY_LEN];
 
-int ip6_ours(struct mbuf **, int *, int, int);
+int ip6_ours(struct mbuf **, int *, int, int, int);
 int ip6_check_rh0hdr(struct mbuf *, int *);
-int ip6_hbhchcheck(struct mbuf **, int *, int *);
+int ip6_hbhchcheck(struct mbuf **, int *, int *, int);
 int ip6_hopopts_input(struct mbuf **, int *, u_int32_t *, u_int32_t *);
 struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
 int ip6_sysctl_soiikey(void *, size_t *, void *, size_t);
@@ -172,11 +172,11 @@ ip6_init(void)
  * NET_LOCK_SHARED() and the transport layer needing it exclusively.
  */
 int
-ip6_ours(struct mbuf **mp, int *offp, int nxt, int af)
+ip6_ours(struct mbuf **mp, int *offp, int nxt, int af, int flags)
 {
        /* ip6_hbhchcheck() may be run before, then off and nxt are set */
        if (*offp == 0) {
-               nxt = ip6_hbhchcheck(mp, offp, NULL);
+               nxt = ip6_hbhchcheck(mp, offp, NULL, flags);
                if (nxt == IPPROTO_DONE)
                        return IPPROTO_DONE;
        }
@@ -365,7 +365,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 #if NPF > 0
        struct in6_addr odst;
 #endif
-       int pfrdr = 0;
+       int flags = 0;
 
        KASSERT(*offp == 0);
 
@@ -412,9 +412,13 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                goto bad;
 
        ip6 = mtod(m, struct ip6_hdr *);
-       pfrdr = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst);
+       if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst))
+               SET(flags, IPV6_REDIRECT);
 #endif
 
+       if (ip6_forwarding != 0)
+               SET(flags, IPV6_FORWARDING);
+
        /*
         * Without embedded scope ID we cannot find link-local
         * addresses in the routing table.
@@ -445,7 +449,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
 #if NPF > 0
        if (pf_ouraddr(m) == 1) {
-               nxt = ip6_ours(mp, offp, nxt, af);
+               nxt = ip6_ours(mp, offp, nxt, af, flags);
                goto out;
        }
 #endif
@@ -472,7 +476,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                if (ip6_mforwarding && ip6_mrouter[ifp->if_rdomain]) {
                        int error;
 
-                       nxt = ip6_hbhchcheck(&m, offp, &ours);
+                       nxt = ip6_hbhchcheck(&m, offp, &ours, flags);
                        if (nxt == IPPROTO_DONE)
                                goto out;
 
@@ -496,7 +500,8 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
                        if (ours) {
                                if (af == AF_UNSPEC)
-                                       nxt = ip6_ours(mp, offp, nxt, af);
+                                       nxt = ip6_ours(mp, offp, nxt, af,
+                                           flags);
                                goto out;
                        }
                        goto bad;
@@ -508,7 +513,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                                ip6stat_inc(ip6s_cantforward);
                        goto bad;
                }
-               nxt = ip6_ours(mp, offp, nxt, af);
+               nxt = ip6_ours(mp, offp, nxt, af, flags);
                goto out;
        }
 
@@ -526,7 +531,8 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
        if (rt != NULL && ISSET(rt->rt_flags, RTF_LOCAL)) {
                struct in6_ifaddr *ia6 = ifatoia6(rt->rt_ifa);
 
-               if (ip6_forwarding == 0 && rt->rt_ifidx != ifp->if_index &&
+               if (!ISSET(flags, IPV6_FORWARDING) &&
+                   rt->rt_ifidx != ifp->if_index &&
                    !((ifp->if_flags & IFF_LOOPBACK) ||
                    (ifp->if_type == IFT_ENC) ||
                    (m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST))) {
@@ -567,7 +573,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
                        goto bad;
                } else {
-                       nxt = ip6_ours(mp, offp, nxt, af);
+                       nxt = ip6_ours(mp, offp, nxt, af, flags);
                        goto out;
                }
        }
@@ -582,18 +588,18 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
         * Now there is no reason to process the packet if it's not our own
         * and we're not a router.
         */
-       if (!ip6_forwarding) {
+       if (!ISSET(flags, IPV6_FORWARDING)) {
                ip6stat_inc(ip6s_cantforward);
                goto bad;
        }
 
-       nxt = ip6_hbhchcheck(&m, offp, &ours);
+       nxt = ip6_hbhchcheck(&m, offp, &ours, flags);
        if (nxt == IPPROTO_DONE)
                goto out;
 
        if (ours) {
                if (af == AF_UNSPEC)
-                       nxt = ip6_ours(mp, offp, nxt, af);
+                       nxt = ip6_ours(mp, offp, nxt, af, flags);
                goto out;
        }
 
@@ -613,7 +619,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
        }
 #endif /* IPSEC */
 
-       ip6_forward(m, &ro, pfrdr);
+       ip6_forward(m, &ro, flags);
        *mp = NULL;
        rtfree(ro.ro_rt);
        return IPPROTO_DONE;
@@ -627,7 +633,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 
 /* On error free mbuf and return IPPROTO_DONE. */
 int
-ip6_hbhchcheck(struct mbuf **mp, int *offp, int *oursp)
+ip6_hbhchcheck(struct mbuf **mp, int *offp, int *oursp, int flags)
 {
        struct ip6_hdr *ip6;
        u_int32_t plen, rtalert = ~0;
@@ -680,7 +686,8 @@ ip6_hbhchcheck(struct mbuf **mp, int *offp, int *oursp)
                 * accept the packet if a router alert option is included
                 * and we act as an IPv6 router.
                 */
-               if (rtalert != ~0 && ip6_forwarding && oursp != NULL)
+               if (rtalert != ~0 && ISSET(flags, IPV6_FORWARDING) &&
+                   oursp != NULL)
                        *oursp = 1;
        } else
                nxt = ip6->ip6_nxt;
index 5987653..47fca70 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.117 2024/05/13 01:15:53 jsg Exp $       */
+/*     $OpenBSD: ip6_var.h,v 1.118 2024/06/20 19:25:42 bluhm Exp $     */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -265,10 +265,11 @@ ip6stat_add(enum ip6stat_counters c, uint64_t v)
        counters_add(ip6counters, c, v);
 }
 
-/* flags passed to ip6_output as last parameter */
-#define        IPV6_UNSPECSRC          0x01    /* allow :: as the source address */
-#define        IPV6_FORWARDING         0x02    /* most of IPv6 header exists */
-#define        IPV6_MINMTU             0x04    /* use minimum MTU (IPV6_USE_MIN_MTU) */
+/* flags passed to ip6_output or ip6_forward as last parameter */
+#define IPV6_UNSPECSRC         0x01    /* allow :: as the source address */
+#define IPV6_FORWARDING                0x02    /* most of IPv6 header exists */
+#define IPV6_MINMTU            0x04    /* use minimum MTU (IPV6_USE_MIN_MTU) */
+#define IPV6_REDIRECT          0x08    /* redirected by pf */
 
 extern int ip6_mtudisc_timeout;                /* mtu discovery */
 extern struct rttimer_queue icmp6_mtudisc_timeout_q;
index 8ddde15..28bc1b9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nd6.c,v 1.280 2023/05/13 16:27:59 bluhm Exp $ */
+/*     $OpenBSD: nd6.c,v 1.281 2024/06/20 19:25:42 bluhm Exp $ */
 /*     $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $   */
 
 /*
@@ -671,7 +671,7 @@ nd6_free(struct rtentry *rt)
 
        ifp = if_get(rt->rt_ifidx);
 
-       if (!ip6_forwarding) {
+       if (ip6_forwarding == 0) {
                if (ln->ln_router) {
                        /*
                         * rt6_flush must be called whether or not the neighbor
index e2fccc4..b674731 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nd6_nbr.c,v 1.151 2023/07/30 12:52:03 krw Exp $       */
+/*     $OpenBSD: nd6_nbr.c,v 1.152 2024/06/20 19:25:42 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 router = ip6_forwarding;
+       int i_am_router = (ip6_forwarding != 0);
        int tlladdr;
        struct nd_opts ndopts;
        struct sockaddr_dl *proxydl = NULL;
@@ -244,7 +244,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
                        if (ifa) {
                                proxy = 1;
                                proxydl = satosdl(rt->rt_gateway);
-                               router = 0;     /* XXX */
+                               i_am_router = 0;        /* XXX */
                        }
                }
                if (rt)
@@ -317,7 +317,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
                saddr6.s6_addr16[1] = htons(ifp->if_index);
                nd6_na_output(ifp, &saddr6, &taddr6,
                    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
-                   (router ? ND_NA_FLAG_ROUTER : 0),
+                   (i_am_router ? ND_NA_FLAG_ROUTER : 0),
                    tlladdr, sdltosa(proxydl));
                goto freeit;
        }
@@ -327,7 +327,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
 
        nd6_na_output(ifp, &saddr6, &taddr6,
            ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
-           (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
+           (i_am_router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
            tlladdr, sdltosa(proxydl));
  freeit:
        m_freem(m);
@@ -559,6 +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);
        struct ifaddr *ifa;
        struct in6_ifaddr *ifa6;
        struct llinfo_nd6 *ln;
@@ -684,7 +685,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
         * If we are a router, we may create new stale cache entries upon
         * receiving Unsolicited Neighbor Advertisements.
         */
-       if (rt == NULL && ip6_forwarding == 1) {
+       if (rt == NULL && i_am_router) {
                rt = nd6_lookup(&taddr6, 1, ifp, ifp->if_rdomain);
                if (rt == NULL || lladdr == NULL ||
                    ((sdl = satosdl(rt->rt_gateway)) == NULL))
@@ -837,7 +838,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
                }
 
                if (ln->ln_router && !is_router) {
-                       if (!ip6_forwarding) {
+                       if (!i_am_router) {
                                /*
                                 * The neighbor may be used
                                 * as a next hop for some destinations