Implement IPv6 forwarding IPsec only.
authorbluhm <bluhm@openbsd.org>
Thu, 4 Jul 2024 12:50:08 +0000 (12:50 +0000)
committerbluhm <bluhm@openbsd.org>
Thu, 4 Jul 2024 12:50:08 +0000 (12:50 +0000)
IPsec gateways set the forwarding sysctl to 2.  While this worked
for IPv4 since a long time, adapt this feature for IPv6 now.  Set
sysctl net.inet6.ip6.forwarding=2 to forward only packets that have
been processed by IPsec.

Set IPV6_FORWARDING_IPSEC in ip6_input() and pass the flag down to
the call stack.  This provides consistent view on global variable
ip6_forwarding.  In ip6_output() or ip6_forward() drop packets that
do not match the policy.

OK denis@

sys/net/pf.c
sys/net/pf_norm.c
sys/netinet6/ip6_forward.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_mroute.c
sys/netinet6/ip6_output.c
sys/netinet6/ip6_var.h

index b967b11..f22c319 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf.c,v 1.1200 2024/07/02 18:33:47 bluhm Exp $ */
+/*     $OpenBSD: pf.c,v 1.1201 2024/07/04 12:50:08 bluhm Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -7986,14 +7986,20 @@ done:
                        break;
                case AF_INET6:
                        if (pd.dir == PF_IN) {
-                               int flags;
+                               int flags = IPV6_REDIRECT;
 
-                               if (ip6_forwarding == 0) {
+                               switch (ip6_forwarding) {
+                               case 2:
+                                       SET(flags, IPV6_FORWARDING_IPSEC);
+                                       /* FALLTHROUGH */
+                               case 1:
+                                       SET(flags, IPV6_FORWARDING);
+                                       break;
+                               default:
                                        ip6stat_inc(ip6s_cantforward);
                                        action = PF_DROP;
                                        goto out;
                                }
-                               flags = IPV6_FORWARDING | IPV6_REDIRECT;
                                ip6_forward(pd.m, NULL, flags);
                        } else
                                ip6_output(pd.m, NULL, NULL, 0, NULL, NULL);
index 8799b84..4178fe7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf_norm.c,v 1.231 2024/06/20 19:25:42 bluhm Exp $ */
+/*     $OpenBSD: pf_norm.c,v 1.232 2024/07/04 12:50:08 bluhm Exp $ */
 
 /*
  * Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -1011,7 +1011,20 @@ 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, IPV6_FORWARDING);
+                       int flags = 0;
+
+                       switch (ip6_forwarding) {
+                       case 2:
+                               SET(flags, IPV6_FORWARDING_IPSEC);
+                               /* FALLTHROUGH */
+                       case 1:
+                               SET(flags, IPV6_FORWARDING);
+                               break;
+                       default:
+                               ip6stat_inc(ip6s_cantforward);
+                               return (PF_DROP);
+                       }
+                       ip6_forward(m, NULL, flags);
                } else if ((u_long)m->m_pkthdr.len <= ifp->if_mtu) {
                        ifp->if_output(ifp, m, sin6tosa(dst), rt);
                } else {
index 9daf51f..c706c32 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_forward.c,v 1.119 2024/06/20 19:25:42 bluhm Exp $ */
+/*     $OpenBSD: ip6_forward.c,v 1.120 2024/07/04 12:50:08 bluhm Exp $ */
 /*     $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $    */
 
 /*
@@ -315,6 +315,15 @@ reroute:
        }
 #endif
 
+#ifdef IPSEC
+       if (ISSET(flags, IPV6_FORWARDING) &&
+           ISSET(flags, IPV6_FORWARDING_IPSEC) &&
+           !ISSET(m->m_pkthdr.ph_tagsset, PACKET_TAG_IPSEC_IN_DONE)) {
+               error = EHOSTUNREACH;
+               goto senderr;
+       }
+#endif
+
        error = if_output_tso(ifp, &m, dst, rt, ifp->if_mtu);
        if (error)
                ip6stat_inc(ip6s_cantforward);
index de9468e..6952cf6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.263 2024/06/20 19:25:42 bluhm Exp $   */
+/*     $OpenBSD: ip6_input.c,v 1.264 2024/07/04 12:50:08 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -416,8 +416,14 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                SET(flags, IPV6_REDIRECT);
 #endif
 
-       if (ip6_forwarding != 0)
+       switch (ip6_forwarding) {
+       case 2:
+               SET(flags, IPV6_FORWARDING_IPSEC);
+               /* FALLTHROUGH */
+       case 1:
                SET(flags, IPV6_FORWARDING);
+               break;
+       }
 
        /*
         * Without embedded scope ID we cannot find link-local
@@ -491,7 +497,7 @@ ip6_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
                         * must be discarded, else it may be accepted below.
                         */
                        KERNEL_LOCK();
-                       error = ip6_mforward(ip6, ifp, m);
+                       error = ip6_mforward(ip6, ifp, m, flags);
                        KERNEL_UNLOCK();
                        if (error) {
                                ip6stat_inc(ip6s_cantforward);
@@ -1442,7 +1448,7 @@ const struct sysctl_bounded_args ipv6ctl_vars[] = {
 #ifdef MROUTING
        { IPV6CTL_MRTPROTO, &ip6_mrtproto, SYSCTL_INT_READONLY },
 #endif
-       { IPV6CTL_FORWARDING, &ip6_forwarding, 0, 1 },
+       { IPV6CTL_FORWARDING, &ip6_forwarding, 0, 2 },
        { IPV6CTL_SENDREDIRECTS, &ip6_sendredirects, 0, 1 },
        { IPV6CTL_DEFHLIM, &ip6_defhlim, 0, 255 },
        { IPV6CTL_MAXFRAGPACKETS, &ip6_maxfragpackets, 0, 1000 },
index f2ab244..34bcb28 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_mroute.c,v 1.142 2024/06/07 08:37:59 jsg Exp $    */
+/*     $OpenBSD: ip6_mroute.c,v 1.143 2024/07/04 12:50:08 bluhm Exp $  */
 /*     $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $   */
 /*     $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $     */
 
@@ -122,8 +122,8 @@ int mcast6_debug = 1;
        do { } while (0)
 #endif
 
-int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
-void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *);
+int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *, int);
+void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *, int);
 
 /*
  * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
@@ -853,7 +853,7 @@ socket6_send(struct socket *so, struct mbuf *mm, struct sockaddr_in6 *src)
  * discard it.
  */
 int
-ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
+ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m, int flags)
 {
        struct rtentry *rt;
        struct mif6 *mifp;
@@ -902,7 +902,7 @@ ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
 
        /* Entry exists, so forward if necessary */
        if (rt) {
-               return (ip6_mdq(m, ifp, rt));
+               return (ip6_mdq(m, ifp, rt, flags));
        } else {
                /*
                 * If we don't have a route for packet's origin,
@@ -997,7 +997,7 @@ mf6c_expire_route(struct rtentry *rt, u_int rtableid)
  * Packet forwarding routine once entry in the cache is made
  */
 int
-ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
+ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int flags)
 {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6;
@@ -1085,7 +1085,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
                m6->m6_pkt_out++;
                m6->m6_bytes_out += plen;
 
-               phyint_send6(ifn, ip6, m);
+               phyint_send6(ifn, ip6, m, flags);
                if_put(ifn);
        } while ((rt = rtable_iterate(rt)) != NULL);
 
@@ -1093,7 +1093,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
 }
 
 void
-phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
+phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m, int flags)
 {
        struct mbuf *mb_copy;
        struct sockaddr_in6 *dst6, sin6;
@@ -1126,8 +1126,8 @@ phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
                /* XXX: ip6_output will override ip6->ip6_hlim */
                im6o.im6o_hlim = ip6->ip6_hlim;
                im6o.im6o_loop = 1;
-               error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
-                   NULL);
+               error = ip6_output(mb_copy, NULL, NULL, flags | IPV6_FORWARDING,
+                   &im6o, NULL);
                return;
        }
 
index c65bfd0..c5c82e5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_output.c,v 1.291 2024/04/17 20:48:51 bluhm Exp $  */
+/*     $OpenBSD: ip6_output.c,v 1.292 2024/07/04 12:50:08 bluhm Exp $  */
 /*     $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $    */
 
 /*
@@ -533,7 +533,7 @@ reroute:
                         */
                        if (ip6_mforwarding && ip6_mrouter[ifp->if_rdomain] &&
                            (flags & IPV6_FORWARDING) == 0) {
-                               if (ip6_mforward(ip6, ifp, m) != 0) {
+                               if (ip6_mforward(ip6, ifp, m, flags) != 0) {
                                        m_freem(m);
                                        goto done;
                                }
@@ -644,6 +644,15 @@ reroute:
        }
 #endif
 
+#ifdef IPSEC
+       if (ISSET(flags, IPV6_FORWARDING) &&
+           ISSET(flags, IPV6_FORWARDING_IPSEC) &&
+           !ISSET(m->m_pkthdr.ph_tagsset, PACKET_TAG_IPSEC_IN_DONE)) {
+               error = EHOSTUNREACH;
+               goto bad;
+       }
+#endif
+
        /*
         * If the packet is not going on the wire it can be destined
         * to any local address.  In this case do not clear its scopes
index 47fca70..bbe59c7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.118 2024/06/20 19:25:42 bluhm Exp $     */
+/*     $OpenBSD: ip6_var.h,v 1.119 2024/07/04 12:50:08 bluhm Exp $     */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -270,6 +270,7 @@ ip6stat_add(enum ip6stat_counters c, uint64_t v)
 #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 */
+#define IPV6_FORWARDING_IPSEC  0x10    /* only packets processed by IPsec */
 
 extern int ip6_mtudisc_timeout;                /* mtu discovery */
 extern struct rttimer_queue icmp6_mtudisc_timeout_q;
@@ -316,7 +317,7 @@ int ip6_unknown_opt(struct mbuf **, u_int8_t *, int);
 int    ip6_get_prevhdr(struct mbuf *, int);
 int    ip6_nexthdr(struct mbuf *, int, int, int *);
 int    ip6_lasthdr(struct mbuf *, int, int, int *);
-int    ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
+int    ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *, int);
 int    ip6_process_hopopts(struct mbuf **, u_int8_t *, int, u_int32_t *,
             u_int32_t *);
 void   ip6_savecontrol(struct inpcb *, struct mbuf *, struct mbuf **);