]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/isakmp_quick.c
ipsec-146.3.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / isakmp_quick.c
index fc3c2594f326bd10a48054b76e17e3adc3053591..a734abb686909f4c8f1faa0b8b915b7dbb6c718d 100644 (file)
@@ -1,4 +1,6 @@
-/* $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.
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -51,6 +53,9 @@
 #  include <time.h>
 # endif
 #endif
 #  include <time.h>
 # endif
 #endif
+#ifdef ENABLE_HYBRID
+#include <resolv.h>
+#endif
 
 #ifndef HAVE_NETINET6_IPSEC
 #include <netinet/ipsec.h>
 
 #ifndef HAVE_NETINET6_IPSEC
 #include <netinet/ipsec.h>
 
 #include "localconf.h"
 #include "remoteconf.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 "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 "ipsec_doi.h"
 #include "crypto_openssl.h"
 #include "pfkey.h"
 #include "admin.h"
 #include "strnames.h"
 #include "nattraversal.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 *));
 
 /* 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
 
 /* \f%%%
  * Quick Mode
@@ -111,6 +124,8 @@ quick_i1prep(iph2, msg)
        }
 
        iph2->msgid = isakmp_newmsgid2(iph2->ph1);
        }
 
        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;
        iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid);
        if (iph2->ivm == NULL)
                return 0;
@@ -124,8 +139,11 @@ quick_i1prep(iph2, msg)
        }
 
        /* send getspi message */
        }
 
        /* 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;
                goto end;
+       }
 
        plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
 
        plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
@@ -140,7 +158,7 @@ end:
 
 /*
  * send to responder
 
 /*
  * 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)
  */
 int
 quick_i1send(iph2, msg)
@@ -149,8 +167,10 @@ quick_i1send(iph2, msg)
 {
        vchar_t *body = NULL;
        vchar_t *hash = NULL;
 {
        vchar_t *body = NULL;
        vchar_t *hash = NULL;
+#ifdef ENABLE_NATT     
        vchar_t *natoa_i = NULL;
        vchar_t *natoa_r = NULL;
        vchar_t *natoa_i = NULL;
        vchar_t *natoa_r = NULL;
+#endif /* ENABLE_NATT */
        int             natoa_type = 0;
        struct isakmp_gen *gen;
        char *p;
        int             natoa_type = 0;
        struct isakmp_gen *gen;
        char *p;
@@ -173,13 +193,19 @@ quick_i1send(iph2, msg)
        }
 
        /* create SA payload for my proposal */
        }
 
        /* 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;
                goto end;
+       }
 
        /* generate NONCE value */
        iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
 
        /* 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;
                goto end;
+       }
 
        /*
         * DH value calculation is kicked out into cfparse.y.
 
        /*
         * DH value calculation is kicked out into cfparse.y.
@@ -195,8 +221,15 @@ quick_i1send(iph2, msg)
                                "failed to set DH value.\n");
                        goto end;
                }
                                "failed to set DH value.\n");
                        goto end;
                }
+#ifdef HAVE_OPENSSL
                if (oakley_dh_generate(iph2->pfsgrp,
                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;
                }
        }
                        goto end;
                }
        }
@@ -207,9 +240,9 @@ quick_i1send(iph2, msg)
                        "failed to get ID.\n");
                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);
        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);
 
        /*
        plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l);
 
        /*
@@ -239,22 +272,28 @@ quick_i1send(iph2, msg)
        if (idcr)
                tlen += sizeof(*gen) + iph2->id_p->l;
 
        if (idcr)
                tlen += sizeof(*gen) + iph2->id_p->l;
 
-#ifdef NOT_NOW
 #ifdef ENABLE_NATT     
 #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);
                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;
                        goto end;
-               else if (natoa_type != 0) {
+               else if (natoa_type != 0) {
                        tlen += sizeof(*gen) + natoa_i->l;
                        tlen += sizeof(*gen) + natoa_r->l;
                        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);
 #endif
 
        body = vmalloc(tlen);
@@ -275,34 +314,21 @@ quick_i1send(iph2, msg)
        else if (idci || idcr)
                np = ISAKMP_NPTYPE_ID;
        else
        else if (idci || idcr)
                np = ISAKMP_NPTYPE_ID;
        else
-#ifdef NOT_NOW
                np = (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
                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. */
        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);
        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 */
        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);
        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)
        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, iph2->id_p, natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE);
                
        /* natoa */
@@ -310,48 +336,65 @@ quick_i1send(iph2, msg)
                p = set_isakmp_payload(p, natoa_i, natoa_type);
                p = set_isakmp_payload(p, natoa_r, ISAKMP_NPTYPE_NONE);
        }
                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);
 
        /* 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;
                goto end;
+       }
 
        /* send isakmp payload */
        iph2->sendbuf = quick_ir1mx(iph2, body, hash);
 
        /* 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;
                goto end;
+       }
 
        /* send the packet, add to the schedule to resend */
        iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
 
        /* 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;
                goto end;
+       }
 
        /* change status of isakmp status entry */
        iph2->status = PHASE2ST_MSG1SENT;
 
        error = 0;
 
 
        /* 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:
 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);
        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);
        if (natoa_i)
                vfree(natoa_i);
        if (natoa_r)
                vfree(natoa_r);
-#endif
+#endif /* ENABLE_NATT */
 
        return error;
 }
 
 /*
  * receive from responder
 
        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)
  */
 int
 quick_i2recv(iph2, msg0)
@@ -368,6 +411,8 @@ quick_i2recv(iph2, msg0)
        char *p;
        int tlen;
        int error = ISAKMP_INTERNAL_ERROR;
        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) {
 
        /* validity check */
        if (iph2->status != PHASE2ST_MSG1SENT) {
@@ -383,8 +428,11 @@ quick_i2recv(iph2, msg0)
                goto end;
        }
        msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
                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;
                goto end;
+       }
 
        /* create buffer for validating HASH(2) */
        /*
 
        /* create buffer for validating HASH(2) */
        /*
@@ -394,8 +442,11 @@ quick_i2recv(iph2, msg0)
         *      3. two IDs must be considered as IDci, then IDcr
         */
        pbuf = isakmp_parse(msg);
         *      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;
                goto end;
+       }
        pa = (struct isakmp_parse_t *)pbuf->v;
 
        /* HASH payload is fixed postion */
        pa = (struct isakmp_parse_t *)pbuf->v;
 
        /* HASH payload is fixed postion */
@@ -425,6 +476,12 @@ quick_i2recv(iph2, msg0)
        /* allocate buffer for computing HASH(2) */
        tlen = iph2->nonce->l
                + ntohl(isakmp->len) - sizeof(*isakmp);
        /* 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,
        hbuf = vmalloc(tlen);
        if (hbuf == NULL) {
                plog(LLV_ERROR, LOCATION, NULL,
@@ -454,70 +511,139 @@ quick_i2recv(iph2, msg0)
                                        "isn't supported.\n");
                                break;
                        }
                                        "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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_NONCE:
                        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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_KE:
                        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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_ID:
                    {
                        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:
                        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:
                        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
 
                        break;
 #endif
 
@@ -563,8 +689,11 @@ quick_i2recv(iph2, msg0)
        plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
 
        my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
        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;
                goto end;
+       }
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
@@ -579,6 +708,8 @@ quick_i2recv(iph2, msg0)
 
        /* validity check SA payload sent from responder */
        if (ipsecdoi_checkph2proposal(iph2) < 0) {
 
        /* 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 = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
                goto end;
        }
@@ -588,7 +719,18 @@ quick_i2recv(iph2, msg0)
 
        error = 0;
 
 
        error = 0;
 
+       IPSECSESSIONTRACEREVENT(iph2->parent_session,
+                                                       IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+                                                       CONSTSTR("Initiator, Quick-Mode message 2"),
+                                                       CONSTSTR(NULL));
+       
 end:
 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 (hbuf)
                vfree(hbuf);
        if (pbuf)
@@ -596,6 +738,15 @@ end:
        if (msg)
                vfree(msg);
 
        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);
        if (error) {
                VPTRINIT(iph2->sa_ret);
                VPTRINIT(iph2->nonce_p);
@@ -622,6 +773,7 @@ quick_i2send(iph2, msg0)
        char *p = NULL;
        int tlen;
        int error = ISAKMP_INTERNAL_ERROR;
        char *p = NULL;
        int tlen;
        int error = ISAKMP_INTERNAL_ERROR;
+       int packet_error = -1;
 
        /* validity check */
        if (iph2->status != PHASE2ST_STATUS6) {
 
        /* validity check */
        if (iph2->status != PHASE2ST_STATUS6) {
@@ -648,8 +800,11 @@ quick_i2send(iph2, msg0)
        hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
        vfree(tmp);
 
        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;
                goto end;
+       }
     }
 
        /* create buffer for isakmp payload */
     }
 
        /* create buffer for isakmp payload */
@@ -664,8 +819,11 @@ quick_i2send(iph2, msg0)
 
        /* create isakmp header */
        p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
 
        /* 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;
                goto end;
+       }
 
        /* add HASH(3) payload */
        p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE);
 
        /* add HASH(3) payload */
        p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE);
@@ -676,32 +834,51 @@ quick_i2send(iph2, msg0)
 
        /* encoding */
        iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
 
        /* 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;
                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 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;
                        goto end;
+               }
        } else {
                /* send the packet */
        } 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;
                        goto end;
+               }
        }
 
        /* the sending message is added to the received-list. */
        if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local,
        }
 
        /* 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;
        }
 
                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 */
        /* 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;
                goto end;
+       }
 
        iph2->status = PHASE2ST_ADDSA;
 
 
        iph2->status = PHASE2ST_ADDSA;
 
@@ -736,6 +913,12 @@ quick_i2send(iph2, msg0)
        error = 0;
 
 end:
        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)
        if (buf != NULL)
                vfree(buf);
        if (msg != NULL)
@@ -761,6 +944,7 @@ quick_i3recv(iph2, msg0)
        struct isakmp_pl_hash *hash = NULL;
        vchar_t *notify = NULL;
        int error = ISAKMP_INTERNAL_ERROR;
        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) {
 
        /* validity check */
        if (iph2->status != PHASE2ST_COMMIT) {
@@ -776,13 +960,19 @@ quick_i3recv(iph2, msg0)
                goto end;
        }
        msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
                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;
                goto end;
+       }
 
        /* validate the type of next payload */
        pbuf = isakmp_parse(msg);
 
        /* 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;
                goto end;
+       }
 
        for (pa = (struct isakmp_parse_t *)pbuf->v;
             pa->type != ISAKMP_NPTYPE_NONE;
 
        for (pa = (struct isakmp_parse_t *)pbuf->v;
             pa->type != ISAKMP_NPTYPE_NONE;
@@ -793,7 +983,12 @@ quick_i3recv(iph2, msg0)
                        hash = (struct isakmp_pl_hash *)pa->ptr;
                        break;
                case ISAKMP_NPTYPE_N:
                        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,
                        notify = vmalloc(pa->len);
                        if (notify == NULL) {
                                plog(LLV_ERROR, LOCATION, NULL,
@@ -833,8 +1028,11 @@ quick_i3recv(iph2, msg0)
 
        my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
        vfree(tmp);
 
        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;
                goto end;
+       }
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
@@ -847,6 +1045,12 @@ quick_i3recv(iph2, msg0)
        }
     }
 
        }
     }
 
+       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 */
 
        iph2->status = PHASE2ST_ADDSA;
        iph2->flags ^= ISAKMP_FLAG_C;   /* reset bit */
 
@@ -874,6 +1078,12 @@ quick_i3recv(iph2, msg0)
        error = 0;
 
 end:
        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)
        if (msg != NULL)
                vfree(msg);
        if (pbuf != NULL)
@@ -886,7 +1096,7 @@ end:
 
 /*
  * receive from initiator
 
 /*
  * 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
 quick_r1recv(iph2, msg0)
@@ -903,6 +1113,8 @@ quick_r1recv(iph2, msg0)
        int tlen;
        int f_id_order; /* for ID payload detection */
        int error = ISAKMP_INTERNAL_ERROR;
        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) {
 
        /* validity check */
        if (iph2->status != PHASE2ST_START) {
@@ -920,8 +1132,11 @@ quick_r1recv(iph2, msg0)
        }
        /* decrypt packet */
        msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
        }
        /* 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;
                goto end;
+       }
 
        /* create buffer for using to validate HASH(1) */
        /*
 
        /* create buffer for using to validate HASH(1) */
        /*
@@ -931,8 +1146,11 @@ quick_r1recv(iph2, msg0)
         *      3. two IDs must be considered as IDci, then IDcr
         */
        pbuf = isakmp_parse(msg);
         *      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;
                goto end;
+       }
        pa = (struct isakmp_parse_t *)pbuf->v;
 
        /* HASH payload is fixed postion */
        pa = (struct isakmp_parse_t *)pbuf->v;
 
        /* HASH payload is fixed postion */
@@ -963,6 +1181,11 @@ quick_r1recv(iph2, msg0)
 
        /* allocate buffer for computing HASH(1) */
        tlen = ntohl(isakmp->len) - sizeof(*isakmp);
 
        /* 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,
        hbuf = vmalloc(tlen);
        if (hbuf == NULL) {
                plog(LLV_ERROR, LOCATION, NULL,
@@ -1005,18 +1228,27 @@ quick_r1recv(iph2, msg0)
                                        "Multi SAs isn't supported.\n");
                                goto end;
                        }
                                        "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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_NONCE:
                        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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_KE:
                        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;
                                goto end;
+                       }
                        break;
 
                case ISAKMP_NPTYPE_ID:
                        break;
 
                case ISAKMP_NPTYPE_ID:
@@ -1024,8 +1256,11 @@ quick_r1recv(iph2, msg0)
                                /* for IDci */
                                f_id_order++;
 
                                /* 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;
                                        goto end;
+                               }
 
                        } else if (iph2->id == NULL) {
                                /* for IDcr */
 
                        } else if (iph2->id == NULL) {
                                /* for IDcr */
@@ -1037,8 +1272,11 @@ quick_r1recv(iph2, msg0)
                                        /* XXX we allowed in this case. */
                                }
 
                                        /* 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;
                                        goto end;
+                               }
                        } else {
                                plog(LLV_ERROR, LOCATION, NULL,
                                        "received too many ID payloads.\n");
                        } else {
                                plog(LLV_ERROR, LOCATION, NULL,
                                        "received too many ID payloads.\n");
@@ -1049,14 +1287,38 @@ quick_r1recv(iph2, msg0)
                        break;
 
                case ISAKMP_NPTYPE_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:
                        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
 
                        break;
 #endif
 
@@ -1107,8 +1369,11 @@ quick_r1recv(iph2, msg0)
        plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash));
 
        my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf);
        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;
                goto end;
+       }
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
@@ -1129,7 +1394,7 @@ quick_r1recv(iph2, msg0)
                goto end;
        }
 
                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:
        error = get_proposal_r(iph2);
        switch (error) {
        case -2:
@@ -1144,6 +1409,8 @@ quick_r1recv(iph2, msg0)
        case 0:
                /* select single proposal or reject it. */
                if (ipsecdoi_selectph2proposal(iph2) < 0) {
        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;
                }
                        error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN;
                        goto end;
                }
@@ -1168,6 +1435,8 @@ quick_r1recv(iph2, msg0)
                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.
        /*
         * save the packet from the initiator in order to resend the
         * responder's first packet against this packet.
@@ -1179,7 +1448,18 @@ quick_r1recv(iph2, msg0)
 
        error = 0;
 
 
        error = 0;
 
+       IPSECSESSIONTRACEREVENT(iph2->parent_session,
+                                                       IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+                                                       CONSTSTR("Responder, Quick-Mode message 1"),
+                                                       CONSTSTR(NULL));
+       
 end:
 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 (hbuf)
                vfree(hbuf);
        if (msg)
@@ -1187,6 +1467,15 @@ end:
        if (pbuf)
                vfree(pbuf);
 
        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);
        if (error) {
                VPTRINIT(iph2->sa);
                VPTRINIT(iph2->nonce_p);
@@ -1218,8 +1507,11 @@ quick_r1prep(iph2, msg)
        iph2->status = PHASE2ST_GETSPISENT;
 
        /* send getspi message */
        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;
                goto end;
+       }
 
        plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
 
        plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n");
 
@@ -1234,7 +1526,7 @@ end:
 
 /*
  * send to initiator
 
 /*
  * 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)
  */
 int
 quick_r2send(iph2, msg)
@@ -1246,7 +1538,6 @@ quick_r2send(iph2, msg)
        vchar_t *natoa_i = NULL;
        vchar_t *natoa_r = NULL;
        int             natoa_type = 0;
        vchar_t *natoa_i = NULL;
        vchar_t *natoa_r = NULL;
        int             natoa_type = 0;
-       int             encmode;
        struct isakmp_gen *gen;
        char *p;
        int tlen;
        struct isakmp_gen *gen;
        char *p;
        int tlen;
@@ -1274,8 +1565,11 @@ quick_r2send(iph2, msg)
 
        /* generate NONCE value */
        iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size);
 
        /* 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;
                goto end;
+       }
 
        /* generate KE value if need */
        pfsgroup = iph2->approval->pfs_group;
 
        /* generate KE value if need */
        pfsgroup = iph2->approval->pfs_group;
@@ -1287,8 +1581,15 @@ quick_r2send(iph2, msg)
                        goto end;
                }
                /* generate DH public value */
                        goto end;
                }
                /* generate DH public value */
+#ifdef HAVE_OPENSSL
                if (oakley_dh_generate(iph2->pfsgrp,
                                &iph2->dhpub, &iph2->dhpriv) < 0) {
                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;
                }
        }
                        goto end;
                }
        }
@@ -1302,25 +1603,33 @@ quick_r2send(iph2, msg)
                tlen += (sizeof(*gen) + iph2->id_p->l
                        + sizeof(*gen) + iph2->id->l);
 
                tlen += (sizeof(*gen) + iph2->id_p->l
                        + sizeof(*gen) + iph2->id->l);
 
-#ifdef NOT_NOW
 #ifdef ENABLE_NATT
 #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);
                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;
                        goto end;
+               }
                else if (natoa_type != 0) {
                        tlen += sizeof(*gen) + natoa_i->l;
                        tlen += sizeof(*gen) + natoa_r->l;
                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
-#endif
 
 
+       plog(LLV_DEBUG, LOCATION, NULL, "Approved SA\n");
+       printsaprop0(LLV_DEBUG, iph2->approval);
 
        body = vmalloc(tlen);
        if (body == NULL) { 
 
        body = vmalloc(tlen);
        if (body == NULL) { 
@@ -1340,36 +1649,26 @@ quick_r2send(iph2, msg)
                                ? ISAKMP_NPTYPE_KE
                                : (iph2->id_p != NULL
                                        ? ISAKMP_NPTYPE_ID
                                ? ISAKMP_NPTYPE_KE
                                : (iph2->id_p != NULL
                                        ? ISAKMP_NPTYPE_ID
-#ifdef NOT_NOW
                                        : (natoa_type ? natoa_type : ISAKMP_NPTYPE_NONE)));
                                        : (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,
 
        /* 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);
        }
 
        /* 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 */
                /* 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));
                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 */
        }
 
        /* add a RESPONDER-LIFETIME notify payload if needed */
@@ -1382,23 +1681,35 @@ quick_r2send(iph2, msg)
                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);
                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;
                        goto end;
+               }
                data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
                                        (caddr_t)&v, sizeof(v));
                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;
                        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 (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;
                        goto end;
+               }
                data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD,
                                        (caddr_t)&v, sizeof(v));
                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;
                        goto end;
+               }
        }
 
        /*
        }
 
        /*
@@ -1410,6 +1721,8 @@ quick_r2send(iph2, msg)
                        body = isakmp_add_pl_n(body, &np_p,
                                        ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data);
                        if (!body) {
                        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 */
                        }
                                vfree(data);
                                return error;   /* XXX */
                        }
@@ -1418,13 +1731,11 @@ quick_r2send(iph2, msg)
        }
     }
 
        }
     }
 
-#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);
        }
        /* 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) */
     {
 
        /* generate HASH(2) */
     {
@@ -1442,22 +1753,32 @@ quick_r2send(iph2, msg)
        hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp);
        vfree(tmp);
 
        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;
     }
                goto end;
     }
+       }
 
        /* send isakmp payload */
        iph2->sendbuf = quick_ir1mx(iph2, body, hash);
 
        /* 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;
                goto end;
+       }
 
        /* send the packet, add to the schedule to resend */
        iph2->retry_counter = iph2->ph1->rmconf->retry_counter;
 
        /* 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;
                goto end;
+       }
 
        /* the sending message is added to the received-list. */
 
        /* 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;
                plog(LLV_ERROR , LOCATION, NULL,
                        "failed to add a response packet to the tree.\n");
                goto end;
@@ -1468,17 +1789,26 @@ quick_r2send(iph2, msg)
 
        error = 0;
 
 
        error = 0;
 
+       IPSECSESSIONTRACEREVENT(iph2->parent_session,
+                                                       IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+                                                       CONSTSTR("Responder, Quick-Mode message 2"),
+                                                       CONSTSTR(NULL));
+       
 end:
 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);
        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);
        if (natoa_i)
                vfree(natoa_i);
        if (natoa_r)
                vfree(natoa_r);
-#endif
 
        return error;
 }
 
        return error;
 }
@@ -1512,13 +1842,19 @@ quick_r3recv(iph2, msg0)
                goto end;
        }
        msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive);
                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;
                goto end;
+       }
 
        /* validate the type of next payload */
        pbuf = isakmp_parse(msg);
 
        /* 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;
                goto end;
+       }
 
        for (pa = (struct isakmp_parse_t *)pbuf->v;
             pa->type != ISAKMP_NPTYPE_NONE;
 
        for (pa = (struct isakmp_parse_t *)pbuf->v;
             pa->type != ISAKMP_NPTYPE_NONE;
@@ -1529,7 +1865,7 @@ quick_r3recv(iph2, msg0)
                        hash = (struct isakmp_pl_hash *)pa->ptr;
                        break;
                case ISAKMP_NPTYPE_N:
                        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() */
                        break;
                default:
                        /* don't send information, see ident_r1recv() */
@@ -1572,8 +1908,11 @@ quick_r3recv(iph2, msg0)
 
        my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp);
        vfree(tmp);
 
        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;
                goto end;
+       }
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
 
        result = memcmp(my_hash->v, r_hash, my_hash->l);
        vfree(my_hash);
@@ -1594,7 +1933,18 @@ quick_r3recv(iph2, msg0)
 
        error = 0;
 
 
        error = 0;
 
+       IPSECSESSIONTRACEREVENT(iph2->parent_session,
+                                                       IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC,
+                                                       CONSTSTR("Responder, Quick-Mode message 3"),
+                                                       CONSTSTR(NULL));
+       
 end:
 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)
        if (pbuf != NULL)
                vfree(pbuf);
        if (msg != NULL)
@@ -1649,8 +1999,11 @@ quick_r3send(iph2, msg0)
        memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize);
 
        myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify);
        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;
                goto end;
+       }
 
        /* create buffer for isakmp payload */
        tlen = sizeof(struct isakmp)
 
        /* create buffer for isakmp payload */
        tlen = sizeof(struct isakmp)
@@ -1665,8 +2018,11 @@ quick_r3send(iph2, msg0)
 
        /* create isakmp header */
        p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
 
        /* 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;
                goto end;
+       }
 
        /* add HASH(4) payload */
        p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N);
 
        /* add HASH(4) payload */
        p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N);
@@ -1680,15 +2036,22 @@ quick_r3send(iph2, msg0)
 
        /* encoding */
        iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
 
        /* 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;
                goto end;
+       }
 
        /* send the packet */
 
        /* 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;
                goto end;
+       }
 
        /* the sending message is added to the received-list. */
 
        /* 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;
                plog(LLV_ERROR , LOCATION, NULL,
                        "failed to add a response packet to the tree.\n");
                goto end;
@@ -1698,7 +2061,18 @@ quick_r3send(iph2, msg0)
 
        error = 0;
 
 
        error = 0;
 
+       IPSECSESSIONTRACEREVENT(iph2->parent_session,
+                                                       IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC,
+                                                       CONSTSTR("Responder, Quick-Mode message 4"),
+                                                       CONSTSTR(NULL));
+       
 end:
 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)
        if (buf != NULL)
                vfree(buf);
        if (myhash != NULL)
@@ -1709,6 +2083,7 @@ end:
        return error;
 }
 
        return error;
 }
 
+
 /*
  * set SA to kernel.
  */
 /*
  * set SA to kernel.
  */
@@ -1728,8 +2103,11 @@ quick_r3prep(iph2, msg0)
        }
 
        /* compute both of KEYMATs */
        }
 
        /* 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;
                goto end;
+       }
 
        iph2->status = PHASE2ST_ADDSA;
        iph2->flags ^= ISAKMP_FLAG_C;   /* reset bit */
 
        iph2->status = PHASE2ST_ADDSA;
        iph2->flags ^= ISAKMP_FLAG_C;   /* reset bit */
@@ -1859,8 +2237,11 @@ quick_ir1mx(iph2, body, hash)
 
        /* set isakmp header */
        p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH);
 
        /* 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;
                goto end;
+       }
 
        /* add HASH payload */
        /* XXX is next type always SA ? */
 
        /* add HASH payload */
        /* XXX is next type always SA ? */
@@ -1875,8 +2256,11 @@ quick_ir1mx(iph2, body, hash)
 
        /* encoding */
        new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv);
 
        /* 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;
                goto end;
+       }
 
        vfree(buf);
 
 
        vfree(buf);
 
@@ -1904,8 +2288,9 @@ get_sainfo_r(iph2)
        vchar_t *idsrc = NULL, *iddst = NULL;
        int prefixlen;
        int error = ISAKMP_INTERNAL_ERROR;
        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;
                switch (iph2->src->sa_family) {
                case AF_INET:
                        prefixlen = sizeof(struct in_addr) << 3;
@@ -1929,7 +2314,7 @@ get_sainfo_r(iph2)
                goto end;
        }
 
                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;
                switch (iph2->dst->sa_family) {
                case AF_INET:
                        prefixlen = sizeof(struct in_addr) << 3;
@@ -1953,15 +2338,68 @@ get_sainfo_r(iph2)
                goto end;
        }
 
                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 (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,
                plog(LLV_ERROR, LOCATION, NULL,
-                       "failed to get sainfo.\n");
+                        "failed to link sainfo\n");
+               iph2->sainfo = NULL;
                goto end;
        }
                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,
 
        plog(LLV_DEBUG, LOCATION, NULL,
-               "get sa info: %s\n", sainfo2str(iph2->sainfo));
+               "selected sainfo: %s\n", sainfo2str(iph2->sainfo));
 
        error = 0;
 end:
 
        error = 0;
 end:
@@ -1973,6 +2411,22 @@ end:
        return error;
 }
 
        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.
 /*
  * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types
  * are IP address and same address family.
@@ -1984,13 +2438,15 @@ end:
  * NOTE: This function is only for responder.
  */
 static int
  * NOTE: This function is only for responder.
  */
 static int
-get_proposal_r(iph2)
+get_proposal_r_remote(iph2, ignore_id)
        struct ph2handle *iph2;
        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;
 {
        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)
 
        /* check the existence of ID payload */
        if ((iph2->id_p != NULL && iph2->id == NULL)
@@ -2000,13 +2456,16 @@ get_proposal_r(iph2)
                return ISAKMP_NTYPE_INVALID_ID_INFORMATION;
        }
 
                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_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
        memset(&spidx, 0, sizeof(spidx));
 
 #define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type
@@ -2018,8 +2477,11 @@ get_proposal_r(iph2)
        /*
         * make destination address in spidx from either ID payload
         * or phase 1 address into a address in spidx.
        /*
         * 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
         */
        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
         && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR
          || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR
          || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET
@@ -2066,7 +2528,11 @@ get_proposal_r(iph2)
                memcpy(&spidx.dst, iph2->src, sysdep_sa_len(iph2->src));
                switch (spidx.dst.ss_family) {
                case AF_INET:
                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:
                        break;
 #ifdef INET6
                case AF_INET6:
@@ -2081,6 +2547,7 @@ get_proposal_r(iph2)
 
        /* make source address in spidx */
        if (iph2->id_p != NULL
 
        /* 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
         && (_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
@@ -2109,7 +2576,17 @@ get_proposal_r(iph2)
                if (_XIDT(iph2->id_p) == idi2type
                 && spidx.dst.ss_family == spidx.src.ss_family) {
                        iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst);
                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);
                        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 {
                }
 
        } else {
@@ -2123,7 +2600,11 @@ get_proposal_r(iph2)
                memcpy(&spidx.src, iph2->dst, sysdep_sa_len(iph2->dst));
                switch (spidx.src.ss_family) {
                case AF_INET:
                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:
                        break;
 #ifdef INET6
                case AF_INET6:
@@ -2157,41 +2638,33 @@ get_proposal_r(iph2)
                spidx.ul_proto = IPSEC_ULPROTO_ANY;
 
        /* get inbound policy */
                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) {
        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) {
                        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 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;
                }
                        return ISAKMP_INTERNAL_ERROR;
                }
-               memcpy(iph2->spidx_gen, &spidx, sizeof(spidx));
        }
        }
-
+    
        /* get outbound policy */
     {
        struct sockaddr_storage addr;
        /* get outbound policy */
     {
        struct sockaddr_storage addr;
@@ -2205,17 +2678,26 @@ get_proposal_r(iph2)
        spidx.prefs = spidx.prefd;
        spidx.prefd = pref;
 
        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));
        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));
 
        }
     }
 
        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.
        /*
         * In the responder side, the inbound policy should be using IPsec.
         * outbound policy is not checked currently.