Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Support IPv6 NAT-T. Implemented by hsuenaga@IIJ and ohis...
details: https://anonhg.NetBSD.org/src/rev/0702448b1db3
branches: trunk
changeset: 446068:0702448b1db3
user: knakahara <knakahara%NetBSD.org@localhost>
date: Thu Nov 22 04:48:34 2018 +0000
description:
Support IPv6 NAT-T. Implemented by hsuenaga@IIJ and ohishi@IIJ.
Add ATF later.
diffstat:
sys/netinet/udp_usrreq.c | 6 +-
sys/netinet6/in6_pcb.h | 4 +-
sys/netinet6/udp6_usrreq.c | 194 ++++++++++++++++++++++++++++++++++++++++++-
sys/netinet6/udp6_var.h | 4 +-
sys/netipsec/ipsec.c | 40 ++++++++-
sys/netipsec/ipsec.h | 5 +-
sys/netipsec/ipsec_output.c | 39 +++++++-
7 files changed, 270 insertions(+), 22 deletions(-)
diffs (truncated from 506 to 300 lines):
diff -r 916ee7b6b19a -r 0702448b1db3 sys/netinet/udp_usrreq.c
--- a/sys/netinet/udp_usrreq.c Wed Nov 21 22:42:26 2018 +0000
+++ b/sys/netinet/udp_usrreq.c Thu Nov 22 04:48:34 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: udp_usrreq.c,v 1.256 2018/09/14 05:09:51 maxv Exp $ */
+/* $NetBSD: udp_usrreq.c,v 1.257 2018/11/22 04:48:34 knakahara Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.256 2018/09/14 05:09:51 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.257 2018/11/22 04:48:34 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -413,7 +413,7 @@
in6_in_2_v4mapin6(&ip->ip_dst, &dst6.sin6_addr);
dst6.sin6_port = uh->uh_dport;
- n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen);
+ n += udp6_realinput(AF_INET, &src6, &dst6, &m, iphlen);
}
#endif
diff -r 916ee7b6b19a -r 0702448b1db3 sys/netinet6/in6_pcb.h
--- a/sys/netinet6/in6_pcb.h Wed Nov 21 22:42:26 2018 +0000
+++ b/sys/netinet6/in6_pcb.h Thu Nov 22 04:48:34 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in6_pcb.h,v 1.49 2017/03/02 05:26:24 ozaki-r Exp $ */
+/* $NetBSD: in6_pcb.h,v 1.50 2018/11/22 04:48:34 knakahara Exp $ */
/* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */
/*
@@ -137,6 +137,8 @@
#define IN6P_LOWPORT 0x2000000 /* user wants "low" port binding */
#define IN6P_ANONPORT 0x4000000 /* port chosen for user */
#define IN6P_FAITH 0x8000000 /* accept FAITH'ed connections */
+/* XXX should move to an UDP control block */
+#define IN6P_ESPINUDP INP_ESPINUDP /* ESP over UDP for NAT-T */
#define IN6P_RFC2292 0x40000000 /* RFC2292 */
#define IN6P_MTU 0x80000000 /* use minimum MTU */
diff -r 916ee7b6b19a -r 0702448b1db3 sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c Wed Nov 21 22:42:26 2018 +0000
+++ b/sys/netinet6/udp6_usrreq.c Thu Nov 22 04:48:34 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: udp6_usrreq.c,v 1.143 2018/11/06 04:27:41 ozaki-r Exp $ */
+/* $NetBSD: udp6_usrreq.c,v 1.144 2018/11/22 04:48:34 knakahara Exp $ */
/* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */
/* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */
@@ -63,7 +63,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.143 2018/11/06 04:27:41 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.144 2018/11/22 04:48:34 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -109,6 +109,7 @@
#ifdef IPSEC
#include <netipsec/ipsec.h>
+#include <netipsec/esp.h>
#ifdef INET6
#include <netipsec/ipsec6.h>
#endif
@@ -135,6 +136,10 @@
static void udp6_notify(struct in6pcb *, int);
static void sysctl_net_inet6_udp6_setup(struct sysctllog **);
+#ifdef IPSEC
+static int udp6_espinudp(struct mbuf **, int, struct sockaddr *,
+ struct socket *);
+#endif
#ifdef UDP_CSUM_COUNTERS
#include <sys/device.h>
@@ -298,7 +303,9 @@
{
int s;
int error = 0;
+ struct in6pcb *in6p;
int family;
+ int optval;
family = so->so_proto->pr_domain->dom_family;
@@ -324,7 +331,42 @@
error = EAFNOSUPPORT;
goto end;
}
- error = EINVAL;
+
+ switch (op) {
+ case PRCO_SETOPT:
+ in6p = sotoin6pcb(so);
+
+ switch (sopt->sopt_name) {
+ case UDP_ENCAP:
+ error = sockopt_getint(sopt, &optval);
+ if (error)
+ break;
+
+ switch(optval) {
+ case 0:
+ in6p->in6p_flags &= ~IN6P_ESPINUDP;
+ break;
+
+ case UDP_ENCAP_ESPINUDP:
+ in6p->in6p_flags |= IN6P_ESPINUDP;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ error = ENOPROTOOPT;
+ break;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
end:
splx(s);
@@ -374,7 +416,7 @@
int
udp6_realinput(int af, struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
- struct mbuf *m, int off)
+ struct mbuf **mp, int off)
{
u_int16_t sport, dport;
int rcvcnt;
@@ -382,6 +424,7 @@
const struct in_addr *dst4;
struct inpcb_hdr *inph;
struct in6pcb *in6p;
+ struct mbuf *m = *mp;
rcvcnt = 0;
off += sizeof(struct udphdr); /* now, offset of payload */
@@ -481,6 +524,32 @@
return rcvcnt;
}
+#ifdef IPSEC
+ /* Handle ESP over UDP */
+ if (in6p->in6p_flags & IN6P_ESPINUDP) {
+ struct sockaddr *sa = (struct sockaddr *)src;
+
+ switch (udp6_espinudp(mp, off, sa, in6p->in6p_socket)) {
+ case -1: /* Error, m was freed */
+ rcvcnt = -1;
+ goto bad;
+
+ case 1: /* ESP over UDP */
+ rcvcnt++;
+ goto bad;
+
+ case 0: /* plain UDP */
+ default: /* Unexpected */
+ /*
+ * Normal UDP processing will take place,
+ * m may have changed.
+ */
+ m = *mp;
+ break;
+ }
+ }
+#endif
+
udp6_sendup(m, off, sin6tosa(src), in6p->in6p_socket);
rcvcnt++;
}
@@ -624,7 +693,7 @@
dst.sin6_addr = ip6->ip6_dst;
dst.sin6_port = uh->uh_dport;
- if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) {
+ if (udp6_realinput(AF_INET6, &src, &dst, &m, off) == 0) {
if (m->m_flags & M_MCAST) {
UDP6_STATINC(UDP6_STAT_NOPORTMCAST);
goto bad;
@@ -1308,6 +1377,121 @@
UDP6_STATINC(stat);
}
+#ifdef IPSEC
+/*
+ * Returns:
+ * 1 if the packet was processed
+ * 0 if normal UDP processing should take place
+ * -1 if an error occurred and m was freed
+ */
+static int
+udp6_espinudp(struct mbuf **mp, int off, struct sockaddr *src,
+ struct socket *so)
+{
+ const size_t skip = sizeof(struct udphdr);
+ size_t len;
+ void *data;
+ size_t minlen;
+ int ip6hdrlen;
+ struct ip6_hdr *ip6;
+ struct m_tag *tag;
+ struct udphdr *udphdr;
+ u_int16_t sport, dport;
+ struct mbuf *m = *mp;
+ uint32_t *marker;
+
+ /*
+ * Collapse the mbuf chain if the first mbuf is too short
+ * The longest case is: UDP + non ESP marker + ESP
+ */
+ minlen = off + sizeof(u_int64_t) + sizeof(struct esp);
+ if (minlen > m->m_pkthdr.len)
+ minlen = m->m_pkthdr.len;
+
+ if (m->m_len < minlen) {
+ if ((*mp = m_pullup(m, minlen)) == NULL) {
+ return -1;
+ }
+ m = *mp;
+ }
+
+ len = m->m_len - off;
+ data = mtod(m, char *) + off;
+
+ /* Ignore keepalive packets */
+ if ((len == 1) && (*(unsigned char *)data == 0xff)) {
+ m_freem(m);
+ *mp = NULL; /* avoid any further processing by caller ... */
+ return 1;
+ }
+
+ /* Handle Non-ESP marker (32bit). If zero, then IKE. */
+ marker = (uint32_t *)data;
+ if (len <= sizeof(uint32_t))
+ return 0;
+ if (marker[0] == 0)
+ return 0;
+
+ /*
+ * Get the UDP ports. They are handled in network
+ * order everywhere in IPSEC_NAT_T code.
+ */
+ udphdr = (struct udphdr *)((char *)data - skip);
+ sport = udphdr->uh_sport;
+ dport = udphdr->uh_dport;
+
+ /*
+ * Remove the UDP header (and possibly the non ESP marker)
+ * IPv6 header length is ip6hdrlen
+ * Before:
+ * <---- off --->
+ * +-----+------+-----+
+ * | IP6 | UDP | ESP |
+ * +-----+------+-----+
+ * <-skip->
+ * After:
+ * +-----+-----+
+ * | IP6 | ESP |
+ * +-----+-----+
+ * <-skip->
+ */
+ ip6hdrlen = off - sizeof(struct udphdr);
+ memmove(mtod(m, char *) + skip, mtod(m, void *), ip6hdrlen);
+ m_adj(m, skip);
+
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - skip);
+ ip6->ip6_nxt = IPPROTO_ESP;
+
+ /*
+ * We have modified the packet - it is now ESP, so we should not
+ * return to UDP processing ...
+ *
+ * Add a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
+ * the source UDP port. This is required if we want
+ * to select the right SPD for multiple hosts behind
+ * same NAT
+ */
+ if ((tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
+ sizeof(sport) + sizeof(dport), M_DONTWAIT)) == NULL) {
+ m_freem(m);
+ return -1;
+ }
+ ((u_int16_t *)(tag + 1))[0] = sport;
Home |
Main Index |
Thread Index |
Old Index