From: bluhm Date: Thu, 4 Jul 2024 12:50:08 +0000 (+0000) Subject: Implement IPv6 forwarding IPsec only. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=28c60e6351dc1963204b5f2f10d2b35624544ca4;p=openbsd Implement IPv6 forwarding IPsec only. 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@ --- diff --git a/sys/net/pf.c b/sys/net/pf.c index b967b11aa48..f22c31900be 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -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); diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 8799b845e9b..4178fe785a1 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -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 @@ -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 { diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 9daf51f92b6..c706c32c53c 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -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); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index de9468ecc3f..6952cf632f9 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -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 }, diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index f2ab244ff7b..34bcb28ce6a 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -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; } diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index c65bfd0b9f4..c5c82e5fe12 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -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 diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 47fca707dda..bbe59c744ac 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -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 **);