]> git.saurik.com Git - apple/network_cmds.git/blobdiff - racoon.tproj/isakmp_ident.c
network_cmds-245.19.tar.gz
[apple/network_cmds.git] / racoon.tproj / isakmp_ident.c
index 4e15a4732ca67c59006c628af66cf70d8886786d..e5c46c24ba25878fd514f54f341b77811e6e8a04 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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.
@@ -38,6 +38,7 @@
 #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>
@@ -68,6 +69,7 @@
 #include "pfkey.h"
 #include "isakmp_ident.h"
 #include "isakmp_inf.h"
+#include "isakmp_natd.h"
 #include "vendorid.h"
 
 #ifdef HAVE_GSSAPI
@@ -96,6 +98,10 @@ ident_i1send(iph1, msg)
        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) {
@@ -122,6 +128,26 @@ ident_i1send(iph1, msg)
        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,
@@ -135,7 +161,14 @@ ident_i1send(iph1, msg)
                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);
@@ -151,6 +184,14 @@ ident_i1send(iph1, msg)
        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;
 }
@@ -212,7 +253,19 @@ ident_i2recv(iph1, msg)
 
                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() */
@@ -224,6 +277,9 @@ ident_i2recv(iph1, msg)
                }
        }
 
+       /* 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,
@@ -381,6 +437,21 @@ ident_i3recv(iph1, msg)
                        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,
@@ -390,6 +461,24 @@ ident_i3recv(iph1, msg)
                        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) {
@@ -759,7 +848,19 @@ ident_r1recv(iph1, msg)
 
                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:
                        /*
@@ -777,6 +878,9 @@ ident_r1recv(iph1, msg)
                }
        }
 
+       /* 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,
@@ -817,6 +921,9 @@ ident_r1send(iph1, msg)
        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) {
@@ -842,6 +949,26 @@ ident_r1send(iph1, msg)
        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,
@@ -856,12 +983,15 @@ ident_r1send(iph1, msg)
 
        /* 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);
@@ -890,6 +1020,8 @@ end:
 #endif
        if (vid)
                vfree(vid);
+       if (nattvid)
+               vfree(nattvid);
        return error;
 }
 
@@ -954,6 +1086,20 @@ ident_r2recv(iph1, msg)
                        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,
@@ -1392,6 +1538,7 @@ ident_ir2mx(iph1)
 #ifdef HAVE_GSSAPI
        vchar_t *gsstoken = NULL;
 #endif
+       int natd_type = 0;
 
 #ifdef HAVE_SIGNING_C
        /* create CR if need */
@@ -1427,6 +1574,17 @@ ident_ir2mx(iph1)
                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,
@@ -1449,7 +1607,8 @@ ident_ir2mx(iph1)
        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
@@ -1457,7 +1616,7 @@ ident_ir2mx(iph1)
                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
 
@@ -1465,12 +1624,27 @@ ident_ir2mx(iph1)
        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: