This patch allows racoon to negotiate with the same instance of itself.  This
means that IKE negotiations over local addresses, including localhost, are now
possibile.  The only major change in this patch is to include
side/directionality in the phase-1 and phase-2 SA lookup functions, the other
changes in this patch are either results of this extra search field or some
simple logic to pick the correct SA for a negotiation when two SA exist for the
same IKE cookie pair.

Please be warned that this is a proof of concept patch and has not been
throughly tested or reviewed.  In face, with certain configure flags it may not
even compile.

---
 src/racoon/admin.c        |    4 +-
 src/racoon/handler.c      |   35 ++++++++++++++++----
 src/racoon/handler.h      |   15 ++++----
 src/racoon/isakmp.c       |   80 +++++++++++++++++++++++++++++++++++++++-------
 src/racoon/isakmp.h       |    2 +
 src/racoon/isakmp_inf.c   |    6 +--
 src/racoon/isakmp_xauth.c |    2 -
 7 files changed, 112 insertions(+), 32 deletions(-)

Index: ipsec-tools-0.6.5-6/src/racoon/admin.c
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/admin.c
+++ ipsec-tools-0.6.5-6/src/racoon/admin.c
@@ -289,7 +289,7 @@ admin_process(so2, combuf)
                        break;
                }
 
-               if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
+               if ((iph1 = getph1byaddrwop(src, dst, ANYSIDE)) == NULL) {
                        plog(LLV_ERROR, LOCATION, NULL, 
                            "phase 1 for %s -> %s not found\n", loc, rem);
                } else {
@@ -322,7 +322,7 @@ admin_process(so2, combuf)
                plog(LLV_INFO, LOCATION, NULL, 
                    "Flushing all SAs for peer %s\n", rem);
 
-               while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
+               while ((iph1 = getph1bydstaddrwop(dst, ANYSIDE)) != NULL) {
                        if ((loc = strdup(saddrwop2str(iph1->local))) == NULL) {
                                plog(LLV_ERROR, LOCATION, NULL, 
                                    "cannot allocate memory\n");
Index: ipsec-tools-0.6.5-6/src/racoon/handler.c
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/handler.c
+++ ipsec-tools-0.6.5-6/src/racoon/handler.c
@@ -93,14 +93,17 @@ static void sweep_recvdpkt __P((void *))
 extern caddr_t val2str(const char *, size_t);
 
 struct ph1handle *
-getph1byindex(index)
+getph1byindex(index, side)
        isakmp_index *index;
+       int side;
 {
        struct ph1handle *p;
 
        LIST_FOREACH(p, &ph1tree, chain) {
                if (p->status == PHASE1ST_EXPIRED)
                        continue;
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (memcmp(&p->index, index, sizeof(*index)) == 0)
                        return p;
        }
@@ -112,14 +115,17 @@ getph1byindex(index)
  * search for isakmp handler by i_ck in index.
  */
 struct ph1handle *
-getph1byindex0(index)
+getph1byindex0(index, side)
        isakmp_index *index;
+       int side;
 {
        struct ph1handle *p;
 
        LIST_FOREACH(p, &ph1tree, chain) {
                if (p->status == PHASE1ST_EXPIRED)
                        continue;
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (memcmp(&p->index, index, sizeof(cookie_t)) == 0)
                        return p;
        }
@@ -133,14 +139,17 @@ getph1byindex0(index)
  * with phase 2's destinaion.
  */
 struct ph1handle *
-getph1byaddr(local, remote)
+getph1byaddr(local, remote, side)
        struct sockaddr *local, *remote;
+       int side;
 {
        struct ph1handle *p;
 
        LIST_FOREACH(p, &ph1tree, chain) {
                if (p->status == PHASE1ST_EXPIRED)
                        continue;
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (CMPSADDR(local, p->local) == 0
                 && CMPSADDR(remote, p->remote) == 0)
                        return p;
@@ -150,14 +159,17 @@ getph1byaddr(local, remote)
 }
 
 struct ph1handle *
-getph1byaddrwop(local, remote)
+getph1byaddrwop(local, remote, side)
        struct sockaddr *local, *remote;
+       int side;
 {
        struct ph1handle *p;
 
        LIST_FOREACH(p, &ph1tree, chain) {
                if (p->status == PHASE1ST_EXPIRED)
                        continue;
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (cmpsaddrwop(local, p->local) == 0
                 && cmpsaddrwop(remote, p->remote) == 0)
                        return p;
@@ -172,14 +184,17 @@ getph1byaddrwop(local, remote)
  * with phase 2's destinaion.
  */
 struct ph1handle *
-getph1bydstaddrwop(remote)
+getph1bydstaddrwop(remote, side)
        struct sockaddr *remote;
+       int side;
 {
        struct ph1handle *p;
 
        LIST_FOREACH(p, &ph1tree, chain) {
                if (p->status == PHASE1ST_EXPIRED)
                        continue;
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (cmpsaddrwop(remote, p->remote) == 0)
                        return p;
        }
@@ -444,13 +459,16 @@ getph2byseq(seq)
  * search ph2handle with message id.
  */
 struct ph2handle *
-getph2bymsgid(iph1, msgid)
+getph2bymsgid(iph1, msgid, side)
        struct ph1handle *iph1;
        u_int32_t msgid;
+       int side;
 {
        struct ph2handle *p;
 
        LIST_FOREACH(p, &ph2tree, chain) {
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (p->msgid == msgid)
                        return p;
        }
@@ -476,12 +494,15 @@ getph2byid(src, dst, spid)
 }
 
 struct ph2handle *
-getph2bysaddr(src, dst)
+getph2bysaddr(src, dst, side)
        struct sockaddr *src, *dst;
+       int side;
 {
        struct ph2handle *p;
 
        LIST_FOREACH(p, &ph2tree, chain) {
+               if (p->side != side && side != ANYSIDE)
+                       continue;
                if (cmpsaddrstrict(src, p->src) == 0 &&
                    cmpsaddrstrict(dst, p->dst) == 0)
                        return p;
Index: ipsec-tools-0.6.5-6/src/racoon/handler.h
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/handler.h
+++ ipsec-tools-0.6.5-6/src/racoon/handler.h
@@ -417,13 +417,13 @@ struct ph1handle;
 struct ph2handle;
 struct policyindex;
 
-extern struct ph1handle *getph1byindex __P((isakmp_index *));
-extern struct ph1handle *getph1byindex0 __P((isakmp_index *));
+extern struct ph1handle *getph1byindex __P((isakmp_index *, int));
+extern struct ph1handle *getph1byindex0 __P((isakmp_index *, int));
 extern struct ph1handle *getph1byaddr __P((struct sockaddr *,
-       struct sockaddr *));
+                                          struct sockaddr *, int));
 extern struct ph1handle *getph1byaddrwop __P((struct sockaddr *,
-       struct sockaddr *));
-extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *));
+       struct sockaddr *, int));
+extern struct ph1handle *getph1bydstaddrwop __P((struct sockaddr *, int));
 extern vchar_t *dumpph1 __P((void));
 extern struct ph1handle *newph1 __P((void));
 extern void delph1 __P((struct ph1handle *));
@@ -436,8 +436,9 @@ extern struct ph2handle *getph2byspidx _
 extern struct ph2handle *getph2byspid __P((u_int32_t));
 extern struct ph2handle *getph2byseq __P((u_int32_t));
 extern struct ph2handle *getph2bysaddr __P((struct sockaddr *,
-       struct sockaddr *));
-extern struct ph2handle *getph2bymsgid __P((struct ph1handle *, u_int32_t));
+       struct sockaddr *, int));
+extern struct ph2handle *getph2bymsgid __P((struct ph1handle *, u_int32_t,
+       int));
 extern struct ph2handle *getph2byid __P((struct sockaddr *,
        struct sockaddr *, u_int32_t));
 extern struct ph2handle *getph2bysaidx __P((struct sockaddr *,
Index: ipsec-tools-0.6.5-6/src/racoon/isakmp.c
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/isakmp.c
+++ ipsec-tools-0.6.5-6/src/racoon/isakmp.c
@@ -369,6 +369,34 @@ end:
 }
 
 /*
+ * isakmp phase 1 search helper
+ */
+static struct ph1handle *
+isakmp_ph1pickside(iph1_i, iph1_r, local)
+       struct ph1handle *iph1_i, *iph1_r;
+       struct sockaddr *local;
+{
+       if (iph1_i == NULL && iph1_r != NULL) {
+               if (cmpsaddrstrict(iph1_r->remote, local) != 0)
+                       return iph1_r;
+               else
+                       return NULL;
+       } else if (iph1_i != NULL && iph1_r == NULL) {
+               if (cmpsaddrstrict(iph1_i->remote, local) != 0)
+                       return iph1_i;
+               else
+                       return NULL;
+       } else if (iph1_i != NULL && iph1_r != NULL) {
+               if (iph1_r->status < iph1_i->status)
+                       return iph1_r;
+               else
+                       return iph1_i;
+       }
+
+       return NULL;
+}
+
+/*
  * main processing to handle isakmp payload
  */
 static int
@@ -434,7 +462,9 @@ isakmp_main(msg, remote, local)
                }
        }
 
-       iph1 = getph1byindex(index);
+       iph1 = isakmp_ph1pickside(getph1byindex(index, INITIATOR),
+                                 getph1byindex(index, RESPONDER),
+                                 local);
        if (iph1 != NULL) {
                /* validity check */
                if (memcmp(&isakmp->r_ck, r_ck0, sizeof(cookie_t)) == 0 &&
@@ -516,7 +546,10 @@ isakmp_main(msg, remote, local)
                         */
 
                        /* search for phase1 handle by index without r_ck */
-                       iph1 = getph1byindex0(index);
+                       iph1 = isakmp_ph1pickside(
+                               getph1byindex0(index, INITIATOR),
+                               getph1byindex0(index, RESPONDER),
+                               local);
                        if (iph1 == NULL) {
                                /*it must be the 1st message from a initiator.*/
                                if (memcmp(&isakmp->r_ck, r_ck0,
@@ -592,7 +625,7 @@ isakmp_main(msg, remote, local)
                 * NOTE: We think such informational exchange should be ignored.
                 */
                if (iph1 == NULL) {
-                       iph1 = getph1byindex0(index);
+                       iph1 = getph1byindex0(index, INITIATOR);
                        if (iph1 == NULL) {
                                plog(LLV_ERROR, LOCATION, remote,
                                        "unknown Informational "
@@ -619,6 +652,7 @@ isakmp_main(msg, remote, local)
        case ISAKMP_ETYPE_QUICK:
        {
                struct ph2handle *iph2;
+               struct ph2handle *iph2_i, *iph2_r;
 
                if (iph1 == NULL) {
                        isakmp_info_send_nx(isakmp, remote, local,
@@ -646,7 +680,25 @@ isakmp_main(msg, remote, local)
                }
 
                /* search isakmp phase 2 stauts record. */
-               iph2 = getph2bymsgid(iph1, msgid);
+               iph2_i = getph2bymsgid(iph1, msgid, INITIATOR);
+               iph2_r = getph2bymsgid(iph1, msgid, RESPONDER);
+               if (iph2_i == NULL && iph2_r != NULL) {
+                       if (cmpsaddrstrict(iph1->remote, local) != 0)
+                               iph2 = iph2_r;
+                       else
+                               iph2 = NULL;
+               } else if (iph2_i != NULL && iph2_r == NULL) {
+                       if (cmpsaddrstrict(iph1->remote, local) != 0)
+                               iph2 = iph2_i;
+                       else
+                               iph2 = NULL;
+               } else if (iph2_i != NULL && iph2_r != NULL) {
+                       if (iph2_r->status < iph2_i->status)
+                               iph2 = iph2_r;
+                       else
+                               iph2 = iph2_i;
+               } else
+                       iph2 = NULL;
                if (iph2 == NULL) {
                        /* it must be new negotiation as responder */
                        if (isakmp_ph2begin_r(iph1, msg) < 0)
@@ -2041,15 +2093,17 @@ isakmp_post_acquire(iph2)
         */
 #ifdef ENABLE_NATT
        if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
-               if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
+               if ((iph1 = getph1byaddrwop(iph2->src,
+                                           iph2->dst,
+                                           ANYSIDE)) != NULL) {
                        set_port(iph2->src, extract_port(iph1->local));
                        set_port(iph2->dst, extract_port(iph1->remote));
                }
        } else {
-               iph1 = getph1byaddr(iph2->src, iph2->dst);
+               iph1 = getph1byaddr(iph2->src, iph2->dst, ANYSIDE);
        }
 #else
-       iph1 = getph1byaddr(iph2->src, iph2->dst);
+       iph1 = getph1byaddr(iph2->src, iph2->dst, ANYSIDE);
 #endif
 
        /* no ISAKMP-SA found. */
@@ -2175,15 +2229,17 @@ isakmp_chkph1there(iph2)
         */
 #ifdef ENABLE_NATT
        if (!extract_port(iph2->src) && !extract_port(iph2->dst)) {
-               if ((iph1 = getph1byaddrwop(iph2->src, iph2->dst)) != NULL) {
+               if ((iph1 = getph1byaddrwop(iph2->src,
+                                           iph2->dst,
+                                           ANYSIDE)) != NULL) {
                        set_port(iph2->src, extract_port(iph1->local));
                        set_port(iph2->dst, extract_port(iph1->remote));
                }
        } else {
-               iph1 = getph1byaddr(iph2->src, iph2->dst);
+               iph1 = getph1byaddr(iph2->src, iph2->dst, ANYSIDE);
        }
 #else
-       iph1 = getph1byaddr(iph2->src, iph2->dst);
+       iph1 = getph1byaddr(iph2->src, iph2->dst, ANYSIDE);
 #endif
 
        /* XXX Even if ph1 as responder is there, should we not start
@@ -2432,7 +2488,7 @@ isakmp_newmsgid2(iph1)
 
        do {
                msgid2 = eay_random();
-       } while (getph2bymsgid(iph1, msgid2));
+       } while (getph2bymsgid(iph1, msgid2, iph1->side));
 
        return msgid2;
 }
@@ -3094,7 +3150,7 @@ purge_remote(iph1)
        iph1->status = PHASE1ST_EXPIRED;
 
        /* Check if we have another, still valid, phase1 SA. */
-       new_iph1 = getph1byaddr(iph1->local, iph1->remote);
+       new_iph1 = getph1byaddr(iph1->local, iph1->remote, ANYSIDE);
 
        /*
         * Delete all orphaned or binded to the deleting ph1handle phase2 SAs.
Index: ipsec-tools-0.6.5-6/src/racoon/isakmp.h
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/isakmp.h
+++ ipsec-tools-0.6.5-6/src/racoon/isakmp.h
@@ -37,6 +37,8 @@
 /* must include <netinet/in.h> first. */
 /* must include "isakmp_var.h" first. */
 
+#define ANYSIDE                -1      /* either INITIATOR or RESPONDER */
+
 #define INITIATOR      0       /* synonym sender */
 #define RESPONDER      1       /* synonym receiver */
 
Index: ipsec-tools-0.6.5-6/src/racoon/isakmp_inf.c
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/isakmp_inf.c
+++ ipsec-tools-0.6.5-6/src/racoon/isakmp_inf.c
@@ -363,7 +363,7 @@ isakmp_info_send_d2(iph2)
         * don't send delete information if there is no phase 1 handler.
         * It's nonsensical to negotiate phase 1 to send the information.
         */
-       iph1 = getph1byaddr(iph2->src, iph2->dst); 
+       iph1 = getph1byaddr(iph2->src, iph2->dst, ANYSIDE);
        if (iph1 == NULL)
                return 0;
 
@@ -892,7 +892,7 @@ isakmp_info_recv_n(iph1, msg)
                                "delete phase1 handle.\n");
                        return -1;
                } else {
-                       iph2 = getph2bymsgid(iph1, msgid);
+                       iph2 = getph2bymsgid(iph1, msgid, iph1->side);
                        if (iph2 == NULL) {
                                plog(LLV_ERROR, LOCATION, iph1->remote,
                                        "unknown notify message, "
@@ -937,7 +937,7 @@ purge_isakmp_spi(proto, spi, n)
        size_t i;
 
        for (i = 0; i < n; i++) {
-               iph1 = getph1byindex(&spi[i]);
+               iph1 = getph1byindex(&spi[i], ANYSIDE);
                if (!iph1)
                        continue;
 
Index: ipsec-tools-0.6.5-6/src/racoon/isakmp_xauth.c
===================================================================
--- ipsec-tools-0.6.5-6.orig/src/racoon/isakmp_xauth.c
+++ ipsec-tools-0.6.5-6/src/racoon/isakmp_xauth.c
@@ -338,7 +338,7 @@ xauth_reply_stub(args)
        struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args;
        struct ph1handle *iph1;
 
-       if ((iph1 = getph1byindex(&xra->index)) != NULL)
+       if ((iph1 = getph1byindex(&xra->index, ANYSIDE)) != NULL)
                xauth_reply(iph1, xra->port, xra->id, xra->res);
        else
                plog(LLV_ERROR, LOCATION, NULL, 

--
paul moore
linux security @ hp

--
redhat-lspp mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/redhat-lspp

Reply via email to