]> git.saurik.com Git - apple/network_cmds.git/blobdiff - racoon.tproj/isakmp_agg.c
network_cmds-245.19.tar.gz
[apple/network_cmds.git] / racoon.tproj / isakmp_agg.c
index bc6e377079abff7e2217d23420a56e4e09c783a8..2f1ebc56b4dd85043f2696fceff0eb554ef520f4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $KAME: isakmp_agg.c,v 1.54 2001/12/11 20:33:41 sakane Exp $     */
+/*     $KAME: isakmp_agg.c,v 1.55 2001/12/12 15:29:13 sakane Exp $     */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -48,6 +48,7 @@
 #  include <time.h>
 # endif
 #endif
+#include <netinet/in.h>
 
 #include "var.h"
 #include "misc.h"
@@ -68,6 +69,7 @@
 #include "pfkey.h"
 #include "isakmp_agg.h"
 #include "isakmp_inf.h"
+#include "isakmp_natd.h"
 #include "vendorid.h"
 #include "strnames.h"
 
@@ -97,6 +99,10 @@ agg_i1send(iph1, msg)
        int tlen;
        int need_cr = 0;
        vchar_t *cr = NULL, *gsstoken = NULL;
+       vchar_t *vid_natt_rfc = NULL;
+       vchar_t *vid_natt_apple = NULL;
+       vchar_t *vid_natt_02 = NULL;
+       vchar_t *vid_natt_02N = NULL;
        int error = -1;
        int nptype;
 #ifdef HAVE_GSSAPI
@@ -144,6 +150,23 @@ agg_i1send(iph1, msg)
        iph1->nonce = eay_set_random(iph1->rmconf->nonce_size);
        if (iph1->nonce == NULL)
                goto end;
+       
+#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;
+       }
+               
+#endif
 
 #ifdef HAVE_SIGNING_C
        /* create CR if need */
@@ -176,6 +199,12 @@ agg_i1send(iph1, msg)
                tlen += sizeof (*gen) + len;
        }
 #endif
+       if (vid_natt_rfc) {
+               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;
+       }
 
        iph1->sendbuf = vmalloc(tlen);
        if (iph1->sendbuf == NULL) {
@@ -208,7 +237,7 @@ agg_i1send(iph1, msg)
        if (need_cr)
                nptype = ISAKMP_NPTYPE_CR;
        else
-               nptype = ISAKMP_NPTYPE_NONE;
+               nptype = vid_natt_rfc ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE;
 
        p = set_isakmp_payload(p, iph1->id, nptype);
 
@@ -216,12 +245,19 @@ agg_i1send(iph1, msg)
        if (iph1->rmconf->proposal->authmethod ==
            OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) {
                gssapi_get_token_to_send(iph1, &gsstoken);
-               p = set_isakmp_payload(p, gsstoken, ISAKMP_NPTYPE_NONE);
+               p = set_isakmp_payload(p, gsstoken, vid_natt_rfc ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE);
        } else
 #endif
        if (need_cr)
                /* create isakmp CR payload */
-               p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE);
+               p = set_isakmp_payload(p, cr, 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);
@@ -241,6 +277,14 @@ end:
                vfree(cr);
        if (gsstoken)
                vfree(gsstoken);
+       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;
 }
@@ -328,7 +372,20 @@ agg_i2recv(iph1, msg)
                        break;
 #endif
                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;
                case ISAKMP_NPTYPE_N:
                        isakmp_check_notify(pa->ptr, iph1);
@@ -340,6 +397,15 @@ agg_i2recv(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:
+                       /*
+                        * ignored for now, we need to know the hash
+                        * algorithm before we can evaluate the natd
+                        * payload.
+                        */
+                       break;
                default:
                        /* don't send information, see isakmp_ident_r1() */
                        plog(LLV_ERROR, LOCATION, iph1->remote,
@@ -350,8 +416,15 @@ agg_i2recv(iph1, msg)
                }
        }
 
+       /* if natt vid(s) received - select type to use */
+       natt_select_type(iph1);
+       
        /* payload existency check */
-       /* XXX to be checked each authentication method. */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "required payloads missing from isakmp message.\n");
+               goto end;
+       }
 
        /* verify identifier */
        if (ipsecdoi_checkid1(iph1) != 0) {
@@ -375,6 +448,25 @@ agg_i2recv(iph1, msg)
        /* fix isakmp index */
        memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck,
                sizeof(cookie_t));
+       
+       
+#ifdef IKE_NAT_T
+
+       /* check natd payloads */       
+       for (pa = (struct isakmp_parse_t *)pbuf->v;
+            pa->type != ISAKMP_NPTYPE_NONE;
+            pa++)
+       {
+               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
 
        /* compute sharing secret of DH */
        if (oakley_dh_compute(iph1->rmconf->dhgrp, iph1->dhpub,
@@ -390,6 +482,24 @@ agg_i2recv(iph1, msg)
                goto end;
        if (oakley_newiv(iph1) < 0)
                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
 
        /* validate authentication value */
     {
@@ -452,11 +562,12 @@ agg_i2send(iph1, msg)
        vchar_t *msg;
 {
        struct isakmp_gen *gen;
-       char *p;
+       char *p = NULL;
        int tlen;
        int need_cert = 0;
        int error = -1;
        vchar_t *gsshash = NULL;
+       int natd_type = 0;
 
        /* validity check */
        if (iph1->status != PHASE1ST_MSG2RECEIVED) {
@@ -479,6 +590,17 @@ agg_i2send(iph1, msg)
 
        tlen = sizeof(struct isakmp);
 
+#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
+
        switch (iph1->approval->authmethod) {
        case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
                tlen += sizeof(*gen) + iph1->hash->l;
@@ -496,7 +618,9 @@ agg_i2send(iph1, msg)
                        goto end;
 
                /* set HASH payload */
-               p = set_isakmp_payload(p, iph1->hash, ISAKMP_NPTYPE_NONE);
+               p = set_isakmp_payload(p, iph1->hash,
+                       natd_type ? natd_type
+                               : ISAKMP_NPTYPE_NONE);
                break;
 #ifdef HAVE_SIGNING_C
        case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
@@ -534,7 +658,9 @@ agg_i2send(iph1, msg)
                if (need_cert)
                        p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG);
                /* add SIG payload */
-               p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE);
+               p = set_isakmp_payload(p, iph1->sig,
+                       natd_type ? natd_type
+                               : ISAKMP_NPTYPE_NONE);
                break;
 #endif
        case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
@@ -563,11 +689,29 @@ agg_i2send(iph1, msg)
                p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_HASH);
                if (p == NULL)
                        goto end;
-               p = set_isakmp_payload(p, gsshash, ISAKMP_NPTYPE_NONE);
+               p = set_isakmp_payload(p, gsshash,
+                       natd_type ? natd_type
+                               : ISAKMP_NPTYPE_NONE);
                break;
 #endif
        }
 
+#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
+
 #ifdef HAVE_PRINT_ISAKMP_C
        isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0);
 #endif
@@ -664,7 +808,20 @@ agg_r1recv(iph1, msg)
                                goto end;
                        break;
                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;
 #ifdef HAVE_SIGNING_C
                case ISAKMP_NPTYPE_CR:
@@ -690,7 +847,11 @@ agg_r1recv(iph1, msg)
        }
 
        /* payload existency check */
-       /* XXX to be checked each authentication method. */
+       if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) {
+               plog(LLV_ERROR, LOCATION, iph1->remote,
+                       "required payloads missing from isakmp message.\n");
+               goto end;
+       }
 
        /* verify identifier */
        if (ipsecdoi_checkid1(iph1) != 0) {
@@ -707,6 +868,11 @@ agg_r1recv(iph1, msg)
                goto end;
        }
 
+#ifdef IKE_NAT_T
+       /* if natt vid(s) received - select type to use */
+       natt_select_type(iph1);
+#endif
+
 #ifdef HAVE_SIGNING_C
        if (oakley_checkcr(iph1) < 0) {
                /* Ignore this error in order to be interoperability. */
@@ -747,7 +913,7 @@ agg_r1send(iph1, msg)
        vchar_t *msg;
 {
        struct isakmp_gen *gen;
-       char *p;
+       char *p = NULL;
        int tlen;
        int need_cr = 0;
        int need_cert = 0;
@@ -759,6 +925,7 @@ agg_r1send(iph1, msg)
        vchar_t *gsstoken = NULL, *gsshash = NULL;
        vchar_t *gss_sa = NULL;
 #endif
+       vchar_t *nattvid = NULL;
 
        /* validity check */
        if (iph1->status != PHASE1ST_MSG1RECEIVED) {
@@ -834,6 +1001,30 @@ agg_r1send(iph1, msg)
 
        tlen = sizeof(struct isakmp);
 
+#ifdef IKE_NAT_T
+       if ((iph1->natt_flags & NATT_TYPE_MASK) != 0) {
+               int vid_type;
+               int natt_type = iph1->natt_flags & NATT_TYPE_MASK;
+               if (natt_type == natt_type_rfc)
+                       vid_type = VENDORID_NATT_RFC;
+               else if (natt_type == natt_type_apple)
+                       vid_type = VENDORID_NATT_APPLE;
+               else if (natt_type == natt_type_02)
+                       vid_type = VENDORID_NATT_02;
+               else
+                       vid_type = VENDORID_NATT_02N;
+               nattvid = set_vendorid(vid_type);                       
+               natd_create(iph1);
+               if (nattvid) {
+                       tlen += sizeof(*gen) + nattvid->l;
+                       if (iph1->local_natd)
+                               tlen += sizeof(*gen) + iph1->local_natd->l;
+                       if (iph1->remote_natd)
+                               tlen += sizeof(*gen) + iph1->remote_natd->l;
+               }
+       }
+#endif
+
        switch (iph1->approval->authmethod) {
        case OAKLEY_ATTR_AUTH_METHOD_PSKEY:
                /* create buffer to send isakmp payload */
@@ -875,17 +1066,21 @@ agg_r1send(iph1, msg)
                p = set_isakmp_payload(p, iph1->hash,
                        vid ? ISAKMP_NPTYPE_VID
                            : (need_cr ? ISAKMP_NPTYPE_CR
-                                      : ISAKMP_NPTYPE_NONE));
+                                      : (nattvid ? ISAKMP_NPTYPE_VID
+                                               : ISAKMP_NPTYPE_NONE)));
 
                /* append vendor id, if needed */
                if (vid)
                        p = set_isakmp_payload(p, vid,
                                need_cr ? ISAKMP_NPTYPE_CR
-                                       : ISAKMP_NPTYPE_NONE);
+                                       : (nattvid ? ISAKMP_NPTYPE_VID
+                                               : 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,
+                               nattvid ? ISAKMP_NPTYPE_VID
+                                       : ISAKMP_NPTYPE_NONE);
                break;
 #ifdef HAVE_SIGNING_C
        case OAKLEY_ATTR_AUTH_METHOD_DSSSIG:
@@ -952,11 +1147,31 @@ agg_r1send(iph1, msg)
                if (vid)
                        p = set_isakmp_payload(p, vid,
                                need_cr ? ISAKMP_NPTYPE_CR
-                                       : ISAKMP_NPTYPE_NONE);
+                                       : (nattvid ? ISAKMP_NPTYPE_VID
+                                               : 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,
+                               nattvid ? ISAKMP_NPTYPE_VID
+                                       : ISAKMP_NPTYPE_NONE);
+
+#ifdef IKE_NAT_T
+               if (nattvid) {
+                       p = set_isakmp_payload(p, nattvid, iph1->natd_payload_type);
+                       if ((iph1->natt_flags & NATT_TYPE_MASK) == natt_type_apple) {
+                               if (iph1->local_natd)
+                                       p = set_isakmp_payload(p, iph1->local_natd, iph1->natd_payload_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, iph1->natd_payload_type);
+                               if (iph1->local_natd)
+                                       p = set_isakmp_payload(p, iph1->local_natd, ISAKMP_NPTYPE_NONE);
+                       }
+               }
+#endif
                break;
 #endif
        case OAKLEY_ATTR_AUTH_METHOD_RSAENC:
@@ -1023,15 +1238,34 @@ agg_r1send(iph1, msg)
 
                /* create isakmp HASH payload */
                p = set_isakmp_payload(p, gsshash,
-                   vid != NULL ? ISAKMP_NPTYPE_VID
+                   vid != NULL || nattvid != NULL ? ISAKMP_NPTYPE_VID
                                : ISAKMP_NPTYPE_NONE);
 
                /* append vendor id, if needed */
                if (vid)
-                       p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE);
+                       p = set_isakmp_payload(p, vid,
+                               nattvid != NULL ? ISAKMP_NPTYPE_VID
+                                       : ISAKMP_NPTYPE_NONE);
                break;
 #endif
        }
+       
+#ifdef IKE_NAT_T
+       if (nattvid) {
+               p = set_isakmp_payload(p, nattvid, iph1->natd_payload_type);
+               if ((iph1->natt_flags & NATT_TYPE_MASK) == natt_type_apple) {
+                       if (iph1->local_natd)
+                               p = set_isakmp_payload(p, iph1->local_natd, iph1->natd_payload_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, iph1->natd_payload_type);
+                       if (iph1->local_natd)
+                               p = set_isakmp_payload(p, iph1->local_natd, ISAKMP_NPTYPE_NONE);
+               }               
+       }
+#endif
 
 
 #ifdef HAVE_PRINT_ISAKMP_C
@@ -1059,6 +1293,8 @@ end:
                vfree(cr);
        if (vid)
                vfree(vid);
+       if (nattvid)
+               vfree(nattvid);
 #ifdef HAVE_GSSAPI
        if (gsstoken)
                vfree(gsstoken);
@@ -1137,6 +1373,20 @@ agg_r2recv(iph1, msg0)
                case ISAKMP_NPTYPE_N:
                        isakmp_check_notify(pa->ptr, iph1);
                        break;
+               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 isakmp_ident_r1() */
                        plog(LLV_ERROR, LOCATION, iph1->remote,