Module Name: src Committed By: knakahara Date: Wed Dec 26 08:58:51 UTC 2018
Modified Files: src/sys/netipsec: ipsec_output.c ipsecif.c key.c Log Message: ipsecif(4) supports multiple peers in the same NAPT. E.g. ipsec0 connects between NetBSD_A and NetBSD_B, ipsec1 connects NetBSD_A and NetBSD_C at the following figure. +----------+ +----| NetBSD_B | +----------+ +------+ | +----------+ | NetBSD_A |--- ... ---| NAPT |---+ +----------+ +------+ | +----------+ +----| NetBSD_C | +----------+ Add ATF later. To generate a diff of this commit: cvs rdiff -u -r1.81 -r1.82 src/sys/netipsec/ipsec_output.c cvs rdiff -u -r1.12 -r1.13 src/sys/netipsec/ipsecif.c cvs rdiff -u -r1.259 -r1.260 src/sys/netipsec/key.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netipsec/ipsec_output.c diff -u src/sys/netipsec/ipsec_output.c:1.81 src/sys/netipsec/ipsec_output.c:1.82 --- src/sys/netipsec/ipsec_output.c:1.81 Thu Nov 22 04:48:34 2018 +++ src/sys/netipsec/ipsec_output.c Wed Dec 26 08:58:51 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_output.c,v 1.81 2018/11/22 04:48:34 knakahara Exp $ */ +/* $NetBSD: ipsec_output.c,v 1.82 2018/12/26 08:58:51 knakahara Exp $ */ /* * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.81 2018/11/22 04:48:34 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.82 2018/12/26 08:58:51 knakahara Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -289,6 +289,24 @@ static void ipsec_fill_saidx_bymbuf(struct secasindex *saidx, const struct mbuf *m, const int af) { + struct m_tag *mtag; + u_int16_t natt_src = IPSEC_PORT_ANY; + u_int16_t natt_dst = IPSEC_PORT_ANY; + + /* + * For NAT-T enabled ipsecif(4), set NAT-T port numbers + * even if the saidx uses transport mode. + * + * See also ipsecif[46]_output(). + */ + mtag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS); + if (mtag) { + u_int16_t *natt_ports; + + natt_ports = (u_int16_t *)(mtag + 1); + natt_src = natt_ports[1]; + natt_dst = natt_ports[0]; + } if (af == AF_INET) { struct sockaddr_in *sin; @@ -298,14 +316,14 @@ ipsec_fill_saidx_bymbuf(struct secasinde sin = &saidx->src.sin; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; + sin->sin_port = natt_src; sin->sin_addr = ip->ip_src; } if (saidx->dst.sa.sa_len == 0) { sin = &saidx->dst.sin; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; + sin->sin_port = natt_dst; sin->sin_addr = ip->ip_dst; } } else { @@ -316,7 +334,7 @@ ipsec_fill_saidx_bymbuf(struct secasinde sin6 = (struct sockaddr_in6 *)&saidx->src; sin6->sin6_len = sizeof(*sin6); sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; + sin6->sin6_port = natt_src; sin6->sin6_addr = ip6->ip6_src; if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { /* fix scope id for comparing SPD */ @@ -329,7 +347,7 @@ ipsec_fill_saidx_bymbuf(struct secasinde sin6 = (struct sockaddr_in6 *)&saidx->dst; sin6->sin6_len = sizeof(*sin6); sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; + sin6->sin6_port = natt_dst; sin6->sin6_addr = ip6->ip6_dst; if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { /* fix scope id for comparing SPD */ Index: src/sys/netipsec/ipsecif.c diff -u src/sys/netipsec/ipsecif.c:1.12 src/sys/netipsec/ipsecif.c:1.13 --- src/sys/netipsec/ipsecif.c:1.12 Fri Dec 7 09:11:04 2018 +++ src/sys/netipsec/ipsecif.c Wed Dec 26 08:58:51 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ipsecif.c,v 1.12 2018/12/07 09:11:04 knakahara Exp $ */ +/* $NetBSD: ipsecif.c,v 1.13 2018/12/26 08:58:51 knakahara Exp $ */ /* * Copyright (c) 2017 Internet Initiative Japan Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.12 2018/12/07 09:11:04 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v 1.13 2018/12/26 08:58:51 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -71,6 +71,7 @@ __KERNEL_RCSID(0, "$NetBSD: ipsecif.c,v #include <net/if_ipsec.h> +static int ipsecif_set_natt_ports(struct ipsec_variant *, struct mbuf *); static void ipsecif4_input(struct mbuf *, int, int, void *); static int ipsecif4_output(struct ipsec_variant *, int, struct mbuf *); static int ipsecif4_filter4(const struct ip *, struct ipsec_variant *, @@ -102,6 +103,32 @@ static const struct encapsw ipsecif4_enc static const struct encapsw ipsecif6_encapsw; #endif +static int +ipsecif_set_natt_ports(struct ipsec_variant *var, struct mbuf *m) +{ + + KASSERT(if_ipsec_heldref_variant(var)); + + if (var->iv_sport || var->iv_dport) { + struct m_tag *mtag; + + mtag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS, + sizeof(uint16_t) + sizeof(uint16_t), M_DONTWAIT); + if (mtag) { + uint16_t *natt_port; + + natt_port = (uint16_t *)(mtag + 1); + natt_port[0] = var->iv_dport; + natt_port[1] = var->iv_sport; + m_tag_prepend(m, mtag); + } else { + return ENOBUFS; + } + } + + return 0; +} + static struct mbuf * ipsecif4_prepend_hdr(struct ipsec_variant *var, struct mbuf *m, uint8_t proto, uint8_t tos) @@ -394,6 +421,13 @@ ipsecif4_output(struct ipsec_variant *va if (mtu > 0) return ipsecif4_fragout(var, family, m, mtu); + /* set NAT-T ports */ + error = ipsecif_set_natt_ports(var, m); + if (error) { + m_freem(m); + goto done; + } + /* IPsec output */ IP_STATINC(IP_STAT_LOCALOUT); error = ipsec4_process_packet(m, sp->req, &sa_mtu); @@ -586,6 +620,13 @@ ipsecif6_output(struct ipsec_variant *va } rtcache_unref(rt, &iro->ir_ro); + /* set NAT-T ports */ + error = ipsecif_set_natt_ports(var, m); + if (error) { + m_freem(m); + goto out; + } + /* * force fragmentation to minimum MTU, to avoid path MTU discovery. * it is too painful to ask for resend of inner packet, to achieve @@ -593,9 +634,10 @@ ipsecif6_output(struct ipsec_variant *va */ error = ip6_output(m, 0, &iro->ir_ro, ip6_ipsec_pmtu ? 0 : IPV6_MINMTU, 0, NULL, NULL); + +out: if (error) rtcache_free(&iro->ir_ro); - mutex_exit(iro->ir_lock); percpu_putref(sc->ipsec_ro_percpu); Index: src/sys/netipsec/key.c diff -u src/sys/netipsec/key.c:1.259 src/sys/netipsec/key.c:1.260 --- src/sys/netipsec/key.c:1.259 Wed Dec 26 08:55:14 2018 +++ src/sys/netipsec/key.c Wed Dec 26 08:58:51 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.259 2018/12/26 08:55:14 knakahara Exp $ */ +/* $NetBSD: key.c,v 1.260 2018/12/26 08:58:51 knakahara Exp $ */ /* $FreeBSD: key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $ */ /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.259 2018/12/26 08:55:14 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.260 2018/12/26 08:58:51 knakahara Exp $"); /* * This code is referred to RFC 2367 @@ -4567,13 +4567,13 @@ key_saidx_match( sa1dst = &saidx1->dst.sa; /* * If NAT-T is enabled, check ports for tunnel mode. - * Don't do it for transport mode, as there is no - * port information available in the SP. - * Also don't check ports if they are set to zero + * For ipsecif(4), check ports for transport mode, too. + * Don't check ports if they are set to zero * in the SPD: This means we have a non-generated * SPD which can't know UDP ports. */ - if (saidx1->mode == IPSEC_MODE_TUNNEL) + if (saidx1->mode == IPSEC_MODE_TUNNEL || + saidx1->mode == IPSEC_MODE_TRANSPORT) chkport = PORT_LOOSE; else chkport = PORT_NONE;