-/* $Id: isakmp_quick.c,v 1.13.2.7 2005/07/20 08:02:05 vanhu Exp $ */
+/* $NetBSD: isakmp_quick.c,v 1.11.4.1 2007/08/01 11:52:21 vanhu Exp $ */
+
+/* Id: isakmp_quick.c,v 1.29 2006/08/22 18:17:17 manubsd Exp */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
# include <time.h>
# endif
#endif
+#ifdef ENABLE_HYBRID
+#include <resolv.h>
+#endif
#ifndef HAVE_NETINET6_IPSEC
#include <netinet/ipsec.h>
#include "localconf.h"
#include "remoteconf.h"
+#include "handler.h"
+#include "policy.h"
+#include "proposal.h"
#include "isakmp_var.h"
#include "isakmp.h"
#include "isakmp_inf.h"
#include "isakmp_quick.h"
#include "oakley.h"
-#include "handler.h"
#include "ipsec_doi.h"
#include "crypto_openssl.h"
#include "pfkey.h"
#include "admin.h"
#include "strnames.h"
#include "nattraversal.h"
+#include "ipsecSessionTracer.h"
+#include "ipsecMessageTracer.h"
+#ifndef HAVE_OPENSSL
+#include <Security/SecDH.h>
+#endif
/* quick mode */
static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *));
static int get_sainfo_r __P((struct ph2handle *));
static int get_proposal_r __P((struct ph2handle *));
+static int get_proposal_r_remote __P((struct ph2handle *, int));
/* \f%%%
* Quick Mode
}
iph2->msgid = isakmp_newmsgid2(iph2->ph1);
+ if (iph2->ivm != NULL)
+ oakley_delivm(iph2->ivm);
iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid);
if (iph2->ivm == NULL)
return 0;
}
/* send getspi message */
- if (pk_sendgetspi(iph2) < 0)
+ if (pk_sendgetspi(iph2) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send getspi message");
goto end;
+ }
plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
/*
* 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)
{
vchar_t *body = NULL;
vchar_t *hash = NULL;
+#ifdef ENABLE_NATT
vchar_t *natoa_i = NULL;
vchar_t *natoa_r = NULL;
+#endif /* ENABLE_NATT */
int natoa_type = 0;
struct isakmp_gen *gen;
char *p;
}
/* create SA payload for my proposal */
- if (ipsecdoi_setph2proposal(iph2) < 0)
+ if (ipsecdoi_setph2proposal(iph2) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to set proposal");
goto end;
+ }
/* generate NONCE value */
iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
- if (iph2->nonce == NULL)
+ if (iph2->nonce == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to generate NONCE");
goto end;
+ }
/*
* DH value calculation is kicked out into cfparse.y.
"failed to set DH value.\n");
goto end;
}
+#ifdef HAVE_OPENSSL
if (oakley_dh_generate(iph2->pfsgrp,
- &iph2->dhpub, &iph2->dhpriv) < 0) {
+ &iph2->dhpub, &iph2->dhpriv) < 0) {
+#else
+ if (oakley_dh_generate(iph2->pfsgrp,
+ &iph2->dhpub, &iph2->publicKeySize, &iph2->dhC) < 0) {
+#endif
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to generate DH");
goto end;
}
}
"failed to get ID.\n");
goto end;
}
- plog(LLV_DEBUG, LOCATION, NULL, "IDci:");
+ plog(LLV_DEBUG, LOCATION, NULL, "IDci:\n");
plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l);
- plog(LLV_DEBUG, LOCATION, NULL, "IDcr:");
+ plog(LLV_DEBUG, LOCATION, NULL, "IDcr:\n");
plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l);
/*
if (idcr)
tlen += sizeof(*gen) + iph2->id_p->l;
-#ifdef NOT_NOW
#ifdef ENABLE_NATT
- /*
- * create natoa payloads if needed but only
- * if transport mode proposals are present
+ /*
+ * RFC3947 5.2. if we propose UDP-Encapsulated-Transport
+ * we should send NAT-OA
*/
- if (ipsecdoi_tunnelmode(iph2) != 1) {
+ if (ipsecdoi_any_transportmode(iph2->proposal)
+ && (iph2->ph1->natt_flags & NAT_DETECTED)) {
natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r);
- if (natoa_type == -1)
+ if (natoa_type == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to generate NAT-OA payload.\n");
goto end;
- else if (natoa_type != 0) {
+ } else if (natoa_type != 0) {
tlen += sizeof(*gen) + natoa_i->l;
tlen += sizeof(*gen) + natoa_r->l;
+
+ plog(LLV_DEBUG, LOCATION, NULL, "initiator send NAT-OAi:\n");
+ plogdump(LLV_DEBUG, natoa_i->v, natoa_i->l);
+ plog(LLV_DEBUG, LOCATION, NULL, "initiator send NAT-OAr:\n");
+ plogdump(LLV_DEBUG, natoa_r->v, natoa_r->l);
}
}
-#endif
#endif
body = vmalloc(tlen);
else if (idci || idcr)
np = ISAKMP_NPTYPE_ID;
else
-#ifdef NOT_NOW
np = (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
-#else
- np = ISAKMP_NPTYPE_NONE;
-#endif
p = set_isakmp_payload(p, iph2->nonce, np);
/* add KE payload if need. */
-#ifdef NOT_NOW
np = (idci || idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
-#else
- np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
-#endif
if (pfsgroup)
p = set_isakmp_payload(p, iph2->dhpub, np);
/* IDci */
-#ifdef NOT_NOW
np = (idcr) ? ISAKMP_NPTYPE_ID : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
-#else
- np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE;
-#endif
if (idci)
p = set_isakmp_payload(p, iph2->id, np);
/* IDcr */
if (idcr)
-#ifdef NOT_NOW
p = set_isakmp_payload(p, iph2->id_p, natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
/* natoa */
p = set_isakmp_payload(p, natoa_i, natoa_type);
p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE);
}
-#else
- p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE);
-#endif
/* generate HASH(1) */
hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body);
- if (hash == NULL)
+ if (hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH");
goto end;
+ }
/* send isakmp payload */
iph2->sendbuf = quick_ir1mx(iph2, body, hash);
- if (iph2->sendbuf == NULL)
+ if (iph2->sendbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to get send buffer");
goto end;
+ }
/* send the packet, add to the schedule to resend */
iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
- if (isakmp_ph2resend(iph2) == -1)
+ if (isakmp_ph2resend(iph2) == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send packet");
goto end;
+ }
/* change status of isakmp status entry */
iph2->status = PHASE2ST_MSG1SENT;
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+ CONSTSTR("Initiator, Quick-Mode message 1"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL,
+ CONSTSTR("Initiator, Quick-Mode Message 1"),
+ CONSTSTR("Failed to transmit Quick-Mode Message 1"));
+ }
if (body != NULL)
vfree(body);
if (hash != NULL)
vfree(hash);
-#ifdef NOT_NOW
+#ifdef ENABLE_NATT
if (natoa_i)
vfree(natoa_i);
if (natoa_r)
vfree(natoa_r);
-#endif
+#endif /* ENABLE_NATT */
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)
char *p;
int tlen;
int error = ISAKMP_INTERNAL_ERROR;
+ struct sockaddr *natoa_i = NULL;
+ struct sockaddr *natoa_r = NULL;
/* validity check */
if (iph2->status != PHASE2ST_MSG1SENT) {
goto end;
}
msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
- if (msg == NULL)
+ if (msg == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to decrypt");
goto end;
+ }
/* create buffer for validating HASH(2) */
/*
* 3. two IDs must be considered as IDci, then IDcr
*/
pbuf = isakmp_parse(msg);
- if (pbuf == NULL)
+ if (pbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to parse msg");
goto end;
+ }
pa = (struct isakmp_parse_t *)pbuf->v;
/* HASH payload is fixed postion */
/* allocate buffer for computing HASH(2) */
tlen = iph2->nonce->l
+ ntohl(isakmp->len) - sizeof(*isakmp);
+ if (tlen < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "invalid length (%d,%d) while getting hash buffer.\n",
+ iph2->nonce->l, ntohl(isakmp->len));
+ goto end;
+ }
hbuf = vmalloc(tlen);
if (hbuf == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
"isn't supported.\n");
break;
}
- if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process SA payload");
goto end;
+ }
break;
case ISAKMP_NPTYPE_NONCE:
- if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process NONCE payload");
goto end;
+ }
break;
case ISAKMP_NPTYPE_KE:
- if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process KE payload");
goto end;
+ }
break;
case ISAKMP_NPTYPE_ID:
{
- vchar_t *vp;
-
- /* check ID value */
- if (f_id == 0) {
- /* for IDci */
- f_id = 1;
- vp = iph2->id;
- } else {
- /* for IDcr */
- vp = iph2->id_p;
- }
-
- /* These ids may not match when natt is used with some devices.
- * RFC 2407 says that the protocol and port fields should be ignored
- * if they are zero, therefore they need to be checked individually.
- */
- struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v;
- struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr;
-
- if (id_ptr->type != idp_ptr->b.type
- || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id)
- || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port)
- || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id),
- vp->l - sizeof(struct ipsecdoi_id_b))) {
- //%%% BUG_FIX - to support some servers
- if (iph2->ph1->natt_flags & NAT_DETECTED) {
- plog(LLV_WARNING, LOCATION, NULL,
- "mismatched ID was returned - ignored because nat traversal is being used.\n");
- break;
+ vchar_t *vp;
+
+ /* check ID value */
+ if (f_id == 0) {
+ /* for IDci */
+ vp = iph2->id;
+ } else {
+ /* for IDcr */
+ vp = iph2->id_p;
}
- plog(LLV_ERROR, LOCATION, NULL,
- "mismatched ID was returned.\n");
- error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
- goto end;
+
+ /* These ids may not match when natt is used with some devices.
+ * RFC 2407 says that the protocol and port fields should be ignored
+ * if they are zero, therefore they need to be checked individually.
+ */
+ struct ipsecdoi_id_b *id_ptr = (struct ipsecdoi_id_b *)vp->v;
+ struct ipsecdoi_pl_id *idp_ptr = (struct ipsecdoi_pl_id *)pa->ptr;
+
+ if (id_ptr->type != idp_ptr->b.type
+ || (idp_ptr->b.proto_id != 0 && idp_ptr->b.proto_id != id_ptr->proto_id)
+ || (idp_ptr->b.port != 0 && idp_ptr->b.port != id_ptr->port)
+ || memcmp(vp->v + sizeof(struct ipsecdoi_id_b), (caddr_t)pa->ptr + sizeof(struct ipsecdoi_pl_id),
+ vp->l - sizeof(struct ipsecdoi_id_b))) {
+ // to support servers that use our external nat address as our ID
+ if (iph2->ph1->natt_flags & NAT_DETECTED) {
+ plog(LLV_WARNING, LOCATION, NULL,
+ "mismatched ID was returned - ignored because nat traversal is being used.\n");
+ /* If I'm behind a nat and the ID is type address - save the address
+ * and port for when the peer rekeys.
+ */
+ if (f_id == 0 && (iph2->ph1->natt_flags & NAT_DETECTED_ME)) {
+ if (lcconf->ext_nat_id)
+ vfree(lcconf->ext_nat_id);
+ if (idp_ptr->h.len < sizeof(struct isakmp_gen)) {
+ plog(LLV_ERROR, LOCATION, NULL, "invalid length (%d) while allocating external nat id.\n", idp_ptr->h.len);
+ goto end;
+ }
+ lcconf->ext_nat_id = vmalloc(ntohs(idp_ptr->h.len) - sizeof(struct isakmp_gen));
+ if (lcconf->ext_nat_id == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "memory error while allocating external nat id.\n");
+ goto end;
+ }
+ memcpy(lcconf->ext_nat_id->v, &(idp_ptr->b), lcconf->ext_nat_id->l);
+ if (iph2->ext_nat_id)
+ vfree(iph2->ext_nat_id);
+ iph2->ext_nat_id = vdup(lcconf->ext_nat_id);
+ if (iph2->ext_nat_id == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "memory error while allocating ph2's external nat id.\n");
+ goto end;
+ }
+ plog(LLV_DEBUG, LOCATION, NULL, "external nat address saved.\n");
+ plogdump(LLV_DEBUG, iph2->ext_nat_id->v, iph2->ext_nat_id->l);
+ } else if (f_id && (iph2->ph1->natt_flags & NAT_DETECTED_PEER)) {
+ if (iph2->ext_nat_id_p)
+ vfree(iph2->ext_nat_id_p);
+ iph2->ext_nat_id_p = vmalloc(ntohs(idp_ptr->h.len) - sizeof(struct isakmp_gen));
+ if (iph2->ext_nat_id_p == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL, "memory error while allocating peers ph2's external nat id.\n");
+ goto end;
+ }
+ memcpy(iph2->ext_nat_id_p->v, &(idp_ptr->b), iph2->ext_nat_id_p->l);
+ plog(LLV_DEBUG, LOCATION, NULL, "peer's external nat address saved.\n");
+ plogdump(LLV_DEBUG, iph2->ext_nat_id_p->v, iph2->ext_nat_id_p->l);
+ }
+ } else {
+ plog(LLV_ERROR, LOCATION, NULL, "mismatched ID was returned.\n");
+ error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED;
+ goto end;
+ }
}
+ if (f_id == 0)
+ f_id = 1;
}
-
break;
case ISAKMP_NPTYPE_N:
- isakmp_check_notify(pa->ptr, iph2->ph1);
+ isakmp_check_ph2_notify(pa->ptr, iph2);
break;
#ifdef ENABLE_NATT
case ISAKMP_NPTYPE_NATOA_DRAFT:
case ISAKMP_NPTYPE_NATOA_BADDRAFT:
case ISAKMP_NPTYPE_NATOA_RFC:
- /* Ignore original source/destination messages */
+ {
+ vchar_t *vp = NULL;
+ struct sockaddr *daddr;
+
+ isakmp_p2ph(&vp, pa->ptr);
+
+ if (vp) {
+ daddr = process_natoa_payload(vp);
+ if (daddr) {
+ if (natoa_i == NULL) {
+ natoa_i = daddr;
+ plog(LLV_DEBUG, LOCATION, NULL, "initiaor rcvd NAT-OA i: %s\n",
+ saddr2str(natoa_i));
+ } else if (natoa_r == NULL) {
+ natoa_r = daddr;
+ plog(LLV_DEBUG, LOCATION, NULL, "initiator rcvd NAT-OA r: %s\n",
+ saddr2str(natoa_r));
+ } else {
+ racoon_free(daddr);
+ }
+ }
+ vfree(vp);
+ }
+
+ }
break;
#endif
plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
- if (my_hash == NULL)
+ if (my_hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH");
goto end;
+ }
result = memcmp(my_hash->v, r_hash, my_hash->l);
vfree(my_hash);
/* validity check SA payload sent from responder */
if (ipsecdoi_checkph2proposal(iph2) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to validate SA proposal");
error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
goto end;
}
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+ CONSTSTR("Initiator, Quick-Mode message 2"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL,
+ CONSTSTR("Initiator, Quick-Mode Message 2"),
+ CONSTSTR("Failed to process Quick-Mode Message 2 "));
+ }
if (hbuf)
vfree(hbuf);
if (pbuf)
if (msg)
vfree(msg);
+#ifdef ENABLE_NATT
+ if (natoa_i) {
+ racoon_free(natoa_i);
+ }
+ if (natoa_r) {
+ racoon_free(natoa_r);
+ }
+#endif
+
if (error) {
VPTRINIT(iph2->sa_ret);
VPTRINIT(iph2->nonce_p);
char *p = NULL;
int tlen;
int error = ISAKMP_INTERNAL_ERROR;
+ int packet_error = -1;
/* validity check */
if (iph2->status != PHASE2ST_STATUS6) {
hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
vfree(tmp);
- if (hash == NULL)
+ if (hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH");
goto end;
+ }
}
/* create buffer for isakmp payload */
/* create isakmp header */
p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
- if (p == NULL)
+ if (p == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to create ISAKMP header");
goto end;
+ }
/* add HASH(3) payload */
p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE);
/* encoding */
iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
- if (iph2->sendbuf == NULL)
+ if (iph2->sendbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to encrypt packet");
goto end;
+ }
/* if there is commit bit, need resending */
if (ISSET(iph2->flags, ISAKMP_FLAG_C)) {
/* send the packet, add to the schedule to resend */
iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
- if (isakmp_ph2resend(iph2) == -1)
+ if (isakmp_ph2resend(iph2) == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send packet, commit-bit");
goto end;
+ }
} else {
/* send the packet */
- if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0)
+ if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send packet");
goto end;
+ }
}
/* the sending message is added to the received-list. */
if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local,
- iph2->sendbuf, msg0) == -1) {
+ iph2->sendbuf, msg0,
+ PH2_NON_ESP_EXTRA_LEN(iph2), PH2_FRAG_FLAGS(iph2)) == -1) {
plog(LLV_ERROR , LOCATION, NULL,
"failed to add a response packet to the tree.\n");
goto end;
}
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+ CONSTSTR("Initiator, Quick-Mode message 3"),
+ CONSTSTR(NULL));
+ packet_error = 0;
+
/* compute both of KEYMATs */
- if (oakley_compute_keymat(iph2, INITIATOR) < 0)
+ if (oakley_compute_keymat(iph2, INITIATOR) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute KEYMAT");
goto end;
+ }
iph2->status = PHASE2ST_ADDSA;
error = 0;
end:
+ if (packet_error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL,
+ CONSTSTR("Initiator, Quick-Mode Message 3"),
+ CONSTSTR("Failed to transmit Quick-Mode Message 3"));
+ }
if (buf != NULL)
vfree(buf);
if (msg != NULL)
struct isakmp_pl_hash *hash = NULL;
vchar_t *notify = NULL;
int error = ISAKMP_INTERNAL_ERROR;
+ int packet_error = -1;
/* validity check */
if (iph2->status != PHASE2ST_COMMIT) {
goto end;
}
msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
- if (msg == NULL)
+ if (msg == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to decrypt packet\n");
goto end;
+ }
/* validate the type of next payload */
pbuf = isakmp_parse(msg);
- if (pbuf == NULL)
+ if (pbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to parse msg\n");
goto end;
+ }
for (pa = (struct isakmp_parse_t *)pbuf->v;
pa->type != ISAKMP_NPTYPE_NONE;
hash = (struct isakmp_pl_hash *)pa->ptr;
break;
case ISAKMP_NPTYPE_N:
- isakmp_check_notify(pa->ptr, iph2->ph1);
+ if (notify != NULL) {
+ plog(LLV_WARNING, LOCATION, NULL,
+ "Ignoring multiple notifications\n");
+ break;
+ }
+ isakmp_check_ph2_notify(pa->ptr, iph2);
notify = vmalloc(pa->len);
if (notify == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
vfree(tmp);
- if (my_hash == NULL)
+ if (my_hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH\n");
goto end;
+ }
result = memcmp(my_hash->v, r_hash, my_hash->l);
vfree(my_hash);
}
}
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+ CONSTSTR("Initiator, Quick-Mode message 4"),
+ CONSTSTR(NULL));
+ packet_error = 0;
+
iph2->status = PHASE2ST_ADDSA;
iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */
error = 0;
end:
+ if (packet_error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL,
+ CONSTSTR("Initiator, Quick-Mode Message 4"),
+ CONSTSTR("Failed to process Quick-Mode Message 4"));
+ }
if (msg != NULL)
vfree(msg);
if (pbuf != NULL)
/*
* 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)
int tlen;
int f_id_order; /* for ID payload detection */
int error = ISAKMP_INTERNAL_ERROR;
+ struct sockaddr *natoa_i = NULL;
+ struct sockaddr *natoa_r = NULL;
/* validity check */
if (iph2->status != PHASE2ST_START) {
}
/* decrypt packet */
msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
- if (msg == NULL)
+ if (msg == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to decrypt packet\n");
goto end;
+ }
/* create buffer for using to validate HASH(1) */
/*
* 3. two IDs must be considered as IDci, then IDcr
*/
pbuf = isakmp_parse(msg);
- if (pbuf == NULL)
+ if (pbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to parse msg\n");
goto end;
+ }
pa = (struct isakmp_parse_t *)pbuf->v;
/* HASH payload is fixed postion */
/* allocate buffer for computing HASH(1) */
tlen = ntohl(isakmp->len) - sizeof(*isakmp);
+ if (tlen < 0) {
+ plog(LLV_ERROR, LOCATION, NULL, "invalid length (%d) while extracting hash.\n",
+ ntohl(isakmp->len));
+ goto end;
+ }
hbuf = vmalloc(tlen);
if (hbuf == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
"Multi SAs isn't supported.\n");
goto end;
}
- if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process SA payload\n");
goto end;
+ }
break;
case ISAKMP_NPTYPE_NONCE:
- if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process NONCE payload\n");
goto end;
+ }
break;
case ISAKMP_NPTYPE_KE:
- if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process KE payload\n");
goto end;
+ }
break;
case ISAKMP_NPTYPE_ID:
/* for IDci */
f_id_order++;
- if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process IDci2 payload\n");
goto end;
+ }
} else if (iph2->id == NULL) {
/* for IDcr */
/* XXX we allowed in this case. */
}
- if (isakmp_p2ph(&iph2->id, pa->ptr) < 0)
+ if (isakmp_p2ph(&iph2->id, pa->ptr) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to process IDcr2 payload\n");
goto end;
+ }
} else {
plog(LLV_ERROR, LOCATION, NULL,
"received too many ID payloads.\n");
break;
case ISAKMP_NPTYPE_N:
- isakmp_check_notify(pa->ptr, iph2->ph1);
+ isakmp_check_ph2_notify(pa->ptr, iph2);
break;
#ifdef ENABLE_NATT
case ISAKMP_NPTYPE_NATOA_DRAFT:
case ISAKMP_NPTYPE_NATOA_BADDRAFT:
case ISAKMP_NPTYPE_NATOA_RFC:
- /* Ignore original source/destination messages */
+ {
+ vchar_t *vp = NULL;
+ struct sockaddr *daddr;
+
+ isakmp_p2ph(&vp, pa->ptr);
+
+ if (vp) {
+ daddr = process_natoa_payload(vp);
+ if (daddr) {
+ if (natoa_i == NULL) {
+ natoa_i = daddr;
+ plog(LLV_DEBUG, LOCATION, NULL, "responder rcvd NAT-OA i: %s\n",
+ saddr2str(natoa_i));
+ } else if (natoa_r == NULL) {
+ natoa_r = daddr;
+ plog(LLV_DEBUG, LOCATION, NULL, "responder rcvd NAT-OA r: %s\n",
+ saddr2str(natoa_r));
+ } else {
+ racoon_free(daddr);
+ }
+ }
+ vfree(vp);
+ }
+
+ }
break;
#endif
plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
- if (my_hash == NULL)
+ if (my_hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH\n");
goto end;
+ }
result = memcmp(my_hash->v, r_hash, my_hash->l);
vfree(my_hash);
goto end;
}
- /* check the existence of ID payload and create responder's proposal */
+ /* check the existence of ID payload and create responder's proposal */
error = get_proposal_r(iph2);
switch (error) {
case -2:
case 0:
/* select single proposal or reject it. */
if (ipsecdoi_selectph2proposal(iph2) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to select proposal.\n");
error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
goto end;
}
goto end;
}
+ ike_session_update_mode(iph2); /* update the mode, now that we have a proposal */
+
/*
* save the packet from the initiator in order to resend the
* responder's first packet against this packet.
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+ CONSTSTR("Responder, Quick-Mode message 1"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL,
+ CONSTSTR("Responder, Quick-Mode Message 1"),
+ CONSTSTR("Failed to process Quick-Mode Message 1"));
+ }
if (hbuf)
vfree(hbuf);
if (msg)
if (pbuf)
vfree(pbuf);
+#ifdef ENABLE_NATT
+ if (natoa_i) {
+ racoon_free(natoa_i);
+ }
+ if (natoa_r) {
+ racoon_free(natoa_r);
+ }
+#endif
+
if (error) {
VPTRINIT(iph2->sa);
VPTRINIT(iph2->nonce_p);
iph2->status = PHASE2ST_GETSPISENT;
/* send getspi message */
- if (pk_sendgetspi(iph2) < 0)
+ if (pk_sendgetspi(iph2) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send getspi");
goto end;
+ }
plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
/*
* 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)
vchar_t *natoa_i = NULL;
vchar_t *natoa_r = NULL;
int natoa_type = 0;
- int encmode;
struct isakmp_gen *gen;
char *p;
int tlen;
/* generate NONCE value */
iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
- if (iph2->nonce == NULL)
+ if (iph2->nonce == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to generate NONCE");
goto end;
+ }
/* generate KE value if need */
pfsgroup = iph2->approval->pfs_group;
goto end;
}
/* generate DH public value */
+#ifdef HAVE_OPENSSL
if (oakley_dh_generate(iph2->pfsgrp,
&iph2->dhpub, &iph2->dhpriv) < 0) {
+#else
+ if (oakley_dh_generate(iph2->pfsgrp,
+ &iph2->dhpub, &iph2->publicKeySize, &iph2->dhC) < 0) {
+#endif
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to generate DH public");
goto end;
}
}
tlen += (sizeof(*gen) + iph2->id_p->l
+ sizeof(*gen) + iph2->id->l);
-#ifdef NOT_NOW
#ifdef ENABLE_NATT
- /* create natoa payloads if needed */
- encmode = iph2->approval->head->encmode;
- if (encmode == IPSECDOI_ATTR_ENC_MODE_TRNS ||
- encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_RFC ||
- encmode == IPSECDOI_ATTR_ENC_MODE_UDPTRNS_DRAFT) {
-
+ /*
+ * RFC3947 5.2. if we chose UDP-Encapsulated-Transport
+ * we should send NAT-OA
+ */
+ if (ipsecdoi_any_transportmode(iph2->approval)
+ && (iph2->ph1->natt_flags & NAT_DETECTED)) {
natoa_type = create_natoa_payloads(iph2, &natoa_i, &natoa_r);
- if (natoa_type == -1)
+ if (natoa_type == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to create NATOA payloads");
goto end;
+ }
else if (natoa_type != 0) {
tlen += sizeof(*gen) + natoa_i->l;
tlen += sizeof(*gen) + natoa_r->l;
+
+ plog(LLV_DEBUG, LOCATION, NULL, "responder send NAT-OAi:\n");
+ plogdump(LLV_DEBUG, natoa_i->v, natoa_i->l);
+ plog(LLV_DEBUG, LOCATION, NULL, "responder send NAT-OAr:\n");
+ plogdump(LLV_DEBUG, natoa_r->v, natoa_r->l);
}
}
#endif
-#endif
+ plog(LLV_DEBUG, LOCATION, NULL, "Approved SA\n");
+ printsaprop0(LLV_DEBUG, iph2->approval);
body = vmalloc(tlen);
if (body == NULL) {
? ISAKMP_NPTYPE_KE
: (iph2->id_p != NULL
? ISAKMP_NPTYPE_ID
-#ifdef NOT_NOW
: (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)));
-#else
- : ISAKMP_NPTYPE_ID));
-#endif
/* 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)
-#ifdef NOT_NOW
- ? (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)
-#else
- ? ISAKMP_NPTYPE_NONE
-#endif
- : ISAKMP_NPTYPE_ID);
+ (iph2->id_p == NULL) ? (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE) : ISAKMP_NPTYPE_ID);
}
/* add ID payloads received. */
if (iph2->id_p != NULL) {
/* IDci */
p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID);
+ plog(LLV_DEBUG, LOCATION, NULL, "sending IDci2:\n");
+ plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l);
/* IDcr */
np_p = &((struct isakmp_gen *)p)->np; /* XXX */
-#ifdef NOT_NOW
p = set_isakmp_payload(p, iph2->id, (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE));
-#else
- p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE);
-#endif
+ plog(LLV_DEBUG, LOCATION, NULL, "sending IDcr2:\n");
+ plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l);
}
/* add a RESPONDER-LIFETIME notify payload if needed */
u_int32_t v = htonl((u_int32_t)pp->lifetime);
data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE,
IPSECDOI_ATTR_SA_LD_TYPE_SEC);
- if (!data)
+ if (!data) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to add RESPONDER-LIFETIME notify (type) payload");
goto end;
+ }
data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
(caddr_t)&v, sizeof(v));
- if (!data)
+ if (!data) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to add RESPONDER-LIFETIME notify (value) payload");
goto end;
+ }
}
if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_KB) {
u_int32_t v = htonl((u_int32_t)pp->lifebyte);
data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE,
IPSECDOI_ATTR_SA_LD_TYPE_KB);
- if (!data)
+ if (!data) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to add RESPONDER-LIFETIME notify (type) payload");
goto end;
+ }
data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
(caddr_t)&v, sizeof(v));
- if (!data)
+ if (!data) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to add RESPONDER-LIFETIME notify (value) payload");
goto end;
+ }
}
/*
body = isakmp_add_pl_n(body, &np_p,
ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data);
if (!body) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "invalid RESPONDER-LIFETIME payload");
vfree(data);
return error; /* XXX */
}
}
}
-#ifdef NOT_NOW
/* natoa */
if (natoa_type) {
p = set_isakmp_payload(p, natoa_i, natoa_type);
p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE);
}
-#endif
/* generate HASH(2) */
{
hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp);
vfree(tmp);
- if (hash == NULL)
+ if (hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH");
goto end;
}
+ }
/* send isakmp payload */
iph2->sendbuf = quick_ir1mx(iph2, body, hash);
- if (iph2->sendbuf == NULL)
+ if (iph2->sendbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to get send buffer");
goto end;
+ }
/* send the packet, add to the schedule to resend */
iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
- if (isakmp_ph2resend(iph2) == -1)
+ if (isakmp_ph2resend(iph2) == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send packet");
goto end;
+ }
/* the sending message is added to the received-list. */
- if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1) == -1) {
+ if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1,
+ PH2_NON_ESP_EXTRA_LEN(iph2), PH2_FRAG_FLAGS(iph2)) == -1) {
plog(LLV_ERROR , LOCATION, NULL,
"failed to add a response packet to the tree.\n");
goto end;
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+ CONSTSTR("Responder, Quick-Mode message 2"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL,
+ CONSTSTR("Responder, Quick-Mode Message 2"),
+ CONSTSTR("Failed to transmit Quick-Mode Message 2"));
+ }
if (body != NULL)
vfree(body);
if (hash != NULL)
vfree(hash);
-#ifdef NOT_NOW
if (natoa_i)
vfree(natoa_i);
if (natoa_r)
vfree(natoa_r);
-#endif
return error;
}
goto end;
}
msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
- if (msg == NULL)
+ if (msg == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to decrypt packet\n");
goto end;
+ }
/* validate the type of next payload */
pbuf = isakmp_parse(msg);
- if (pbuf == NULL)
+ if (pbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to parse msg\n");
goto end;
+ }
for (pa = (struct isakmp_parse_t *)pbuf->v;
pa->type != ISAKMP_NPTYPE_NONE;
hash = (struct isakmp_pl_hash *)pa->ptr;
break;
case ISAKMP_NPTYPE_N:
- isakmp_check_notify(pa->ptr, iph2->ph1);
+ isakmp_check_ph2_notify(pa->ptr, iph2);
break;
default:
/* don't send information, see ident_r1recv() */
my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
vfree(tmp);
- if (my_hash == NULL)
+ if (my_hash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH\n");
goto end;
+ }
result = memcmp(my_hash->v, r_hash, my_hash->l);
vfree(my_hash);
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+ CONSTSTR("Responder, Quick-Mode message 3"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL,
+ CONSTSTR("Responder, Quick-Mode Message 3"),
+ CONSTSTR("Failed to process Quick-Mode Message 3"));
+ }
if (pbuf != NULL)
vfree(pbuf);
if (msg != NULL)
memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize);
myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
- if (myhash == NULL)
+ if (myhash == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute HASH");
goto end;
+ }
/* create buffer for isakmp payload */
tlen = sizeof(struct isakmp)
/* create isakmp header */
p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
- if (p == NULL)
+ if (p == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to set ISAKMP header");
goto end;
+ }
/* add HASH(4) payload */
p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N);
/* encoding */
iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
- if (iph2->sendbuf == NULL)
+ if (iph2->sendbuf == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to encrypt packet");
goto end;
+ }
/* send the packet */
- if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0)
+ if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to send packet");
goto end;
+ }
/* the sending message is added to the received-list. */
- if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0) == -1) {
+ if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0,
+ PH2_NON_ESP_EXTRA_LEN(iph2), PH2_FRAG_FLAGS(iph2)) == -1) {
plog(LLV_ERROR , LOCATION, NULL,
"failed to add a response packet to the tree.\n");
goto end;
error = 0;
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+ CONSTSTR("Responder, Quick-Mode message 4"),
+ CONSTSTR(NULL));
+
end:
+ if (error) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL,
+ CONSTSTR("Responder, Quick-Mode Message 4"),
+ CONSTSTR("Failed to transmit Quick-Mode Message 4"));
+ }
if (buf != NULL)
vfree(buf);
if (myhash != NULL)
return error;
}
+
/*
* set SA to kernel.
*/
}
/* compute both of KEYMATs */
- if (oakley_compute_keymat(iph2, RESPONDER) < 0)
+ if (oakley_compute_keymat(iph2, RESPONDER) < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to compute KEYMAT");
goto end;
+ }
iph2->status = PHASE2ST_ADDSA;
iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */
/* set isakmp header */
p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
- if (p == NULL)
+ if (p == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to set ISAKMP header");
goto end;
+ }
/* add HASH payload */
/* XXX is next type always SA ? */
/* encoding */
new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
- if (new == NULL)
+ if (new == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to encrypt packet");
goto end;
+ }
vfree(buf);
vchar_t *idsrc = NULL, *iddst = NULL;
int prefixlen;
int error = ISAKMP_INTERNAL_ERROR;
+ struct sainfo *anonymous = NULL;
- if (iph2->id_p == NULL) {
+ if (iph2->id == NULL) {
switch (iph2->src->sa_family) {
case AF_INET:
prefixlen = sizeof(struct in_addr) << 3;
goto end;
}
- if (iph2->id == NULL) {
+ if (iph2->id_p == NULL) {
switch (iph2->dst->sa_family) {
case AF_INET:
prefixlen = sizeof(struct in_addr) << 3;
goto end;
}
- iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p);
+ iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, 0);
+ // track anonymous sainfo, because we'll try to find a better sainfo if this is a client
+ if (iph2->sainfo && iph2->sainfo->idsrc == NULL)
+ anonymous = iph2->sainfo;
+
+ if (iph2->sainfo == NULL ||
+ (anonymous && iph2->parent_session && iph2->parent_session->is_client)) {
+ if ((iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL)
+ iph2->sainfo = getsainfo(idsrc, iddst, iph2->ph1->id_p, 1);
+ if (iph2->sainfo) {
+ plog(LLV_DEBUG2, LOCATION, NULL,
+ "get_sainfo_r case 1.\n");
+ }
+ // still no sainfo (or anonymous): for client, fallback to sainfo used by a previous established phase2
+ if (iph2->sainfo == NULL ||
+ (iph2->sainfo->idsrc == NULL && iph2->parent_session && iph2->parent_session->is_client)) {
+ ike_session_get_sainfo_r(iph2);
+ if (iph2->sainfo) {
+ plog(LLV_DEBUG2, LOCATION, NULL,
+ "get_sainfo_r case 2.\n");
+ }
+ // still no sainfo (or anonymous): fallback to sainfo picked by dst id
+ if ((iph2->sainfo == NULL || iph2->sainfo->idsrc == NULL) && iph2->id_p) {
+ plog(LLV_DEBUG2, LOCATION, NULL,
+ "get_sainfo_r about to try dst id only.\n");
+ iph2->sainfo = getsainfo_by_dst_id(iph2->id_p, iph2->ph1->id_p);
+ if (iph2->sainfo) {
+ plog(LLV_DEBUG2, LOCATION, NULL,
+ "get_sainfo_r case 3.\n");
+ if (iph2->sainfo->idsrc == NULL)
+ anonymous = iph2->sainfo;
+ }
+ }
+ }
+ }
if (iph2->sainfo == NULL) {
+ if (anonymous == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to get sainfo.\n");
+ goto end;
+ }
+ iph2->sainfo = anonymous;
+ }
+ if (link_sainfo_to_ph2(iph2->sainfo) != 0) {
plog(LLV_ERROR, LOCATION, NULL,
- "failed to get sainfo.\n");
+ "failed to link sainfo\n");
+ iph2->sainfo = NULL;
goto end;
}
+
+#ifdef ENABLE_HYBRID
+ /* xauth group inclusion check */
+ if (iph2->sainfo->group != NULL)
+ if(group_check(iph2->ph1,&iph2->sainfo->group->v,1)) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to group check");
+ goto end;
+ }
+#endif
plog(LLV_DEBUG, LOCATION, NULL,
- "get sa info: %s\n", sainfo2str(iph2->sainfo));
+ "selected sainfo: %s\n", sainfo2str(iph2->sainfo));
error = 0;
end:
return error;
}
+static int
+get_proposal_r(iph2)
+ struct ph2handle *iph2;
+{
+ int error = get_proposal_r_remote(iph2, 0);
+ if (error != -2 && error != 0 &&
+ (((iph2->ph1->natt_flags & NAT_DETECTED_ME) && lcconf->ext_nat_id != NULL) ||
+ (iph2->parent_session && iph2->parent_session->is_client))) {
+ if (iph2->parent_session && iph2->parent_session->is_client)
+ error = ike_session_get_proposal_r(iph2);
+ if (error != -2 && error != 0)
+ error = get_proposal_r_remote(iph2, 1);
+ }
+ return error;
+}
+
/*
* Copy both IP addresses in ID payloads into [src,dst]_id if both ID types
* are IP address and same address family.
* NOTE: This function is only for responder.
*/
static int
-get_proposal_r(iph2)
+get_proposal_r_remote(iph2, ignore_id)
struct ph2handle *iph2;
+ int ignore_id;
{
struct policyindex spidx;
struct secpolicy *sp_in, *sp_out;
int idi2type = 0; /* switch whether copy IDs into id[src,dst]. */
int error = ISAKMP_INTERNAL_ERROR;
+ int generated_policy_exit_early = 1;
/* check the existence of ID payload */
if ((iph2->id_p != NULL && iph2->id == NULL)
return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
}
- /* make sure if id[src,dst] is null. */
- if (iph2->src_id || iph2->dst_id) {
+ /* make sure if id[src,dst] is null (if use_remote_addr == 0). */
+ if (!ignore_id && (iph2->src_id || iph2->dst_id)) {
plog(LLV_ERROR, LOCATION, NULL,
"Why do ID[src,dst] exist already.\n");
return ISAKMP_INTERNAL_ERROR;
}
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s: ignore_id %x.\n", __FUNCTION__, ignore_id);
+
memset(&spidx, 0, sizeof(spidx));
#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
/*
* make destination address in spidx from either ID payload
* or phase 1 address into a address in spidx.
+ * If behind a nat - use phase1 address because server's
+ * use the nat's address in the ID payload.
*/
if (iph2->id != NULL
+ && ignore_id == 0
&& (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
|| _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR
|| _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET
memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src));
switch (spidx.dst.ss_family) {
case AF_INET:
- spidx.prefd = sizeof(struct in_addr) << 3;
+ {
+ struct sockaddr_in *s = (struct sockaddr_in *)&spidx.dst;
+ spidx.prefd = sizeof(struct in_addr) << 3;
+ s->sin_port = htons(0);
+ }
break;
#ifdef INET6
case AF_INET6:
/* make source address in spidx */
if (iph2->id_p != NULL
+ && ignore_id == 0
&& (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR
|| _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR
|| _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET
if (_XIDT(iph2->id_p) == idi2type
&& spidx.dst.ss_family == spidx.src.ss_family) {
iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst);
+ if (iph2->src_id == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "buffer allocation failed.\n");
+ return ISAKMP_INTERNAL_ERROR;
+ }
iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src);
+ if (iph2->dst_id == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "buffer allocation failed.\n");
+ return ISAKMP_INTERNAL_ERROR;
+ }
}
} else {
memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
switch (spidx.src.ss_family) {
case AF_INET:
- spidx.prefs = sizeof(struct in_addr) << 3;
+ {
+ struct sockaddr_in *s = (struct sockaddr_in *)&spidx.src;
+ spidx.prefs = sizeof(struct in_addr) << 3;
+ s->sin_port = htons(0);
+ }
break;
#ifdef INET6
case AF_INET6:
spidx.ul_proto = IPSEC_ULPROTO_ANY;
/* get inbound policy */
- sp_in = getsp_r(&spidx);
+ sp_in = getsp_r(&spidx, iph2);
if (sp_in == NULL || sp_in->policy == IPSEC_POLICY_GENERATE) {
if (iph2->ph1->rmconf->gen_policy) {
- plog(LLV_INFO, LOCATION, NULL,
- "no policy found, "
- "try to generate the policy : %s\n",
- spidx2str(&spidx));
+ if (sp_in)
+ plog(LLV_INFO, LOCATION, NULL,
+ "Update the generated policy : %s\n",
+ spidx2str(&spidx));
+ else
+ plog(LLV_INFO, LOCATION, NULL,
+ "no policy found, "
+ "try to generate the policy : %s\n",
+ spidx2str(&spidx));
iph2->spidx_gen = racoon_malloc(sizeof(spidx));
if (!iph2->spidx_gen) {
- plog(LLV_ERROR, LOCATION, NULL,
- "buffer allocation failed.\n");
+ plog(LLV_ERROR, LOCATION, NULL,
+ "buffer allocation failed.\n");
return ISAKMP_INTERNAL_ERROR;
}
memcpy(iph2->spidx_gen, &spidx, sizeof(spidx));
- return -2; /* special value */
- }
- plog(LLV_ERROR, LOCATION, NULL,
- "no policy found: %s\n", spidx2str(&spidx));
- return ISAKMP_INTERNAL_ERROR;
- }
- /* Refresh existing generated policies
- */
- if (iph2->ph1->rmconf->gen_policy) {
- plog(LLV_INFO, LOCATION, NULL,
- "Update the generated policy : %s\n",
- spidx2str(&spidx));
- iph2->spidx_gen = racoon_malloc(sizeof(spidx));
- if (!iph2->spidx_gen) {
- plog(LLV_ERROR, LOCATION, NULL,
- "buffer allocation failed.\n");
+ generated_policy_exit_early = 1; /* special value */
+ } else {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "no policy found: %s\n", spidx2str(&spidx));
return ISAKMP_INTERNAL_ERROR;
}
- memcpy(iph2->spidx_gen, &spidx, sizeof(spidx));
}
-
+
/* get outbound policy */
{
struct sockaddr_storage addr;
spidx.prefs = spidx.prefd;
spidx.prefd = pref;
- sp_out = getsp_r(&spidx);
+ sp_out = getsp_r(&spidx, iph2);
if (!sp_out) {
plog(LLV_WARNING, LOCATION, NULL,
"no outbound policy found: %s\n",
spidx2str(&spidx));
+ } else {
+
+ if (!iph2->spid) {
+ iph2->spid = sp_out->id;
+ }
}
}
plog(LLV_DEBUG, LOCATION, NULL,
"suitable SP found:%s\n", spidx2str(&spidx));
+ if (generated_policy_exit_early) {
+ return -2;
+ }
+
/*
* In the responder side, the inbound policy should be using IPsec.
* outbound policy is not checked currently.