Add support for nat-t oa payload handling. Submitted by Timo Teras.

This commit is contained in:
mgrooms 2007-12-12 04:45:59 +00:00
parent 27f7bc42d9
commit 892304dffa
5 changed files with 338 additions and 44 deletions

View File

@ -1,3 +1,10 @@
2007-12-11 Matthew Grooms
From Timo Teras <timo.teras@iki.fi>:
* src/racoon/handler.c
src/racoon/handler.h
src/racoon/isakmp_quick.c
src/racoon/pfkey.c: add support for nat-t oa payload handling.
2007-12-04 Matthew Grooms
From Timo Teras <timo.teras@iki.fi>:
* src/racoon/ipsec_doi.c

View File

@ -1,4 +1,4 @@
/* $NetBSD: handler.c,v 1.16 2007/09/12 23:39:50 mgrooms Exp $ */
/* $NetBSD: handler.c,v 1.17 2007/12/12 04:45:59 mgrooms Exp $ */
/* Id: handler.c,v 1.28 2006/05/26 12:17:29 manubsd Exp */
@ -656,13 +656,23 @@ delph2(iph2)
iph2->dst = NULL;
}
if (iph2->src_id) {
racoon_free(iph2->src_id);
iph2->src_id = NULL;
racoon_free(iph2->src_id);
iph2->src_id = NULL;
}
if (iph2->dst_id) {
racoon_free(iph2->dst_id);
iph2->dst_id = NULL;
racoon_free(iph2->dst_id);
iph2->dst_id = NULL;
}
#ifdef ENABLE_NATT
if (iph2->natoa_src) {
racoon_free(iph2->natoa_src);
iph2->natoa_src = NULL;
}
if (iph2->natoa_dst) {
racoon_free(iph2->natoa_dst);
iph2->natoa_dst = NULL;
}
#endif
if (iph2->proposal) {
flushsaprop(iph2->proposal);

View File

@ -1,4 +1,4 @@
/* $NetBSD: handler.h,v 1.9 2006/09/09 16:22:09 manu Exp $ */
/* $NetBSD: handler.h,v 1.10 2007/12/12 04:46:00 mgrooms Exp $ */
/* Id: handler.h,v 1.19 2006/02/25 08:25:12 manubsd Exp */
@ -253,6 +253,10 @@ struct ph2handle {
*/
struct sockaddr *src_id;
struct sockaddr *dst_id;
#ifdef ENABLE_NATT
struct sockaddr *natoa_src; /* peer's view of my address */
struct sockaddr *natoa_dst; /* peer's view of his address */
#endif
u_int32_t spid; /* policy id by kernel */

View File

@ -1,4 +1,4 @@
/* $NetBSD: isakmp_quick.c,v 1.15 2007/12/04 19:52:31 mgrooms Exp $ */
/* $NetBSD: isakmp_quick.c,v 1.16 2007/12/12 04:46:00 mgrooms Exp $ */
/* Id: isakmp_quick.c,v 1.29 2006/08/22 18:17:17 manubsd Exp */
@ -90,6 +90,10 @@
#include "isakmp_cfg.h"
#endif
#ifdef ENABLE_NATT
#include "nattraversal.h"
#endif
/* quick mode */
static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *));
static int get_sainfo_r __P((struct ph2handle *));
@ -145,7 +149,7 @@ end:
/*
* send to responder
* HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
* HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
*/
int
quick_i1send(iph2, msg)
@ -158,9 +162,14 @@ quick_i1send(iph2, msg)
char *p;
int tlen;
int error = ISAKMP_INTERNAL_ERROR;
int natoa = ISAKMP_NPTYPE_NONE;
int pfsgroup, idci, idcr;
int np;
struct ipsecdoi_id_b *id, *id_p;
#ifdef ENABLE_NATT
vchar_t *nat_oai = NULL;
vchar_t *nat_oar = NULL;
#endif
/* validity check */
if (msg != NULL) {
@ -231,6 +240,35 @@ quick_i1send(iph2, msg)
} else
idci = idcr = 1;
#ifdef ENABLE_NATT
/*
* RFC3947 5.2. if we propose UDP-Encapsulated-Transport
* we should send NAT-OA
*/
if (ipsecdoi_transportmode(iph2->proposal)
&& (iph2->ph1->natt_flags & NAT_DETECTED)) {
natoa = iph2->ph1->natt_options->payload_nat_oa;
nat_oai = ipsecdoi_sockaddr2id(iph2->src,
IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
nat_oar = ipsecdoi_sockaddr2id(iph2->dst,
IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
if (nat_oai == NULL || nat_oar == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
"failed to generate NAT-OA payload.\n");
goto end;
}
plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n");
plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l);
plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n");
plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l);
} else {
natoa = ISAKMP_NPTYPE_NONE;
}
#endif
/* create SA;NONCE payload, and KE if need, and IDii, IDir. */
tlen = + sizeof(*gen) + iph2->sa->l
+ sizeof(*gen) + iph2->nonce->l;
@ -240,6 +278,10 @@ quick_i1send(iph2, msg)
tlen += sizeof(*gen) + iph2->id->l;
if (idcr)
tlen += sizeof(*gen) + iph2->id_p->l;
#ifdef ENABLE_NATT
if (natoa != ISAKMP_NPTYPE_NONE)
tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l;
#endif
body = vmalloc(tlen);
if (body == NULL) {
@ -259,22 +301,30 @@ quick_i1send(iph2, msg)
else if (idci || idcr)
np = ISAKMP_NPTYPE_ID;
else
np = ISAKMP_NPTYPE_NONE;
np = natoa;
p = set_isakmp_payload(p, iph2->nonce, np);
/* add KE payload if need. */
np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
np = (idci || idcr) ? ISAKMP_NPTYPE_ID : natoa;
if (pfsgroup)
p = set_isakmp_payload(p, iph2->dhpub, np);
/* IDci */
np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
np = (idcr) ? ISAKMP_NPTYPE_ID : natoa;
if (idci)
p = set_isakmp_payload(p, iph2->id, np);
/* IDcr */
if (idcr)
p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE);
p = set_isakmp_payload(p, iph2->id_p, natoa);
#ifdef ENABLE_NATT
/* NAT-OA */
if (natoa != ISAKMP_NPTYPE_NONE) {
p = set_isakmp_payload(p, nat_oai, natoa);
p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE);
}
#endif
/* generate HASH(1) */
hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body);
@ -301,13 +351,19 @@ end:
vfree(body);
if (hash != NULL)
vfree(hash);
#ifdef ENABLE_NATT
if (nat_oai != NULL)
vfree(nat_oai);
if (nat_oar != NULL)
vfree(nat_oar);
#endif
return error;
}
/*
* receive from responder
* HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
* HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
*/
int
quick_i2recv(iph2, msg0)
@ -317,10 +373,11 @@ quick_i2recv(iph2, msg0)
vchar_t *msg = NULL;
vchar_t *hbuf = NULL; /* for hash computing. */
vchar_t *pbuf = NULL; /* for payload parsing */
vchar_t *idci = NULL;
vchar_t *idcr = NULL;
struct isakmp_parse_t *pa;
struct isakmp *isakmp = (struct isakmp *)msg0->v;
struct isakmp_pl_hash *hash = NULL;
int f_id;
char *p;
int tlen;
int error = ISAKMP_INTERNAL_ERROR;
@ -394,7 +451,6 @@ quick_i2recv(iph2, msg0)
* copy non-HASH payloads into hbuf, so that we can validate HASH.
*/
iph2->sa_ret = NULL;
f_id = 0; /* flag to use checking ID */
tlen = 0; /* count payload length except of HASH payload. */
for (; pa->type; pa++) {
@ -425,27 +481,15 @@ quick_i2recv(iph2, msg0)
break;
case ISAKMP_NPTYPE_ID:
{
vchar_t *vp;
/* check ID value */
if (f_id == 0) {
/* for IDci */
f_id = 1;
vp = iph2->id;
if (idci == NULL) {
if (isakmp_p2ph(&idci, pa->ptr) < 0)
goto end;
} else if (idcr == NULL) {
if (isakmp_p2ph(&idcr, pa->ptr) < 0)
goto end;
} else {
/* for IDcr */
vp = iph2->id_p;
}
if (memcmp(vp->v, (caddr_t)pa->ptr + sizeof(struct isakmp_gen), vp->l)) {
plog(LLV_ERROR, LOCATION, NULL,
"mismatched ID was returned.\n");
error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
goto end;
}
}
break;
case ISAKMP_NPTYPE_N:
@ -455,7 +499,38 @@ quick_i2recv(iph2, msg0)
#ifdef ENABLE_NATT
case ISAKMP_NPTYPE_NATOA_DRAFT:
case ISAKMP_NPTYPE_NATOA_RFC:
/* Ignore original source/destination messages */
{
struct sockaddr_storage addr;
struct sockaddr *daddr;
u_int8_t prefix;
u_int16_t ul_proto;
vchar_t *vp;
if (isakmp_p2ph(&vp, pa->ptr) < 0)
goto end;
error = ipsecdoi_id2sockaddr(vp,
(struct sockaddr *) &addr,
&prefix, &ul_proto);
vfree(vp);
if (error)
goto end;
daddr = dupsaddr((struct sockaddr *) &addr);
if (daddr == NULL)
goto end;
if (iph2->natoa_src == NULL)
iph2->natoa_src = daddr;
else if (iph2->natoa_dst == NULL)
iph2->natoa_dst = daddr;
else {
racoon_free(daddr);
goto end;
}
}
break;
#endif
@ -481,6 +556,98 @@ quick_i2recv(iph2, msg0)
goto end;
}
/* identity check */
if (idci != NULL) {
struct sockaddr_storage proposed_addr, got_addr;
u_int8_t proposed_prefix, got_prefix;
u_int16_t proposed_ulproto, got_ulproto;
error = ipsecdoi_id2sockaddr(iph2->id,
(struct sockaddr *) &proposed_addr,
&proposed_prefix, &proposed_ulproto);
if (error)
goto end;
error = ipsecdoi_id2sockaddr(idci,
(struct sockaddr *) &got_addr,
&got_prefix, &got_ulproto);
if (error)
goto end;
if (proposed_prefix != got_prefix
|| proposed_ulproto != got_ulproto) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDci prefix/ulproto does not match proposal.\n");
error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
goto end;
}
if (cmpsaddrstrict((struct sockaddr *) &proposed_addr,
(struct sockaddr *) &got_addr) == 0) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDci matches proposal.\n");
#ifdef ENABLE_NATT
} else if (iph2->natoa_src != NULL
&& cmpsaddrwop(iph2->natoa_src,
(struct sockaddr *) &got_addr) == 0
&& extract_port((struct sockaddr *) &proposed_addr) ==
extract_port((struct sockaddr *) &got_addr)) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDci matches NAT-OAi.\n");
#endif
} else {
plog(LLV_ERROR, LOCATION, NULL,
"mismatched IDci was returned.\n");
error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
goto end;
}
}
if (idcr != NULL) {
struct sockaddr_storage proposed_addr, got_addr;
u_int8_t proposed_prefix, got_prefix;
u_int16_t proposed_ulproto, got_ulproto;
error = ipsecdoi_id2sockaddr(iph2->id_p,
(struct sockaddr *) &proposed_addr,
&proposed_prefix, &proposed_ulproto);
if (error)
goto end;
error = ipsecdoi_id2sockaddr(idcr,
(struct sockaddr *) &got_addr,
&got_prefix, &got_ulproto);
if (error)
goto end;
if (proposed_prefix != got_prefix
|| proposed_ulproto != got_ulproto) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDcr prefix/ulproto does not match proposal.\n");
error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
goto end;
}
if (cmpsaddrstrict((struct sockaddr *) &proposed_addr,
(struct sockaddr *) &got_addr) == 0) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDcr matches proposal.\n");
#ifdef ENABLE_NATT
} else if (iph2->natoa_dst != NULL
&& cmpsaddrwop(iph2->natoa_dst,
(struct sockaddr *) &got_addr) == 0
&& extract_port((struct sockaddr *) &proposed_addr) ==
extract_port((struct sockaddr *) &got_addr)) {
plog(LLV_DEBUG, LOCATION, NULL,
"IDcr matches NAT-OAr.\n");
#endif
} else {
plog(LLV_ERROR, LOCATION, NULL,
"mismatched IDcr was returned.\n");
error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
goto end;
}
}
/* Fixed buffer for calculating HASH */
memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l);
plog(LLV_DEBUG, LOCATION, NULL,
@ -533,6 +700,10 @@ end:
vfree(pbuf);
if (msg)
vfree(msg);
if (idci)
vfree(idci);
if (idcr)
vfree(idcr);
if (error) {
VPTRINIT(iph2->sa_ret);
@ -540,6 +711,16 @@ end:
VPTRINIT(iph2->dhpub_p);
VPTRINIT(iph2->id);
VPTRINIT(iph2->id_p);
#ifdef ENABLE_NATT
if (iph2->natoa_src) {
racoon_free(iph2->natoa_src);
iph2->natoa_src = NULL;
}
if (iph2->natoa_dst) {
racoon_free(iph2->natoa_dst);
iph2->natoa_dst = NULL;
}
#endif
}
return error;
@ -829,7 +1010,7 @@ end:
/*
* receive from initiator
* HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ]
* HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
*/
int
quick_r1recv(iph2, msg0)
@ -998,7 +1179,38 @@ quick_r1recv(iph2, msg0)
#ifdef ENABLE_NATT
case ISAKMP_NPTYPE_NATOA_DRAFT:
case ISAKMP_NPTYPE_NATOA_RFC:
/* Ignore original source/destination messages */
{
struct sockaddr_storage addr;
struct sockaddr *daddr;
u_int8_t prefix;
u_int16_t ul_proto;
vchar_t *vp;
if (isakmp_p2ph(&vp, pa->ptr) < 0)
goto end;
error = ipsecdoi_id2sockaddr(vp,
(struct sockaddr *) &addr,
&prefix, &ul_proto);
vfree(vp);
if (error)
goto end;
daddr = dupsaddr((struct sockaddr *) &addr);
if (daddr == NULL)
goto end;
if (iph2->natoa_dst == NULL)
iph2->natoa_dst = daddr;
else if (iph2->natoa_src == NULL)
iph2->natoa_src = daddr;
else {
racoon_free(daddr);
goto end;
}
}
break;
#endif
@ -1137,6 +1349,16 @@ end:
VPTRINIT(iph2->dhpub_p);
VPTRINIT(iph2->id);
VPTRINIT(iph2->id_p);
#ifdef ENABLE_NATT
if (iph2->natoa_src) {
racoon_free(iph2->natoa_src);
iph2->natoa_src = NULL;
}
if (iph2->natoa_dst) {
racoon_free(iph2->natoa_dst);
iph2->natoa_dst = NULL;
}
#endif
}
return error;
@ -1178,7 +1400,7 @@ end:
/*
* send to initiator
* HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ]
* HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] [, NAT-OAi, NAT-OAr ]
*/
int
quick_r2send(iph2, msg)
@ -1191,8 +1413,13 @@ quick_r2send(iph2, msg)
char *p;
int tlen;
int error = ISAKMP_INTERNAL_ERROR;
int natoa = ISAKMP_NPTYPE_NONE;
int pfsgroup;
u_int8_t *np_p = NULL;
#ifdef ENABLE_NATT
vchar_t *nat_oai = NULL;
vchar_t *nat_oar = NULL;
#endif
/* validity check */
if (msg != NULL) {
@ -1233,6 +1460,33 @@ quick_r2send(iph2, msg)
}
}
#ifdef ENABLE_NATT
/*
* RFC3947 5.2. if we chose UDP-Encapsulated-Transport
* we should send NAT-OA
*/
if (ipsecdoi_transportmode(iph2->proposal)
&& (iph2->ph1->natt_flags & NAT_DETECTED)) {
natoa = iph2->ph1->natt_options->payload_nat_oa;
nat_oai = ipsecdoi_sockaddr2id(iph2->dst,
IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
nat_oar = ipsecdoi_sockaddr2id(iph2->src,
IPSECDOI_PREFIX_HOST, IPSEC_ULPROTO_ANY);
if (nat_oai == NULL || nat_oar == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
"failed to generate NAT-OA payload.\n");
goto end;
}
plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAi:\n");
plogdump(LLV_DEBUG, nat_oai->v, nat_oai->l);
plog(LLV_DEBUG, LOCATION, NULL, "NAT-OAr:\n");
plogdump(LLV_DEBUG, nat_oar->v, nat_oar->l);
}
#endif
/* create SA;NONCE payload, and KE and ID if need */
tlen = sizeof(*gen) + iph2->sa_ret->l
+ sizeof(*gen) + iph2->nonce->l;
@ -1241,6 +1495,10 @@ quick_r2send(iph2, msg)
if (iph2->id_p != NULL)
tlen += (sizeof(*gen) + iph2->id_p->l
+ sizeof(*gen) + iph2->id->l);
#ifdef ENABLE_NATT
if (natoa != ISAKMP_NPTYPE_NONE)
tlen += 2 * sizeof(*gen) + nat_oai->l + nat_oar->l;
#endif
body = vmalloc(tlen);
if (body == NULL) {
@ -1260,14 +1518,14 @@ quick_r2send(iph2, msg)
? ISAKMP_NPTYPE_KE
: (iph2->id_p != NULL
? ISAKMP_NPTYPE_ID
: ISAKMP_NPTYPE_NONE));
: natoa));
/* add KE payload if need. */
if (iph2->dhpub_p != NULL && pfsgroup != 0) {
np_p = &((struct isakmp_gen *)p)->np; /* XXX */
p = set_isakmp_payload(p, iph2->dhpub,
(iph2->id_p == NULL)
? ISAKMP_NPTYPE_NONE
? natoa
: ISAKMP_NPTYPE_ID);
}
@ -1277,9 +1535,17 @@ quick_r2send(iph2, msg)
p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID);
/* IDcr */
np_p = &((struct isakmp_gen *)p)->np; /* XXX */
p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE);
p = set_isakmp_payload(p, iph2->id, natoa);
}
#ifdef ENABLE_NATT
/* NAT-OA */
if (natoa != ISAKMP_NPTYPE_NONE) {
p = set_isakmp_payload(p, nat_oai, natoa);
p = set_isakmp_payload(p, nat_oar, ISAKMP_NPTYPE_NONE);
}
#endif
/* add a RESPONDER-LIFETIME notify payload if needed */
{
vchar_t *data = NULL;
@ -1373,6 +1639,12 @@ end:
vfree(body);
if (hash != NULL)
vfree(hash);
#ifdef ENABLE_NATT
if (nat_oai != NULL)
vfree(nat_oai);
if (nat_oar != NULL)
vfree(nat_oar);
#endif
return error;
}
@ -1380,6 +1652,7 @@ end:
/*
* receive from initiator
* HDR*, HASH(3)
*/
int
quick_r3recv(iph2, msg0)

View File

@ -1,6 +1,6 @@
/* $NetBSD: pfkey.c,v 1.24 2007/11/09 16:27:58 vanhu Exp $ */
/* $NetBSD: pfkey.c,v 1.25 2007/12/12 04:46:00 mgrooms Exp $ */
/* $Id: pfkey.c,v 1.24 2007/11/09 16:27:58 vanhu Exp $ */
/* $Id: pfkey.c,v 1.25 2007/12/12 04:46:00 mgrooms Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -1109,7 +1109,7 @@ pk_sendupdate(iph2)
sa_args.l_natt_type = iph2->ph1->natt_options->encaps_type;
sa_args.l_natt_sport = extract_port (iph2->ph1->remote);
sa_args.l_natt_dport = extract_port (iph2->ph1->local);
sa_args.l_natt_oa = NULL; // FIXME: Here comes OA!!!
sa_args.l_natt_oa = iph2->natoa_src;
#ifdef SADB_X_EXT_NAT_T_FRAG
sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag;
#endif
@ -1398,7 +1398,7 @@ pk_sendadd(iph2)
sa_args.l_natt_type = UDP_ENCAP_ESPINUDP;
sa_args.l_natt_sport = extract_port(iph2->ph1->local);
sa_args.l_natt_dport = extract_port(iph2->ph1->remote);
sa_args.l_natt_oa = NULL; // FIXME: Here comes OA!!!
sa_args.l_natt_oa = iph2->natoa_dst;
#ifdef SADB_X_EXT_NAT_T_FRAG
sa_args.l_natt_frag = iph2->ph1->rmconf->esp_frag;
#endif