-/* $KAME: isakmp_ident.c,v 1.62 2001/12/12 15:29:13 sakane Exp $ */
+/* $KAME: isakmp_ident.c,v 1.63 2001/12/12 17:57:26 sakane Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <netinet/in.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#include "pfkey.h"
#include "isakmp_ident.h"
#include "isakmp_inf.h"
+#include "isakmp_natd.h"
#include "vendorid.h"
#ifdef HAVE_GSSAPI
caddr_t p;
int tlen;
int error = -1;
+ vchar_t *vid_natt_rfc = NULL;
+ vchar_t *vid_natt_apple = NULL;
+ vchar_t *vid_natt_02 = NULL;
+ vchar_t *vid_natt_02N = NULL;
/* validity check */
if (msg != NULL) {
tlen = sizeof(struct isakmp)
+ sizeof(*gen) + iph1->sa->l;
+#ifdef IKE_NAT_T
+ vid_natt_rfc = set_vendorid(VENDORID_NATT_RFC);
+ vid_natt_apple = set_vendorid(VENDORID_NATT_APPLE);
+ vid_natt_02 = set_vendorid(VENDORID_NATT_02);
+ vid_natt_02N = set_vendorid(VENDORID_NATT_02N);
+
+ if (vid_natt_rfc == NULL ||
+ vid_natt_apple == NULL ||
+ vid_natt_02 == NULL ||
+ vid_natt_02N == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to get vendor ID buffer.\n");
+ goto end;
+ }
+ tlen += sizeof(*gen) + vid_natt_rfc->l;
+ tlen += sizeof(*gen) + vid_natt_apple->l;
+ tlen += sizeof(*gen) + vid_natt_02->l;
+ tlen += sizeof(*gen) + vid_natt_02N->l;
+#endif
+
iph1->sendbuf = vmalloc(tlen);
if (iph1->sendbuf == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
goto end;
/* set SA payload to propose */
- p = set_isakmp_payload(p, iph1->sa, ISAKMP_NPTYPE_NONE);
+ p = set_isakmp_payload(p, iph1->sa, vid_natt_rfc ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE);
+
+ if (vid_natt_rfc) {
+ p = set_isakmp_payload(p, vid_natt_rfc, ISAKMP_NPTYPE_VID);
+ p = set_isakmp_payload(p, vid_natt_apple, ISAKMP_NPTYPE_VID);
+ p = set_isakmp_payload(p, vid_natt_02, ISAKMP_NPTYPE_VID);
+ p = set_isakmp_payload(p, vid_natt_02N, ISAKMP_NPTYPE_NONE);
+ }
#ifdef HAVE_PRINT_ISAKMP_C
isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
error = 0;
end:
+ if (vid_natt_rfc)
+ vfree(vid_natt_rfc);
+ if (vid_natt_apple)
+ vfree(vid_natt_apple);
+ if (vid_natt_02)
+ vfree(vid_natt_02);
+ if (vid_natt_02N)
+ vfree(vid_natt_02N);
return error;
}
switch (pa->type) {
case ISAKMP_NPTYPE_VID:
- (void)check_vendorid(pa->ptr);
+#ifdef IKE_NAT_T
+ {
+ int vid = check_vendorid(pa->ptr);
+ if (vid == VENDORID_NATT_RFC)
+ iph1->natt_flags |= natt_type_rfc;
+ else if (vid == VENDORID_NATT_APPLE)
+ iph1->natt_flags |= natt_type_apple;
+ else if (vid == VENDORID_NATT_02)
+ iph1->natt_flags |= natt_type_02;
+ else if (vid == VENDORID_NATT_02N)
+ iph1->natt_flags |= natt_type_02N;
+ }
+#endif
break;
default:
/* don't send information, see ident_r1recv() */
}
}
+ /* if natt vid(s) received - select type to use */
+ natt_select_type(iph1);
+
/* check SA payload and set approval SA for use */
if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) {
plog(LLV_ERROR, LOCATION, iph1->remote,
gssapi_save_received_token(iph1, gsstoken);
break;
#endif
+ case ISAKMP_NPTYPE_NATD_RFC:
+ case ISAKMP_NPTYPE_NATD_DRAFT:
+ case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#ifdef IKE_NAT_T
+
+ if (pa->type == iph1->natd_payload_type) {
+ natd_match_t match = natd_matches(iph1, pa->ptr);
+ iph1->natt_flags |= natt_natd_received;
+ if ((match & natd_match_local) != 0)
+ iph1->natt_flags |= natt_no_local_nat;
+ if ((match & natd_match_remote) != 0)
+ iph1->natt_flags |= natt_no_remote_nat;
+ }
+#endif
+ break;
default:
/* don't send information, see ident_r1recv() */
plog(LLV_ERROR, LOCATION, iph1->remote,
goto end;
}
}
+
+#ifdef IKE_NAT_T
+ /* Determine if we need to switch to port 4500 */
+ if (natd_hasnat(iph1))
+ {
+ /* There is a NAT between us! Switch to port 4500. */
+ if (iph1->remote->sa_family == AF_INET)
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in*)iph1->remote;
+ plog(LLV_INFO, LOCATION, NULL,
+ "detected NAT, switching to port %d for %s",
+ PORT_ISAKMP_NATT, saddr2str(iph1->remote));
+ sin->sin_port = htons(PORT_ISAKMP_NATT);
+ sin = (struct sockaddr_in*)iph1->local;
+ sin->sin_port = htons(PORT_ISAKMP_NATT);
+ }
+ }
+#endif
/* payload existency check */
if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
switch (pa->type) {
case ISAKMP_NPTYPE_VID:
- (void)check_vendorid(pa->ptr);
+ {
+ int vid = check_vendorid(pa->ptr);
+#if IKE_NAT_T
+ if (vid == VENDORID_NATT_RFC)
+ iph1->natt_flags |= natt_type_rfc;
+ else if (vid == VENDORID_NATT_APPLE)
+ iph1->natt_flags |= natt_type_apple;
+ else if (vid == VENDORID_NATT_02)
+ iph1->natt_flags |= natt_type_02;
+ else
+ iph1->natt_flags |= natt_type_02N;
+#endif
+ }
break;
default:
/*
}
}
+ /* if natt vid(s) received - select type to use */
+ natt_select_type(iph1);
+
/* check SA payload and set approval SA for use */
if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) {
plog(LLV_ERROR, LOCATION, iph1->remote,
int error = -1;
vchar_t *gss_sa = NULL;
vchar_t *vid = NULL;
+#ifdef IKE_NAT_T
+ vchar_t *nattvid = NULL;
+#endif
/* validity check */
if (iph1->status != PHASE1ST_MSG1RECEIVED) {
if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL)
tlen += sizeof(*gen) + vid->l;
+#ifdef IKE_NAT_T
+ {
+ int natt_type = iph1->natt_flags & NATT_TYPE_MASK;
+
+ if (natt_type != 0) {
+ if (natt_type == natt_type_rfc)
+ nattvid = set_vendorid(VENDORID_NATT_RFC);
+ else if (natt_type == natt_type_apple)
+ nattvid = set_vendorid(VENDORID_NATT_APPLE);
+ else if (natt_type == natt_type_02)
+ nattvid = set_vendorid(VENDORID_NATT_02);
+ else if (natt_type == natt_type_02N)
+ nattvid = set_vendorid(VENDORID_NATT_02N);
+
+ if (nattvid != NULL)
+ tlen += sizeof(*gen) + nattvid->l;
+ }
+ }
+#endif
+
iph1->sendbuf = vmalloc(tlen);
if (iph1->sendbuf == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
/* set SA payload to reply */
p = set_isakmp_payload(p, gss_sa,
- vid ? ISAKMP_NPTYPE_VID
+ (vid || nattvid) ? ISAKMP_NPTYPE_VID
: ISAKMP_NPTYPE_NONE);
/* Set Vendor ID, if necessary. */
if (vid)
- p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE);
+ p = set_isakmp_payload(p, vid, nattvid ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE);
+
+ if (nattvid)
+ p = set_isakmp_payload(p, nattvid, ISAKMP_NPTYPE_NONE);
#ifdef HAVE_PRINT_ISAKMP_C
isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
#endif
if (vid)
vfree(vid);
+ if (nattvid)
+ vfree(nattvid);
return error;
}
gssapi_save_received_token(iph1, gsstoken);
break;
#endif
+ case ISAKMP_NPTYPE_NATD_RFC:
+ case ISAKMP_NPTYPE_NATD_DRAFT:
+ case ISAKMP_NPTYPE_NATD_BADDRAFT:
+#ifdef IKE_NAT_T
+ if (pa->type == iph1->natd_payload_type) {
+ natd_match_t match = natd_matches(iph1, pa->ptr);
+ iph1->natt_flags |= natt_natd_received;
+ if ((match & natd_match_local) != 0)
+ iph1->natt_flags |= natt_no_local_nat;
+ if ((match & natd_match_remote) != 0)
+ iph1->natt_flags |= natt_no_remote_nat;
+ }
+#endif
+ break;
default:
/* don't send information, see ident_r1recv() */
plog(LLV_ERROR, LOCATION, iph1->remote,
#ifdef HAVE_GSSAPI
vchar_t *gsstoken = NULL;
#endif
+ int natd_type = 0;
#ifdef HAVE_SIGNING_C
/* create CR if need */
tlen += sizeof(*gen) + gsstoken->l;
#endif
+#ifdef IKE_NAT_T
+ if ((iph1->natt_flags & NATT_TYPE_MASK) != 0) {
+ natd_type = iph1->natd_payload_type;
+ natd_create(iph1);
+ if (iph1->local_natd)
+ tlen += sizeof(*gen) + iph1->local_natd->l;
+ if (iph1->remote_natd)
+ tlen += sizeof(*gen) + iph1->remote_natd->l;
+ }
+#endif
+
buf = vmalloc(tlen);
if (buf == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
else
#endif
nptype = vid ? ISAKMP_NPTYPE_VID :
- (need_cr ? ISAKMP_NPTYPE_CR : ISAKMP_NPTYPE_NONE);
+ (need_cr ? ISAKMP_NPTYPE_CR :
+ (natd_type ? natd_type : ISAKMP_NPTYPE_NONE));
p = set_isakmp_payload(p, iph1->nonce, nptype);
#ifdef HAVE_GSSAPI
p = set_isakmp_payload(p, gsstoken,
vid ? ISAKMP_NPTYPE_VID
: (need_cr ? ISAKMP_NPTYPE_CR
- : ISAKMP_NPTYPE_NONE));
+ : (natd_type ? natd_type : ISAKMP_NPTYPE_NONE)));
}
#endif
if (vid)
p = set_isakmp_payload(p, vid,
need_cr ? ISAKMP_NPTYPE_CR
- : ISAKMP_NPTYPE_NONE);
+ : (natd_type ? natd_type : ISAKMP_NPTYPE_NONE));
/* create isakmp CR payload if needed */
if (need_cr)
- p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE);
-
+ p = set_isakmp_payload(p, cr, natd_type ? natd_type : ISAKMP_NPTYPE_NONE);
+
+#ifdef IKE_NAT_T
+ if (natd_type) {
+ if ((iph1->natt_flags & NATT_TYPE_MASK) == natt_type_apple) {
+ if (iph1->local_natd)
+ p = set_isakmp_payload(p, iph1->local_natd, natd_type);
+ if (iph1->remote_natd)
+ p = set_isakmp_payload(p, iph1->remote_natd, ISAKMP_NPTYPE_NONE);
+ } else {
+ if (iph1->remote_natd)
+ p = set_isakmp_payload(p, iph1->remote_natd, natd_type);
+ if (iph1->local_natd)
+ p = set_isakmp_payload(p, iph1->local_natd, ISAKMP_NPTYPE_NONE);
+ }
+ }
+#endif
error = 0;
end: