summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2021-01-11 13:28:55 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2021-01-11 13:28:55 +0000
commit937345d9a5b3170f316fbcdc3720523fda530293 (patch)
treea75fa674323487db895286a472e963e93f2f34f0 /sys
parentb9b9a3eaf0dde7447ed587b7d45552e41487ba46 (diff)
Create a path MTU host route for IPsec over IPv6. Basically the
code is copied from IPv4 and adapted. Some things are changed in v4 to make it look similar. - ip6_forward increases the noroute error counter, do that in ip_forward, too. - Pass more specific sockaddr_in6 to icmp6_mtudisc_clone(). - IPv6 may also use reject routes for IPsec PMTU clones. - To pass a route_in6 to ip6_output_ipsec_send() introduce one in ip6_forward(). That is the same what IPv4 does. Note that dst and sin6 switch roles. - Copy comments from ip_output_ipsec_send() to ip6_output_ipsec_send() to make code similar. - Implement dynamic IPv6 IPsec PMTU routes. OK tobhe@
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/icmp6.h3
-rw-r--r--sys/netinet/ip_input.c5
-rw-r--r--sys/netinet/ip_output.c4
-rw-r--r--sys/netinet6/icmp6.c16
-rw-r--r--sys/netinet6/ip6_forward.c29
-rw-r--r--sys/netinet6/ip6_output.c81
-rw-r--r--sys/netinet6/ip6_var.h5
7 files changed, 111 insertions, 32 deletions
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 468b45ca43f..ef7df8dfdde 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: icmp6.h,v 1.50 2020/10/28 17:27:35 bluhm Exp $ */
+/* $OpenBSD: icmp6.h,v 1.51 2021/01/11 13:28:53 bluhm Exp $ */
/* $KAME: icmp6.h,v 1.84 2003/04/23 10:26:51 itojun Exp $ */
/*
@@ -599,6 +599,7 @@ void icmp6_prepare(struct mbuf *);
void icmp6_redirect_input(struct mbuf *, int);
void icmp6_redirect_output(struct mbuf *, struct rtentry *);
int icmp6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+struct rtentry *icmp6_mtudisc_clone(struct sockaddr_in6 *, u_int, int);
struct ip6ctlparam;
void icmp6_mtudisc_update(struct ip6ctlparam *, int);
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 8258faf7477..3b07b80df12 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_input.c,v 1.352 2020/11/16 06:44:38 gnezdo Exp $ */
+/* $OpenBSD: ip_input.c,v 1.353 2021/01/11 13:28:53 bluhm Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
@@ -1418,8 +1418,8 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
goto freecopy;
}
+ memset(&ro, 0, sizeof(ro));
sin = satosin(&ro.ro_dst);
- memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_len = sizeof(*sin);
sin->sin_addr = ip->ip_dst;
@@ -1429,6 +1429,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
m->m_pkthdr.ph_rtableid);
if (rt == NULL) {
+ ipstat_inc(ips_noroute);
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
return;
}
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 2792b7f6f70..7492bf47fda 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.359 2021/01/07 14:51:46 claudio Exp $ */
+/* $OpenBSD: ip_output.c,v 1.360 2021/01/11 13:28:53 bluhm Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -613,7 +613,7 @@ ip_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route *ro, int fwd)
ntohl(tdb->tdb_spi), tdb->tdb_mtu, rt, rt_mtucloned));
if (rt != NULL) {
rt->rt_mtu = tdb->tdb_mtu;
- if (ro && ro->ro_rt != NULL) {
+ if (ro != NULL && ro->ro_rt != NULL) {
rtfree(ro->ro_rt);
ro->ro_rt = rtalloc(&ro->ro_dst, RT_RESOLVE,
m->m_pkthdr.ph_rtableid);
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index e27dbf9b696..378927ecfec 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: icmp6.c,v 1.233 2020/10/28 17:27:35 bluhm Exp $ */
+/* $OpenBSD: icmp6.c,v 1.234 2021/01/11 13:28:53 bluhm Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@@ -138,7 +138,6 @@ int icmp6_ratelimit(const struct in6_addr *, const int, const int);
const char *icmp6_redirect_diag(struct in6_addr *, struct in6_addr *,
struct in6_addr *);
int icmp6_notify_error(struct mbuf *, int, int, int);
-struct rtentry *icmp6_mtudisc_clone(struct sockaddr *, u_int);
void icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
void icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
@@ -1015,7 +1014,7 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
&sin6.sin6_addr);
- rt = icmp6_mtudisc_clone(sin6tosa(&sin6), m->m_pkthdr.ph_rtableid);
+ rt = icmp6_mtudisc_clone(&sin6, m->m_pkthdr.ph_rtableid, 0);
if (rt != NULL && ISSET(rt->rt_flags, RTF_HOST) &&
!(rt->rt_locks & RTV_MTU) &&
@@ -1784,15 +1783,18 @@ icmp6_ratelimit(const struct in6_addr *dst, const int type, const int code)
}
struct rtentry *
-icmp6_mtudisc_clone(struct sockaddr *dst, u_int rtableid)
+icmp6_mtudisc_clone(struct sockaddr_in6 *dst, u_int rtableid, int ipsec)
{
struct rtentry *rt;
int error;
- rt = rtalloc(dst, RT_RESOLVE, rtableid);
+ rt = rtalloc(sin6tosa(dst), RT_RESOLVE, rtableid);
/* Check if the route is actually usable */
- if (!rtisvalid(rt) || (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
+ if (!rtisvalid(rt))
+ goto bad;
+ /* IPsec needs the route only for PMTU, it can use reject for that */
+ if (!ipsec && (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
goto bad;
/*
@@ -1812,7 +1814,7 @@ icmp6_mtudisc_clone(struct sockaddr *dst, u_int rtableid)
memset(&info, 0, sizeof(info));
info.rti_ifa = rt->rt_ifa;
info.rti_flags = RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC;
- info.rti_info[RTAX_DST] = dst;
+ info.rti_info[RTAX_DST] = sin6tosa(dst);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
info.rti_info[RTAX_LABEL] =
rtlabel_id2sa(rt->rt_labelid, &sa_rl);
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 65fcb55b2a0..85994f30732 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_forward.c,v 1.99 2020/11/26 18:55:12 tb Exp $ */
+/* $OpenBSD: ip6_forward.c,v 1.100 2021/01/11 13:28:54 bluhm Exp $ */
/* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */
/*
@@ -85,7 +85,8 @@ void
ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt)
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct sockaddr_in6 *dst, sin6;
+ struct sockaddr_in6 *sin6;
+ struct route_in6 ro;
struct ifnet *ifp = NULL;
int error = 0, type = 0, code = 0;
struct mbuf *mcopy = NULL;
@@ -160,15 +161,15 @@ reroute:
}
#endif /* IPSEC */
- dst = &sin6;
- memset(dst, 0, sizeof(*dst));
- dst->sin6_len = sizeof(struct sockaddr_in6);
- dst->sin6_family = AF_INET6;
- dst->sin6_addr = ip6->ip6_dst;
+ memset(&ro, 0, sizeof(ro));
+ sin6 = &ro.ro_dst;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_addr = ip6->ip6_dst;
if (!rtisvalid(rt)) {
rtfree(rt);
- rt = rtalloc_mpath(sin6tosa(dst), &ip6->ip6_src.s6_addr32[0],
+ rt = rtalloc_mpath(sin6tosa(sin6), &ip6->ip6_src.s6_addr32[0],
m->m_pkthdr.ph_rtableid);
if (rt == NULL) {
ip6stat_inc(ip6s_noroute);
@@ -215,12 +216,12 @@ reroute:
/*
* Check if the packet needs encapsulation.
* ipsp_process_packet will never come back to here.
- * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
- * PMTU notification. is it okay?
*/
if (tdb != NULL) {
/* Callee frees mbuf */
- error = ip6_output_ipsec_send(tdb, m, 0, 1);
+ ro.ro_rt = rt;
+ ro.ro_tableid = m->m_pkthdr.ph_rtableid;
+ error = ip6_output_ipsec_send(tdb, m, &ro, 0, 1);
if (error)
goto senderr;
goto freecopy;
@@ -228,7 +229,7 @@ reroute:
#endif /* IPSEC */
if (rt->rt_flags & RTF_GATEWAY)
- dst = satosin6(rt->rt_gateway);
+ sin6 = satosin6(rt->rt_gateway);
/*
* If we are to forward the packet using the same interface
@@ -248,7 +249,7 @@ reroute:
ip6_sendredirects &&
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
if ((ifp->if_flags & IFF_POINTOPOINT) &&
- nd6_is_addr_neighbor(&sin6, ifp)) {
+ nd6_is_addr_neighbor(&ro.ro_dst, ifp)) {
/*
* If the incoming interface is equal to the outgoing
* one, the link attached to the interface is
@@ -320,7 +321,7 @@ reroute:
goto out;
}
- error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
+ error = ifp->if_output(ifp, m, sin6tosa(sin6), rt);
if (error) {
ip6stat_inc(ip6s_cantforward);
} else {
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index c7eac1ebd0a..d85f100903a 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.248 2020/12/22 13:37:48 bluhm Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.249 2021/01/11 13:28:54 bluhm Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -106,6 +106,12 @@
#include <netinet/ip_ipsp.h>
#include <netinet/ip_ah.h>
#include <netinet/ip_esp.h>
+
+#ifdef ENCDEBUG
+#define DPRINTF(x) do { if (encdebug) printf x ; } while (0)
+#else
+#define DPRINTF(x)
+#endif
#endif /* IPSEC */
struct ip6_exthdrs {
@@ -426,7 +432,7 @@ reroute:
* packet just because ip6_dst is different from what tdb has.
* XXX
*/
- error = ip6_output_ipsec_send(tdb, m,
+ error = ip6_output_ipsec_send(tdb, m, ro,
exthdrs.ip6e_rthdr ? 1 : 0, 0);
goto done;
}
@@ -2762,14 +2768,19 @@ ip6_output_ipsec_lookup(struct mbuf *m, int *error, struct inpcb *inp)
}
int
-ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, int tunalready, int fwd)
+ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
+ int tunalready, int fwd)
{
#if NPF > 0
struct ifnet *encif;
#endif
+ struct ip6_hdr *ip6;
int error;
#if NPF > 0
+ /*
+ * Packet filter
+ */
if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) == NULL ||
pf_test(AF_INET6, fwd ? PF_FWD : PF_OUT, encif, &m) != PF_PASS) {
m_freem(m);
@@ -2786,7 +2797,69 @@ ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, int tunalready, int fwd)
*/
in6_proto_cksum_out(m, encif);
#endif
- m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
+
+ /* Check if we are allowed to fragment */
+ ip6 = mtod(m, struct ip6_hdr *);
+ if (ip_mtudisc && tdb->tdb_mtu &&
+ sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) > tdb->tdb_mtu &&
+ tdb->tdb_mtutimeout > gettime()) {
+ struct rtentry *rt = NULL;
+ int rt_mtucloned = 0;
+ int transportmode = 0;
+
+ transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET6) &&
+ (IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
+ &ip6->ip6_dst));
+
+ /* Find a host route to store the mtu in */
+ if (ro != NULL)
+ rt = ro->ro_rt;
+ /* but don't add a PMTU route for transport mode SAs */
+ if (transportmode)
+ rt = NULL;
+ else if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0) {
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_addr = ip6->ip6_dst;
+ sin6.sin6_scope_id =
+ in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
+ &ip6->ip6_dst);
+ error = in6_embedscope(&ip6->ip6_dst, &sin6, NULL);
+ if (error) {
+ /* should be impossible */
+ ipsecstat_inc(ipsec_odrops);
+ m_freem(m);
+ return error;
+ }
+ rt = icmp6_mtudisc_clone(&sin6,
+ m->m_pkthdr.ph_rtableid, 1);
+ rt_mtucloned = 1;
+ }
+ DPRINTF(("%s: spi %08x mtu %d rt %p cloned %d\n", __func__,
+ ntohl(tdb->tdb_spi), tdb->tdb_mtu, rt, rt_mtucloned));
+ if (rt != NULL) {
+ rt->rt_mtu = tdb->tdb_mtu;
+ if (ro != NULL && ro->ro_rt != NULL) {
+ rtfree(ro->ro_rt);
+ ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
+ RT_RESOLVE, m->m_pkthdr.ph_rtableid);
+ }
+ if (rt_mtucloned)
+ rtfree(rt);
+ }
+ ipsec_adjust_mtu(m, tdb->tdb_mtu);
+ m_freem(m);
+ return EMSGSIZE;
+ }
+
+ /*
+ * Clear these -- they'll be set in the recursive invocation
+ * as needed.
+ */
+ m->m_flags &= ~(M_BCAST | M_MCAST);
/* Callee frees mbuf */
error = ipsp_process_packet(m, tdb, AF_INET6, tunalready);
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 3d766f6aeda..640d89e5f6a 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_var.h,v 1.86 2019/12/08 11:08:22 sashan Exp $ */
+/* $OpenBSD: ip6_var.h,v 1.87 2021/01/11 13:28:54 bluhm Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@@ -368,7 +368,8 @@ u_int32_t ip6_randomflowlabel(void);
struct tdb;
struct tdb *
ip6_output_ipsec_lookup(struct mbuf *, int *, struct inpcb *);
-int ip6_output_ipsec_send(struct tdb *, struct mbuf *, int, int);
+int ip6_output_ipsec_send(struct tdb *, struct mbuf *, struct route_in6 *,
+ int, int);
#endif /* IPSEC */
#endif /* _KERNEL */