Module Name: src
Committed By: martin
Date: Sun Mar 13 11:59:23 UTC 2016
Modified Files:
src/sys/netipsec [netbsd-7]: key.c key_debug.h
Log Message:
Pull up following revision(s) (requested by christos in ticket #1136):
sys/netipsec/key.c: revision 1.92-1.97
sys/netipsec/key_debug.h: revision 1.7
Add more debugging, no functional change.
Gather more information from mbuf.
Fix port matching; we need to ignore ports when they are 0 not only in
the second saidx but the first one too. Fixes NAT-T issue with NetBSD
being the host behind NAT.
Kill stray &
Simplify the port comparison code further.
PR/50905: Henning Petersen: Fix useless comparison (from FreeBSD)
To generate a diff of this commit:
cvs rdiff -u -r1.91 -r1.91.2.1 src/sys/netipsec/key.c
cvs rdiff -u -r1.6 -r1.6.30.1 src/sys/netipsec/key_debug.h
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/key.c
diff -u src/sys/netipsec/key.c:1.91 src/sys/netipsec/key.c:1.91.2.1
--- src/sys/netipsec/key.c:1.91 Mon Jun 16 03:34:45 2014
+++ src/sys/netipsec/key.c Sun Mar 13 11:59:22 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: key.c,v 1.91 2014/06/16 03:34:45 christos Exp $ */
+/* $NetBSD: key.c,v 1.91.2.1 2016/03/13 11:59:22 martin 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 $ */
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.91 2014/06/16 03:34:45 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.91.2.1 2016/03/13 11:59:22 martin Exp $");
/*
* This code is referd to RFC 2367
@@ -113,6 +113,10 @@ __KERNEL_RCSID(0, "$NetBSD: key.c,v 1.91
#define FULLMASK 0xff
#define _BITS(bytes) ((bytes) << 3)
+#define PORT_NONE 0
+#define PORT_LOOSE 1
+#define PORT_STRICT 2
+
percpu_t *pfkeystat_percpu;
/*
@@ -676,7 +680,7 @@ key_allocsp2(u_int32_t spi,
/* NB: spi's must exist and match */
if (!sp->req || !sp->req->sav || sp->req->sav->spi != spi)
continue;
- if (key_sockaddrcmp(&sp->spidx.dst.sa, &dst->sa, 1) == 0)
+ if (key_sockaddrcmp(&sp->spidx.dst.sa, &dst->sa, PORT_STRICT) == 0)
goto found;
}
sp = NULL;
@@ -748,13 +752,13 @@ key_gettunnel(const struct sockaddr *osr
if (!key_cmpspidx_withmask(&sp->spidx, &spidx))
continue;
} else {
- if (key_sockaddrcmp(&r1->saidx.src.sa, isrc, 0) ||
- key_sockaddrcmp(&r1->saidx.dst.sa, idst, 0))
+ if (key_sockaddrcmp(&r1->saidx.src.sa, isrc, PORT_NONE) ||
+ key_sockaddrcmp(&r1->saidx.dst.sa, idst, PORT_NONE))
continue;
}
- if (key_sockaddrcmp(&r2->saidx.src.sa, osrc, 0) ||
- key_sockaddrcmp(&r2->saidx.dst.sa, odst, 0))
+ if (key_sockaddrcmp(&r2->saidx.src.sa, osrc, PORT_NONE) ||
+ key_sockaddrcmp(&r2->saidx.dst.sa, odst, PORT_NONE))
continue;
goto found;
@@ -1086,9 +1090,8 @@ key_allocsa(
struct secasvar *sav;
u_int stateidx, state;
const u_int *saorder_state_valid;
- int arraysize;
+ int arraysize, chkport;
int s;
- int chkport = 0;
int must_check_spi = 1;
int must_check_alg = 0;
@@ -1096,13 +1099,12 @@ key_allocsa(
u_int8_t algo = 0;
if ((sport != 0) && (dport != 0))
- chkport = 1;
+ chkport = PORT_STRICT;
+ else
+ chkport = PORT_NONE;
IPSEC_ASSERT(dst != NULL, ("key_allocsa: null dst address"));
- KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
- printf("DP %s from %s:%u\n", __func__, where, tag));
-
/*
* XXX IPCOMP case
* We use cpi to define spi here. In the case where cpi <=
@@ -1121,6 +1123,10 @@ key_allocsa(
must_check_alg = 1;
}
}
+ KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+ printf("DP %s from %s:%u check_spi=%d, check_alg=%d\n",
+ __func__, where, tag, must_check_spi, must_check_alg));
+
/*
* searching SAD.
@@ -1141,25 +1147,44 @@ key_allocsa(
for (stateidx = 0; stateidx < arraysize; stateidx++) {
state = saorder_state_valid[stateidx];
LIST_FOREACH(sav, &sah->savtree[state], chain) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("try match spi %#x, %#x\n",
+ ntohl(spi), ntohl(sav->spi)));
/* sanity check */
KEY_CHKSASTATE(sav->state, state, "key_allocsav");
/* do not return entries w/ unusable state */
if (sav->state != SADB_SASTATE_MATURE &&
- sav->state != SADB_SASTATE_DYING)
+ sav->state != SADB_SASTATE_DYING) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("bad state %d\n",
+ sav->state));
continue;
- if (proto != sav->sah->saidx.proto)
+ }
+ if (proto != sav->sah->saidx.proto) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("proto fail %d != %d\n",
+ proto, sav->sah->saidx.proto));
continue;
- if (must_check_spi && spi != sav->spi)
+ }
+ if (must_check_spi && spi != sav->spi) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("spi fail %#x != %#x\n",
+ ntohl(spi), ntohl(sav->spi)));
continue;
+ }
/* XXX only on the ipcomp case */
- if (must_check_alg && algo != sav->alg_comp)
+ if (must_check_alg && algo != sav->alg_comp) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("algo fail %d != %d\n",
+ algo, sav->alg_comp));
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)
+ if (key_sockaddrcmp(&src->sa, &sav->sah->saidx.src.sa, PORT_NONE) != 0)
continue;
#endif
/* fix port of dst address XXX*/
@@ -4189,7 +4214,8 @@ key_cmpsaidx(
const struct secasindex *saidx1,
int flag)
{
- int chkport = 0;
+ int chkport;
+ const struct sockaddr *sa0src, *sa0dst, *sa1src, *sa1dst;
/* sanity */
if (saidx0 == NULL && saidx1 == NULL)
@@ -4228,29 +4254,28 @@ key_cmpsaidx(
return 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.
- * Also 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 &&
- ((((const struct sockaddr *)(&saidx1->src))->sa_family == AF_INET &&
- ((const struct sockaddr *)(&saidx1->dst))->sa_family == AF_INET &&
- ((const struct sockaddr_in *)(&saidx1->src))->sin_port &&
- ((const struct sockaddr_in *)(&saidx1->dst))->sin_port) ||
- (((const struct sockaddr *)(&saidx1->src))->sa_family == AF_INET6 &&
- ((const struct sockaddr *)(&saidx1->dst))->sa_family == AF_INET6 &&
- ((const struct sockaddr_in6 *)(&saidx1->src))->sin6_port &&
- ((const struct sockaddr_in6 *)(&saidx1->dst))->sin6_port)))
- chkport = 1;
- if (key_sockaddrcmp(&saidx0->src.sa, &saidx1->src.sa, chkport) != 0) {
+ sa0src = &saidx0->src.sa;
+ sa0dst = &saidx0->dst.sa;
+ sa1src = &saidx1->src.sa;
+ 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
+ * in the SPD: This means we have a non-generated
+ * SPD which can't know UDP ports.
+ */
+ if (saidx1->mode == IPSEC_MODE_TUNNEL)
+ chkport = PORT_LOOSE;
+ else
+ chkport = PORT_NONE;
+
+ if (key_sockaddrcmp(sa0src, sa1src, chkport) != 0) {
return 0;
}
- if (key_sockaddrcmp(&saidx0->dst.sa, &saidx1->dst.sa, chkport) != 0) {
+ if (key_sockaddrcmp(sa0dst, sa1dst, chkport) != 0) {
return 0;
}
}
@@ -4284,8 +4309,8 @@ key_cmpspidx_exactly(
|| spidx0->ul_proto != spidx1->ul_proto)
return 0;
- return key_sockaddrcmp(&spidx0->src.sa, &spidx1->src.sa, 1) == 0 &&
- key_sockaddrcmp(&spidx0->dst.sa, &spidx1->dst.sa, 1) == 0;
+ return key_sockaddrcmp(&spidx0->src.sa, &spidx1->src.sa, PORT_STRICT) == 0 &&
+ key_sockaddrcmp(&spidx0->dst.sa, &spidx1->dst.sa, PORT_STRICT) == 0;
}
/*
@@ -4391,46 +4416,86 @@ key_cmpspidx_withmask(
/* returns 0 on match */
static int
+key_portcomp(in_port_t port1, in_port_t port2, int howport)
+{
+ switch (howport) {
+ case PORT_NONE:
+ return 0;
+ case PORT_LOOSE:
+ if (port1 == 0 || port2 == 0)
+ return 0;
+ /*FALLTHROUGH*/
+ case PORT_STRICT:
+ if (port1 != port2) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("port fail %d != %d\n", port1, port2));
+ return 1;
+ }
+ return 0;
+ default:
+ KASSERT(0);
+ return 1;
+ }
+}
+
+/* returns 0 on match */
+static int
key_sockaddrcmp(
const struct sockaddr *sa1,
const struct sockaddr *sa2,
- int port)
+ int howport)
{
-#ifdef satosin
-#undef satosin
-#endif
-#define satosin(s) ((const struct sockaddr_in *)s)
-#ifdef satosin6
-#undef satosin6
-#endif
-#define satosin6(s) ((const struct sockaddr_in6 *)s)
- if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len)
+ const struct sockaddr_in *sin1, *sin2;
+ const struct sockaddr_in6 *sin61, *sin62;
+
+ if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("fam/len fail %d != %d || %d != %d\n",
+ sa1->sa_family, sa2->sa_family, sa1->sa_len,
+ sa2->sa_len));
return 1;
+ }
switch (sa1->sa_family) {
case AF_INET:
- if (sa1->sa_len != sizeof(struct sockaddr_in))
+ if (sa1->sa_len != sizeof(struct sockaddr_in)) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("len fail %d != %zu\n",
+ sa1->sa_len, sizeof(struct sockaddr_in)));
return 1;
- if (satosin(sa1)->sin_addr.s_addr !=
- satosin(sa2)->sin_addr.s_addr) {
+ }
+ sin1 = (const struct sockaddr_in *)sa1;
+ sin2 = (const struct sockaddr_in *)sa2;
+ if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("addr fail %#x != %#x\n",
+ sin1->sin_addr.s_addr,
+ sin2->sin_addr.s_addr));
return 1;
}
- if (port && satosin(sa1)->sin_port != satosin(sa2)->sin_port)
+ if (key_portcomp(sin1->sin_port, sin2->sin_port, howport)) {
return 1;
+ }
+ KEYDEBUG(KEYDEBUG_MATCH,
+ printf("addr success %#x[%d] == %#x[%d]\n",
+ sin1->sin_addr.s_addr,
+ sin1->sin_port,
+ sin2->sin_addr.s_addr,
+ sin2->sin_port));
break;
case AF_INET6:
+ sin61 = (const struct sockaddr_in6 *)sa1;
+ sin62 = (const struct sockaddr_in6 *)sa2;
if (sa1->sa_len != sizeof(struct sockaddr_in6))
return 1; /*EINVAL*/
- if (satosin6(sa1)->sin6_scope_id !=
- satosin6(sa2)->sin6_scope_id) {
+
+ if (sin61->sin6_scope_id != sin62->sin6_scope_id) {
return 1;
}
- if (!IN6_ARE_ADDR_EQUAL(&satosin6(sa1)->sin6_addr,
- &satosin6(sa2)->sin6_addr)) {
+ if (!IN6_ARE_ADDR_EQUAL(&sin61->sin6_addr, &sin62->sin6_addr)) {
return 1;
}
- if (port &&
- satosin6(sa1)->sin6_port != satosin6(sa2)->sin6_port) {
+ if (key_portcomp(sin61->sin6_port, sin62->sin6_port, howport)) {
return 1;
}
break;
@@ -4441,8 +4506,6 @@ key_sockaddrcmp(
}
return 0;
-#undef satosin
-#undef satosin6
}
/*
@@ -5615,11 +5678,14 @@ key_getmsgbuf_x1(struct mbuf *m, const s
panic("key_getmsgbuf_x1: NULL pointer is passed");
/* create new sadb_msg to reply. */
- n = key_gather_mbuf(m, mhp, 1, 9, SADB_EXT_RESERVED,
+ n = key_gather_mbuf(m, mhp, 1, 15, SADB_EXT_RESERVED,
SADB_EXT_SA, SADB_X_EXT_SA2,
SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST,
SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT,
- SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST);
+ SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST,
+ SADB_X_EXT_NAT_T_TYPE, SADB_X_EXT_NAT_T_SPORT,
+ SADB_X_EXT_NAT_T_DPORT, SADB_X_EXT_NAT_T_OAI,
+ SADB_X_EXT_NAT_T_OAR, SADB_X_EXT_NAT_T_FRAG);
if (!n)
return NULL;
@@ -7267,6 +7333,7 @@ key_parse(struct mbuf *m, struct socket
{
struct sadb_msg *msg;
struct sadb_msghdr mh;
+ u_int orglen;
int error;
int target;
@@ -7286,10 +7353,11 @@ key_parse(struct mbuf *m, struct socket
return ENOBUFS;
}
msg = mtod(m, struct sadb_msg *);
+ orglen = PFKEY_UNUNIT64(msg->sadb_msg_len);
target = KEY_SENDUP_ONE;
if ((m->m_flags & M_PKTHDR) == 0 ||
- m->m_pkthdr.len != m->m_pkthdr.len) {
+ m->m_pkthdr.len != orglen) {
ipseclog((LOG_DEBUG, "key_parse: invalid message length.\n"));
PFKEY_STATINC(PFKEY_STAT_OUT_INVLEN);
error = EINVAL;
Index: src/sys/netipsec/key_debug.h
diff -u src/sys/netipsec/key_debug.h:1.6 src/sys/netipsec/key_debug.h:1.6.30.1
--- src/sys/netipsec/key_debug.h:1.6 Mon Feb 21 22:21:40 2011
+++ src/sys/netipsec/key_debug.h Sun Mar 13 11:59:22 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: key_debug.h,v 1.6 2011/02/21 22:21:40 drochner Exp $ */
+/* $NetBSD: key_debug.h,v 1.6.30.1 2016/03/13 11:59:22 martin Exp $ */
/* $FreeBSD: src/sys/netipsec/key_debug.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
/* $KAME: key_debug.h,v 1.10 2001/08/05 08:37:52 itojun Exp $ */
@@ -39,6 +39,7 @@
#define KEYDEBUG_STAMP 0x00000001 /* path */
#define KEYDEBUG_DATA 0x00000002 /* data */
#define KEYDEBUG_DUMP 0x00000004 /* dump */
+#define KEYDEBUG_MATCH 0x00000008 /* match */
#define KEYDEBUG_KEY 0x00000010 /* key processing */
#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */