Subject: IPSEC_NAT_T for FAST_IPSEC
To: None <tech-net@NetBSD.org>
From: None <degroote@netbsd.org>
List: tech-net
Date: 06/19/2007 23:46:21
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Hi
I have finished to add support of IPSEC_NAT_T for FAST_IPSEC. Tke key
management part is more or less directly taken from manu@ work so most of
congrats is for him :D
Can you review the following patch and if possible test it on a real
configuration (I have done some tests but only on virtual networks).
If nobody object, I will commit it next week.
--
Arnaud Degroote
degroote@netbsd.org
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="ipsec_nat_t.diff"
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.159
diff -u -r1.159 udp_usrreq.c
--- netinet/udp_usrreq.c 12 May 2007 02:03:15 -0000 1.159
+++ netinet/udp_usrreq.c 19 Jun 2007 20:59:56 -0000
@@ -1528,7 +1528,7 @@
m_tag_prepend(n, tag);
#ifdef FAST_IPSEC
- ipsec4_common_input(n, iphdrlen);
+ ipsec4_common_input(n, iphdrlen, IPPROTO_ESP);
#else
esp4_input(n, iphdrlen);
#endif
Index: netipsec/ipsec_input.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_input.c,v
retrieving revision 1.16
diff -u -r1.16 ipsec_input.c
--- netipsec/ipsec_input.c 4 Mar 2007 21:17:54 -0000 1.16
+++ netipsec/ipsec_input.c 19 Jun 2007 20:59:58 -0000
@@ -116,7 +116,12 @@
union sockaddr_union dst_address;
struct secasvar *sav;
u_int32_t spi;
+ u_int16_t sport = 0;
+ u_int16_t dport = 0;
int s, error;
+#ifdef IPSEC_NAT_T
+ struct m_tag * tag = NULL;
+#endif
IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
ipcompstat.ipcomps_input);
@@ -149,7 +154,19 @@
u_int16_t cpi;
m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), &cpi);
spi = ntohl(htons(cpi));
+ } else {
+ panic("ipsec_common_input called with bad protocol number :"
+ "%d\n", sproto);
}
+
+
+#ifdef IPSEC_NAT_T
+ /* find the source port for NAT-T */
+ if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+ sport = ((u_int16_t *)(tag + 1))[0];
+ dport = ((u_int16_t *)(tag + 1))[1];
+ }
+#endif
/*
* Find the SA and (indirectly) call the appropriate
@@ -187,12 +204,12 @@
s = splsoftnet();
/* NB: only pass dst since key_allocsa follows RFC2401 */
- sav = KEY_ALLOCSA(&dst_address, sproto, spi);
+ sav = KEY_ALLOCSA(&dst_address, sproto, spi, sport, dport);
if (sav == NULL) {
DPRINTF(("ipsec_common_input: no key association found for"
- " SA %s/%08lx/%u\n",
+ " SA %s/%08lx/%u/%u\n",
ipsec_address(&dst_address),
- (u_long) ntohl(spi), sproto));
+ (u_long) ntohl(spi), sproto, ntohs(dport)));
IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
ipcompstat.ipcomps_notdb);
splx(s);
Index: netipsec/ipsec_netbsd.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_netbsd.c,v
retrieving revision 1.26
diff -u -r1.26 ipsec_netbsd.c
--- netipsec/ipsec_netbsd.c 11 Apr 2007 22:21:41 -0000 1.26
+++ netipsec/ipsec_netbsd.c 19 Jun 2007 20:59:58 -0000
@@ -112,7 +112,7 @@
*/
ah = (struct ah *)((char *)ip + (ip->ip_hl << 2));
sav = KEY_ALLOCSA((const union sockaddr_union *)sa,
- IPPROTO_AH, ah->ah_spi);
+ IPPROTO_AH, ah->ah_spi, 0, 0);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
@@ -163,7 +163,7 @@
*/
esp = (struct esp *)((char *)ip + (ip->ip_hl << 2));
sav = KEY_ALLOCSA((const union sockaddr_union *)sa,
- IPPROTO_ESP, esp->esp_spi);
+ IPPROTO_ESP, esp->esp_spi, 0, 0);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
@@ -249,7 +249,7 @@
* to the address in the ICMP message payload.
*/
sav = KEY_ALLOCSA((const union sockaddr_union*)sa,
- IPPROTO_AH, ahp->ah_spi);
+ IPPROTO_AH, ahp->ah_spi, 0, 0);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
@@ -357,7 +357,7 @@
*/
sav = KEY_ALLOCSA((const union sockaddr_union*)sa,
- IPPROTO_ESP, espp->esp_spi);
+ IPPROTO_ESP, espp->esp_spi, 0, 0);
if (sav) {
if (sav->state == SADB_SASTATE_MATURE ||
Index: netipsec/ipsec_output.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_output.c,v
retrieving revision 1.21
diff -u -r1.21 ipsec_output.c
--- netipsec/ipsec_output.c 10 Feb 2007 09:43:05 -0000 1.21
+++ netipsec/ipsec_output.c 19 Jun 2007 20:59:59 -0000
@@ -72,6 +72,9 @@
#ifdef INET6
#include <netinet/icmp6.h>
#endif
+#ifdef IPSEC_NAT_T
+#include <netinet/udp.h>
+#endif
#include <netipsec/ipsec.h>
#include <netipsec/ipsec_var.h>
@@ -99,6 +102,18 @@
struct secasvar *sav;
struct secasindex *saidx;
int error;
+#ifdef INET
+ struct ip * ip;
+#endif /* INET */
+#ifdef INET6
+ struct ip6_hdr * ip6;
+#endif /* INET6 */
+#ifdef IPSEC_NAT_T
+ struct mbuf * mo;
+ struct udphdr *udp = NULL;
+ uint64_t * data = NULL;
+ int hlen, roff;
+#endif /* IPSEC_NAT_T */
IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
@@ -109,11 +124,57 @@
IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
saidx = &sav->sah->saidx;
+
+#ifdef IPSEC_NAT_T
+ if(sav->natt_type != 0) {
+ ip = mtod(m, struct ip *);
+
+ hlen = sizeof(struct udphdr);
+ if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+ hlen += sizeof(uint64_t);
+
+ mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
+ if (mo == NULL) {
+ DPRINTF(("ipsec_process_done : failed to inject"
+ "%u byte UDP for SA %s/%08lx\n",
+ hlen, ipsec_address(&saidx->dst),
+ (u_long) ntohl(sav->spi)));
+ error = ENOBUFS;
+ goto bad;
+ }
+
+ udp = (struct udphdr*) (mtod(mo, char*) + roff);
+ data = (uint64_t*) (udp + 1);
+
+ if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+ *data = 0; /* NON-IKE Marker */
+
+ if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
+ udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
+ else
+ udp->uh_sport = key_portfromsaddr(&saidx->src);
+
+ udp->uh_dport = key_portfromsaddr(&saidx->dst);
+ udp->uh_sum = 0;
+#ifdef _IP_VHL
+ udp->uh_ulen = htons(m->m_pkthdr.len -
+ (IP_VHL_HL(ip->ip_vhl) << 2));
+#else
+ udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
+#endif
+ }
+#endif /* IPSEC_NAT_T */
+
switch (saidx->dst.sa.sa_family) {
#ifdef INET
case AF_INET:
/* Fix the header length, for AH processing. */
- mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+#ifdef IPSEC_NAT_T
+ if (sav->natt_type != 0)
+ ip->ip_p = IPPROTO_UDP;
+#endif /* IPSEC_NAT_T */
break;
#endif /* INET */
#ifdef INET6
@@ -128,8 +189,12 @@
error = ENXIO; /*?*/
goto bad;
}
- mtod(m, struct ip6_hdr *)->ip6_plen =
- htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
+#ifdef IPSEC_NAT_T
+ if (sav->natt_type != 0)
+ ip6->ip6_nxt = IPPROTO_UDP;
+#endif /* IPSEC_NAT_T */
break;
#endif /* INET6 */
default:
@@ -190,7 +255,6 @@
*/
switch (saidx->dst.sa.sa_family) {
#ifdef INET
- struct ip *ip;
case AF_INET:
ip = mtod(m, struct ip *);
#ifdef __FreeBSD__
Index: netipsec/key.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/key.c,v
retrieving revision 1.47
diff -u -r1.47 key.c
--- netipsec/key.c 8 May 2007 14:03:05 -0000 1.47
+++ netipsec/key.c 19 Jun 2007 21:00:01 -0000
@@ -1,7 +1,7 @@
/* $NetBSD: key.c,v 1.47 2007/05/08 14:03:05 degroote Exp $ */
/* $FreeBSD: src/sys/netipsec/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 $ */
-
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -353,16 +353,10 @@
* set parameters into secasindex buffer.
* Must allocate secasindex buffer before calling this function.
*/
-#define KEY_SETSECASIDX(p, m, r, s, d, idx) \
-do { \
- bzero((idx), sizeof(struct secasindex)); \
- (idx)->proto = (p); \
- (idx)->mode = (m); \
- (idx)->reqid = (r); \
- bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len); \
- bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len); \
-} while (0)
-
+static int
+key_setsecasidx __P((int, int, int, const struct sadb_address *,
+ const struct sadb_address *, struct secasindex *));
+
/* key statistics */
struct _keystat {
u_long getspi_count; /* the avarage of count to try to get new SPI */
@@ -399,6 +393,10 @@
const struct sadb_msghdr *));
static struct mbuf * key_setspddump __P((int *errorp, pid_t));
static struct mbuf * key_setspddump_chain __P((int *errorp, int *lenp, pid_t pid));
+#ifdef IPSEC_NAT_T
+static int key_nat_map __P((struct socket *, struct mbuf *,
+ const struct sadb_msghdr *));
+#endif
static struct mbuf *key_setdumpsp __P((struct secpolicy *,
u_int8_t, u_int32_t, pid_t));
static u_int key_getspreqmsglen __P((struct secpolicy *));
@@ -419,6 +417,12 @@
static int key_mature __P((struct secasvar *));
static struct mbuf *key_setdumpsa __P((struct secasvar *, u_int8_t,
u_int8_t, u_int32_t, u_int32_t));
+#ifdef IPSEC_NAT_T
+static struct mbuf *key_setsadbxport __P((u_int16_t, u_int16_t));
+static struct mbuf *key_setsadbxtype __P((u_int16_t));
+#endif
+static void key_porttosaddr __P((union sockaddr_union *, u_int16_t));
+static int key_checksalen __P((const union sockaddr_union *));
static struct mbuf *key_setsadbmsg __P((u_int8_t, u_int16_t, u_int8_t,
u_int32_t, pid_t, u_int16_t));
static struct mbuf *key_setsadbsa __P((struct secasvar *));
@@ -454,6 +458,10 @@
const struct sadb_msghdr *));
static u_int32_t key_do_getnewspi __P((struct sadb_spirange *,
struct secasindex *));
+#ifdef IPSEC_NAT_T
+static int key_handle_natt_info __P((struct secasvar *,
+ const struct sadb_msghdr *));
+#endif
static int key_update __P((struct socket *, struct mbuf *,
const struct sadb_msghdr *));
#ifdef IPSEC_DOSEQCHECK
@@ -1037,24 +1045,34 @@
* Note that, however, we do need to keep source address in IPsec SA.
* IKE specification and PF_KEY specification do assume that we
* keep source address in IPsec SA. We see a tricky situation here.
+ *
+ * sport and dport are used for NAT-T. network order is always used.
*/
struct secasvar *
key_allocsa(
const union sockaddr_union *dst,
u_int proto,
u_int32_t spi,
+ u_int16_t sport,
+ u_int16_t dport,
const char* where, int tag)
{
struct secashead *sah;
struct secasvar *sav;
u_int stateidx, state;
int s;
+ int chkport = 0;
int must_check_spi = 1;
int must_check_alg = 0;
u_int16_t cpi = 0;
u_int8_t algo = 0;
+#ifdef IPSEC_NAT_T
+ if ((sport != 0) && (dport != 0))
+ chkport = 1;
+#endif
+
IPSEC_ASSERT(dst != NULL, ("key_allocsa: null dst address"));
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -1108,12 +1126,16 @@
continue;
#if 0 /* don't check src */
+ /* Fix port in src->sa */
+
/* check src address */
if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, 0) != 0)
continue;
#endif
+ /* fix port of dst address XXX*/
+ key_porttosaddr(__UNCONST(dst), dport);
/* check dst address */
- if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, 0) != 0)
+ if (key_sockaddrcmp(&dst->sa, &sav->sah->saidx.dst.sa, chkport) != 0)
continue;
SA_ADDREF(sav);
goto done;
@@ -2546,6 +2568,68 @@
return error;
}
+#ifdef IPSEC_NAT_T
+/*
+ * SADB_X_NAT_T_NEW_MAPPING. Unused by racoon as of 2005/04/23
+ */
+static int
+key_nat_map(so, m, mhp)
+ struct socket *so;
+ struct mbuf *m;
+ const struct sadb_msghdr *mhp;
+{
+ struct sadb_x_nat_t_type *type;
+ struct sadb_x_nat_t_port *sport;
+ struct sadb_x_nat_t_port *dport;
+ struct sadb_address *addr;
+ struct sadb_x_nat_t_frag *frag;
+
+ /* sanity check */
+ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+ panic("key_nat_map: NULL pointer is passed.");
+
+ if (mhp->ext[SADB_X_EXT_NAT_T_TYPE] == NULL ||
+ mhp->ext[SADB_X_EXT_NAT_T_SPORT] == NULL ||
+ mhp->ext[SADB_X_EXT_NAT_T_DPORT] == NULL) {
+ ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+ return key_senderror(so, m, EINVAL);
+ }
+ if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+ (mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+ (mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+ ipseclog((LOG_DEBUG, "key_nat_map: invalid message.\n"));
+ return key_senderror(so, m, EINVAL);
+ }
+
+ if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) &&
+ (mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+ ipseclog((LOG_DEBUG, "key_nat_map: invalid message\n"));
+ return key_senderror(so, m, EINVAL);
+ }
+
+ if ((mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL) &&
+ (mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag))) {
+ ipseclog((LOG_DEBUG, "key_nat_map: invalid message\n"));
+ return key_senderror(so, m, EINVAL);
+ }
+
+ type = (struct sadb_x_nat_t_type *)mhp->ext[SADB_X_EXT_NAT_T_TYPE];
+ sport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_SPORT];
+ dport = (struct sadb_x_nat_t_port *)mhp->ext[SADB_X_EXT_NAT_T_DPORT];
+ addr = (struct sadb_address *)mhp->ext[SADB_X_EXT_NAT_T_OA];
+ frag = (struct sadb_x_nat_t_frag *) mhp->ext[SADB_X_EXT_NAT_T_FRAG];
+
+ printf("sadb_nat_map called\n");
+
+ /*
+ * XXX handle that, it should also contain a SA, or anything
+ * that enable to update the SA information.
+ */
+
+ return 0;
+}
+#endif /* IPSEC_NAT_T */
+
static struct mbuf *
key_setdumpsp(sp, type, seq, pid)
struct secpolicy *sp;
@@ -3128,6 +3212,10 @@
sav->tdb_encalgxform = NULL; /* encoding algorithm */
sav->tdb_authalgxform = NULL; /* authentication algorithm */
sav->tdb_compalgxform = NULL; /* compression algorithm */
+#ifdef IPSEC_NAT_T
+ sav->natt_type = 0;
+ sav->esp_frag = 0;
+#endif
/* SA */
if (mhp->ext[SADB_EXT_SA] != NULL) {
@@ -3463,6 +3551,12 @@
SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH,
SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC,
SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY,
+#ifdef IPSEC_NAT_T
+ SADB_X_EXT_NAT_T_TYPE, SADB_X_EXT_NAT_T_SPORT,
+ SADB_X_EXT_NAT_T_DPORT, SADB_X_EXT_NAT_T_OA,
+ SADB_X_EXT_NAT_T_FRAG,
+#endif
+
};
m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt);
@@ -3539,6 +3633,31 @@
p = sav->lft_s;
break;
+#ifdef IPSEC_NAT_T
+ case SADB_X_EXT_NAT_T_TYPE:
+ if ((m = key_setsadbxtype(sav->natt_type)) == NULL)
+ goto fail;
+ break;
+
+ case SADB_X_EXT_NAT_T_DPORT:
+ if ((m = key_setsadbxport(
+ key_portfromsaddr(&sav->sah->saidx.dst),
+ SADB_X_EXT_NAT_T_DPORT)) == NULL)
+ goto fail;
+ break;
+
+ case SADB_X_EXT_NAT_T_SPORT:
+ if ((m = key_setsadbxport(
+ key_portfromsaddr(&sav->sah->saidx.src),
+ SADB_X_EXT_NAT_T_SPORT)) == NULL)
+ goto fail;
+ break;
+
+ case SADB_X_EXT_NAT_T_OA:
+ case SADB_X_EXT_NAT_T_FRAG:
+ continue;
+#endif
+
case SADB_EXT_ADDRESS_PROXY:
case SADB_EXT_IDENTITY_SRC:
case SADB_EXT_IDENTITY_DST:
@@ -3592,6 +3711,155 @@
return NULL;
}
+
+#ifdef IPSEC_NAT_T
+/*
+ * set a type in sadb_x_nat_t_type
+ */
+static struct mbuf *
+key_setsadbxtype(type)
+ u_int16_t type;
+{
+ struct mbuf *m;
+ size_t len;
+ struct sadb_x_nat_t_type *p;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_type));
+
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_x_nat_t_type *);
+
+ bzero(p, len);
+ p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
+ p->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ p->sadb_x_nat_t_type_type = type;
+
+ return m;
+}
+/*
+ * set a port in sadb_x_nat_t_port. port is in network order
+ */
+static struct mbuf *
+key_setsadbxport(port, type)
+ u_int16_t port;
+ u_int16_t type;
+{
+ struct mbuf *m;
+ size_t len;
+ struct sadb_x_nat_t_port *p;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_x_nat_t_port));
+
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_x_nat_t_port *);
+
+ bzero(p, len);
+ p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
+ p->sadb_x_nat_t_port_exttype = type;
+ p->sadb_x_nat_t_port_port = port;
+
+ return m;
+}
+
+/*
+ * Get port from sockaddr, port is in network order
+ */
+u_int16_t
+key_portfromsaddr(saddr)
+ const union sockaddr_union *saddr;
+{
+ u_int16_t port;
+
+ switch (saddr->sa.sa_family) {
+ case AF_INET: {
+ port = saddr->sin.sin_port;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6: {
+ port = saddr->sin6.sin6_port;
+ break;
+ }
+#endif
+ default:
+ printf("key_portfromsaddr: unexpected address family\n");
+ port = 0;
+ break;
+ }
+
+ return port;
+}
+
+#endif /* IPSEC_NAT_T */
+
+/*
+ * Set port is struct sockaddr. port is in network order
+ */
+static void
+key_porttosaddr(saddr, port)
+ union sockaddr_union *saddr;
+ u_int16_t port;
+{
+ switch (saddr->sa.sa_family) {
+ case AF_INET: {
+ saddr->sin.sin_port = port;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6: {
+ saddr->sin6.sin6_port = port;
+ break;
+ }
+#endif
+ default:
+ printf("key_porttosaddr: unexpected address family %d\n",
+ saddr->sa.sa_family);
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Safety check sa_len
+ */
+static int
+key_checksalen(saddr)
+ const union sockaddr_union *saddr;
+{
+ switch (saddr->sa.sa_family) {
+ case AF_INET:
+ if (saddr->sa.sa_len != sizeof(struct sockaddr_in))
+ return -1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (saddr->sa.sa_len != sizeof(struct sockaddr_in6))
+ return -1;
+ break;
+#endif
+ default:
+ printf("key_checksalen: unexpected sa_family %d\n",
+ saddr->sa.sa_family);
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+
/*
* set data into sadb_msg.
*/
@@ -3961,6 +4229,8 @@
const struct secasindex *saidx1,
int flag)
{
+ int chkport = 0;
+
/* sanity */
if (saidx0 == NULL && saidx1 == NULL)
return 1;
@@ -3998,10 +4268,20 @@
return 0;
}
- if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, 0) != 0) {
+ /*
+ * 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.
+ */
+#ifdef IPSEC_NAT_T
+ if (saidx1->mode == IPSEC_MODE_TUNNEL)
+ chkport = 1;
+#endif
+
+ if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, chkport) != 0) {
return 0;
}
- if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, 0) != 0) {
+ if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, chkport) != 0) {
return 0;
}
}
@@ -4597,6 +4877,40 @@
/* NOTREACHED */
}
+static int
+key_setsecasidx(proto, mode, reqid, src, dst, saidx)
+ int proto;
+ int mode;
+ int reqid;
+ const struct sadb_address * src;
+ const struct sadb_address * dst;
+ struct secasindex * saidx;
+{
+ const union sockaddr_union * src_u =
+ (const union sockaddr_union *) src;
+ const union sockaddr_union * dst_u =
+ (const union sockaddr_union *) dst;
+
+ /* sa len safety check */
+ if (key_checksalen(src_u) != 0)
+ return -1;
+ if (key_checksalen(dst_u) != 0)
+ return -1;
+
+ memset(saidx, 0, sizeof(*saidx));
+ saidx->proto = proto;
+ saidx->mode = mode;
+ saidx->reqid = reqid;
+ memcpy(&saidx->src, src_u, src_u->sa.sa_len);
+ memcpy(&saidx->dst, dst_u, dst_u->sa.sa_len);
+
+#ifndef IPSEC_NAT_T
+ key_porttosaddr(&((saidx)->src),0); \
+ key_porttosaddr(&((saidx)->dst),0);
+#endif
+ return 0;
+}
+
/* %%% PF_KEY */
/*
* SADB_GETSPI processing is to receive
@@ -4657,42 +4971,10 @@
return key_senderror(so, m, EINVAL);
}
- /* make sure if port number is zero. */
- switch (((struct sockaddr *)(src0 + 1))->sa_family) {
- case AF_INET:
- if (((struct sockaddr *)(src0 + 1))->sa_len !=
- sizeof(struct sockaddr_in))
- return key_senderror(so, m, EINVAL);
- ((struct sockaddr_in *)(src0 + 1))->sin_port = 0;
- break;
- case AF_INET6:
- if (((struct sockaddr *)(src0 + 1))->sa_len !=
- sizeof(struct sockaddr_in6))
- return key_senderror(so, m, EINVAL);
- ((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0;
- break;
- default:
- ; /*???*/
- }
- switch (((struct sockaddr *)(dst0 + 1))->sa_family) {
- case AF_INET:
- if (((struct sockaddr *)(dst0 + 1))->sa_len !=
- sizeof(struct sockaddr_in))
- return key_senderror(so, m, EINVAL);
- ((struct sockaddr_in *)(dst0 + 1))->sin_port = 0;
- break;
- case AF_INET6:
- if (((struct sockaddr *)(dst0 + 1))->sa_len !=
- sizeof(struct sockaddr_in6))
- return key_senderror(so, m, EINVAL);
- ((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0;
- break;
- default:
- ; /*???*/
- }
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
/* SPI allocation */
spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE],
@@ -4872,6 +5154,76 @@
return newspi;
}
+#ifdef IPSEC_NAT_T
+/* Handle IPSEC_NAT_T info if present */
+static int
+key_handle_natt_info(sav,mhp)
+ struct secasvar *sav;
+ const struct sadb_msghdr *mhp;
+{
+
+ if (mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL)
+ printf("update: NAT-T OA present\n");
+
+ if ((mhp->ext[SADB_X_EXT_NAT_T_TYPE] != NULL) &&
+ (mhp->ext[SADB_X_EXT_NAT_T_SPORT] != NULL) &&
+ (mhp->ext[SADB_X_EXT_NAT_T_DPORT] != NULL)) {
+ struct sadb_x_nat_t_type *type;
+ struct sadb_x_nat_t_port *sport;
+ struct sadb_x_nat_t_port *dport;
+ struct sadb_address *addr;
+ struct sadb_x_nat_t_frag *frag;
+
+ if ((mhp->extlen[SADB_X_EXT_NAT_T_TYPE] < sizeof(*type)) ||
+ (mhp->extlen[SADB_X_EXT_NAT_T_SPORT] < sizeof(*sport)) ||
+ (mhp->extlen[SADB_X_EXT_NAT_T_DPORT] < sizeof(*dport))) {
+ ipseclog((LOG_DEBUG, "key_update: "
+ "invalid message.\n"));
+ return -1;
+ }
+
+ if ((mhp->ext[SADB_X_EXT_NAT_T_OA] != NULL) &&
+ (mhp->extlen[SADB_X_EXT_NAT_T_OA] < sizeof(*addr))) {
+ ipseclog((LOG_DEBUG, "key_update: invalid message\n"));
+ return -1;
+ }
+
+ if ((mhp->ext[SADB_X_EXT_NAT_T_FRAG] != NULL) &&
+ (mhp->extlen[SADB_X_EXT_NAT_T_FRAG] < sizeof(*frag))) {
+ ipseclog((LOG_DEBUG, "key_update: invalid message\n"));
+ return -1;
+ }
+
+ type = (struct sadb_x_nat_t_type *)
+ mhp->ext[SADB_X_EXT_NAT_T_TYPE];
+ sport = (struct sadb_x_nat_t_port *)
+ mhp->ext[SADB_X_EXT_NAT_T_SPORT];
+ dport = (struct sadb_x_nat_t_port *)
+ mhp->ext[SADB_X_EXT_NAT_T_DPORT];
+ addr = (struct sadb_address *)
+ mhp->ext[SADB_X_EXT_NAT_T_OA];
+ frag = (struct sadb_x_nat_t_frag *)
+ mhp->ext[SADB_X_EXT_NAT_T_FRAG];
+
+ if (type)
+ sav->natt_type = type->sadb_x_nat_t_type_type;
+ if (sport)
+ key_porttosaddr(&sav->sah->saidx.src,
+ sport->sadb_x_nat_t_port_port);
+ if (dport)
+ key_porttosaddr(&sav->sah->saidx.dst,
+ dport->sadb_x_nat_t_port_port);
+ if (frag)
+ sav->esp_frag = frag->sadb_x_nat_t_frag_fraglen;
+ else
+ sav->esp_frag = IP_MAXPACKET;
+ }
+
+ return 0;
+}
+#endif
+
+
/*
* SADB_UPDATE processing
* receive
@@ -4944,8 +5296,10 @@
src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
+
/* get a SA header */
if ((sah = key_getsah(&saidx)) == NULL) {
@@ -5013,6 +5367,11 @@
return key_senderror(so, m, 0);
}
+#ifdef IPSEC_NAT_T
+ if ((error = key_handle_natt_info(sav,mhp)) != 0)
+ return key_senderror(so, m, EINVAL);
+#endif /* IPSEC_NAT_T */
+
{
struct mbuf *n;
@@ -5139,8 +5498,9 @@
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, mode, reqid, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
/* get a SA header */
if ((newsah = key_getsah(&saidx)) == NULL) {
@@ -5175,6 +5535,11 @@
return key_senderror(so, m, error);
}
+#ifdef IPSEC_NAT_T
+ if ((error = key_handle_natt_info(newsav, mhp)) != 0)
+ return key_senderror(so, m, EINVAL);
+#endif /* IPSEC_NAT_T */
+
/*
* don't call key_freesav() here, as we would like to keep the SA
* in the database on success.
@@ -5326,6 +5691,7 @@
struct secashead *sah;
struct secasvar *sav = NULL;
u_int16_t proto;
+ int error;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -5366,8 +5732,9 @@
src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
/* get a SA header */
LIST_FOREACH(sah, &sahtree, chain) {
@@ -5428,12 +5795,14 @@
struct secashead *sah;
struct secasvar *sav, *nextsav;
u_int stateidx, state;
+ int error;
src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
LIST_FOREACH(sah, &sahtree, chain) {
if (sah->state == SADB_SASTATE_DEAD)
@@ -5513,6 +5882,7 @@
struct secashead *sah;
struct secasvar *sav = NULL;
u_int16_t proto;
+ int error;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -5541,8 +5911,10 @@
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+
+ if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
/* get a SA header */
LIST_FOREACH(sah, &sahtree, chain) {
@@ -6225,8 +6597,9 @@
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
- /* XXX boundary check against sa_len */
- KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+ if ((error = key_setsecasidx(proto, IPSEC_MODE_ANY, 0, src0 + 1,
+ dst0 + 1, &saidx)) != 0)
+ return key_senderror(so, m, EINVAL);
/* get a SA index */
LIST_FOREACH(sah, &sahtree, chain) {
@@ -6913,7 +7286,9 @@
key_spdadd, /* SADB_X_SPDSETIDX */
NULL, /* SADB_X_SPDEXPIRE */
key_spddelete2, /* SADB_X_SPDDELETE2 */
- NULL, /* SADB_X_NAT_T_NEW_MAPPING */
+#ifdef IPSEC_NAT_T
+ key_nat_map, /* SADB_X_NAT_T_NEW_MAPPING */
+#endif
};
/*
@@ -7255,6 +7630,13 @@
case SADB_EXT_SPIRANGE:
case SADB_X_EXT_POLICY:
case SADB_X_EXT_SA2:
+#ifdef IPSEC_NAT_T
+ case SADB_X_EXT_NAT_T_TYPE:
+ case SADB_X_EXT_NAT_T_SPORT:
+ case SADB_X_EXT_NAT_T_DPORT:
+ case SADB_X_EXT_NAT_T_OA:
+ case SADB_X_EXT_NAT_T_FRAG:
+#endif
/* duplicate check */
/*
* XXX Are there duplication payloads of either
Index: netipsec/key.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/key.h,v
retrieving revision 1.6
diff -u -r1.6 key.h
--- netipsec/key.h 4 Mar 2007 06:03:29 -0000 1.6
+++ netipsec/key.h 19 Jun 2007 21:00:02 -0000
@@ -36,6 +36,8 @@
#ifdef _KERNEL
+#include "opt_ipsec.h"
+
struct secpolicy;
struct secpolicyindex;
struct ipsecrequest;
@@ -78,11 +80,11 @@
_key_freesp(spp, __FILE__, __LINE__)
extern struct secasvar *key_allocsa(const union sockaddr_union *,
- u_int, u_int32_t,const char*, int);
+ u_int, u_int32_t, u_int16_t, u_int16_t, const char*, int);
extern void key_freesav(struct secasvar **, const char*, int);
-#define KEY_ALLOCSA(dst, proto, spi) \
- key_allocsa(dst, proto, spi, __FILE__, __LINE__)
+#define KEY_ALLOCSA(dst, proto, spi, sport, dport) \
+ key_allocsa(dst, proto, spi, sport, dport, __FILE__, __LINE__)
#define KEY_FREESAV(psav) \
key_freesav(psav, __FILE__, __LINE__)
@@ -111,6 +113,12 @@
extern void key_sa_routechange __P((struct sockaddr *));
extern void key_sa_stir_iv __P((struct secasvar *));
+#ifdef IPSEC_NAT_T
+u_int16_t key_portfromsaddr __P((const union sockaddr_union *));
+#endif
+
+
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_SECA);
#endif /* MALLOC_DECLARE */
Index: netipsec/keydb.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/keydb.h,v
retrieving revision 1.4
diff -u -r1.4 keydb.h
--- netipsec/keydb.h 4 Mar 2007 19:54:49 -0000 1.4
+++ netipsec/keydb.h 19 Jun 2007 21:00:02 -0000
@@ -36,6 +36,8 @@
#ifdef _KERNEL
+#include "opt_ipsec.h"
+
#include <netipsec/key_var.h>
#include <net/route.h>
#include <netinet/in.h>
@@ -125,6 +127,11 @@
struct auth_hash *tdb_authalgxform; /* authentication algorithm */
struct comp_algo *tdb_compalgxform; /* compression algorithm */
u_int64_t tdb_cryptoid; /* crypto session id */
+
+#ifdef IPSEC_NAT_T
+ u_int16_t natt_type;
+ u_int16_t esp_frag;
+#endif
};
/* replay prevention */
Index: netipsec/xform_ah.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_ah.c,v
retrieving revision 1.17
diff -u -r1.17 xform_ah.c
--- netipsec/xform_ah.c 25 Mar 2007 22:11:18 -0000 1.17
+++ netipsec/xform_ah.c 19 Jun 2007 21:00:02 -0000
@@ -794,6 +794,11 @@
u_int8_t nxt;
char *ptr;
int s, authsize;
+ u_int16_t dport = 0;
+ u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+ struct m_tag * tag = NULL;
+#endif
crd = crp->crp_desc;
@@ -805,9 +810,18 @@
mtag = (struct m_tag *) tc->tc_ptr;
m = (struct mbuf *) crp->crp_buf;
+
+#ifdef IPSEC_NAT_T
+ /* find the source port for NAT-T */
+ if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+ sport = ((u_int16_t *)(tag + 1))[0];
+ dport = ((u_int16_t *)(tag + 1))[1];
+ }
+#endif
+
s = splsoftnet();
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
if (sav == NULL) {
ahstat.ahs_notdb++;
DPRINTF(("ah_input_cb: SA expired while in crypto\n"));
@@ -1208,7 +1222,7 @@
s = splsoftnet();
isr = tc->tc_isr;
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
if (sav == NULL) {
ahstat.ahs_notdb++;
DPRINTF(("ah_output_cb: SA expired while in crypto\n"));
Index: netipsec/xform_esp.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_esp.c,v
retrieving revision 1.15
diff -u -r1.15 xform_esp.c
--- netipsec/xform_esp.c 4 Mar 2007 21:17:55 -0000 1.15
+++ netipsec/xform_esp.c 19 Jun 2007 21:00:02 -0000
@@ -469,6 +469,11 @@
struct secasvar *sav;
struct secasindex *saidx;
void *ptr;
+ u_int16_t dport = 0;
+ u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+ struct m_tag * tag = NULL;
+#endif
crd = crp->crp_desc;
IPSEC_ASSERT(crd != NULL, ("esp_input_cb: null crypto descriptor!"));
@@ -480,9 +485,17 @@
mtag = (struct m_tag *) tc->tc_ptr;
m = (struct mbuf *) crp->crp_buf;
+#ifdef IPSEC_NAT_T
+ /* find the source port for NAT-T */
+ if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+ sport = ((u_int16_t *)(tag + 1))[0];
+ dport = ((u_int16_t *)(tag + 1))[1];
+ }
+#endif
+
s = splsoftnet();
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
if (sav == NULL) {
espstat.esps_notdb++;
DPRINTF(("esp_input_cb: SA expired while in crypto "
@@ -920,7 +933,7 @@
s = splsoftnet();
isr = tc->tc_isr;
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
if (sav == NULL) {
espstat.esps_notdb++;
DPRINTF(("esp_output_cb: SA expired while in crypto "
Index: netipsec/xform_ipcomp.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/xform_ipcomp.c,v
retrieving revision 1.13
diff -u -r1.13 xform_ipcomp.c
--- netipsec/xform_ipcomp.c 4 Mar 2007 21:17:55 -0000 1.13
+++ netipsec/xform_ipcomp.c 19 Jun 2007 21:00:02 -0000
@@ -226,6 +226,11 @@
int s, hlen = IPCOMP_HLENGTH, error, clen;
u_int8_t nproto;
void *addr;
+ u_int16_t dport = 0;
+ u_int16_t sport = 0;
+#ifdef IPSEC_NAT_T
+ struct m_tag * tag = NULL;
+#endif
crd = crp->crp_desc;
@@ -236,9 +241,17 @@
mtag = (struct mtag *) tc->tc_ptr;
m = (struct mbuf *) crp->crp_buf;
+#ifdef IPSEC_NAT_T
+ /* find the source port for NAT-T */
+ if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL))) {
+ sport = ((u_int16_t *)(tag + 1))[0];
+ dport = ((u_int16_t *)(tag + 1))[1];
+ }
+#endif
+
s = splsoftnet();
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, sport, dport);
if (sav == NULL) {
ipcompstat.ipcomps_notdb++;
DPRINTF(("ipcomp_input_cb: SA expired while in crypto\n"));
@@ -491,7 +504,7 @@
s = splsoftnet();
isr = tc->tc_isr;
- sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
+ sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
if (sav == NULL) {
ipcompstat.ipcomps_notdb++;
DPRINTF(("ipcomp_output_cb: SA expired while in crypto\n"));
--X1bOJ3K7DJ5YkBrT--