Hi,

The racoonctl delete-sa command does not work when deleting phase 2 SA. It only deletes phase 1 SA when you issue the command. We have found this is due to the handling of phase 2 SA deletion is missing in admin.c. We have fixed it by adding the changes as shown in the attached diff. Note that the racoonctl command only works after the problem in adminsock_path is fixed, see my other post titled "Patch: The reference to adminsock_path for the racoonctl command".

Also note that the patch could be extended such that the racoonctl delete-sa command can handle different phase 2 SA deletion based on protocol, such as esp, ah, or ipsec. But in our changes, we simplify it such that all phase 2 SAs, regardless the protocol, are deleted when a racoonctl delete-sa command for phase 2 SA is received.

Thanks,
Jianli

--------------------------------------------------------------------------------------

diff -uNr ipsec-tools-0.6.5.orig/src/racoon/admin.c ipsec-tools-0.6.5/src/racoon/admin.c
--- ipsec-tools-0.6.5.orig/src/racoon/admin.c   2007-05-24 16:31:02.000000000 -0500
+++ ipsec-tools-0.6.5/src/racoon/admin.c        2007-05-24 20:38:12.000000000 -0500
@@ -289,14 +289,28 @@
                        break;
                }
 
-               if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
-                       plog(LLV_ERROR, LOCATION, NULL,
-                           "phase 1 for %s -> %s not found\n", loc, rem);
-               } else {
-                       if (iph1->status == PHASE1ST_ESTABLISHED)
-                               isakmp_info_send_d1(iph1);
-                       purge_remote(iph1);
+/* Start of change: Enable the racoonctl command to delete Phase 2 SAs */
+               switch (com->ac_proto) {
+               case ADMIN_PROTO_ISAKMP:
+                       if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
+                               plog(LLV_ERROR, LOCATION, NULL,
+                               "phase 1 for %s -> %s not found\n", loc, rem);
+                       } else {
+                               if (iph1->status == PHASE1ST_ESTABLISHED)
+                                       isakmp_info_send_d1(iph1);
+                               purge_remote(iph1);
+                       }
+                       break;
+               case ADMIN_PROTO_IPSEC:
+               case ADMIN_PROTO_AH:
+               case ADMIN_PROTO_ESP:
+                       purge_ph2_sa(src, dst);
+                       break;
+               default:
+                       /* ignore */
+                       break;
                }
+/* End of change */
 
                racoon_free(loc);
                racoon_free(rem);
diff -uNr ipsec-tools-0.6.5.orig/src/racoon/isakmp.c ipsec-tools-0.6.5/src/racoon/isakmp.c
--- ipsec-tools-0.6.5.orig/src/racoon/isakmp.c  2007-05-24 16:31:02.000000000 -0500
+++ ipsec-tools-0.6.5/src/racoon/isakmp.c       2007-05-29 17:46:47.000000000 -0500
@@ -3221,6 +3221,101 @@
        iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
 }
 
+/* Start of change: Enable the racoonctl command to delete Phase 2 SAs */
+/* This function deletes Phase 2 SAs */
+void
+purge_ph2_sa(local,remote)
+       struct sockaddr *local, *remote;
+{
+        vchar_t *buf = NULL;
+        struct sadb_msg *msg, *next, *end;
+        struct sadb_sa *sa;
+        struct sockaddr *src, *dst;
+        caddr_t mhp[SADB_EXT_MAX + 1];
+        struct ph2handle *iph2;
+
+        /* Delete all phase2 SAs */
+        buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
+        if (buf == NULL) {
+                plog(LLV_DEBUG, LOCATION, NULL,
+                        "pfkey_dump_sadb returned nothing.\n");
+                return;
+        }
+
+        msg = (struct sadb_msg *)buf->v;
+        end = (struct sadb_msg *)(buf->v + buf->l);
+
+        while (msg < end) {
+                if ((msg->sadb_msg_len << 3) < sizeof(*msg))
+                        break;
+                next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3));
+                if (msg->sadb_msg_type != SADB_DUMP) {
+                        msg = next;
+                        continue;
+                }
+
+                if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
+                        plog(LLV_ERROR, LOCATION, NULL,
+                                "pfkey_check (%s)\n", ipsec_strerror());
+                        msg = next;
+                        continue;
+                }
+
+                sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
+                if (!sa ||
+                    !mhp[SADB_EXT_ADDRESS_SRC] ||
+                    !mhp[SADB_EXT_ADDRESS_DST]) {
+                        msg = next;
+                        continue;
+                }
+                src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]);
+                dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]);
+
+                if (sa->sadb_sa_state != SADB_SASTATE_MATURE &&
+                    sa->sadb_sa_state != SADB_SASTATE_DYING) {
+                        msg = next;
+                        continue;
+                }
+
+                /* delete in/outbound SAs */
+                if ((CMPSADDR(remote,dst) || CMPSADDR(local,src)) &&
+                     (CMPSADDR(local,dst) || CMPSADDR(remote,src)))
+                {
+                        msg = next;
+                        continue;
+                }
+
+                pfkey_send_delete(lcconf->sock_pfkey,
+                                  msg->sadb_msg_satype,
+                                  IPSEC_MODE_ANY,
+                                  src, dst, sa->sadb_sa_spi);
+
+                /*
+                 * delete a relative phase 2 handler.
+                 * continue to process if no relative phase 2 handler
+                 * exists.
+                 */
+                while ((iph2 = getph2bysaddr(src, dst)) != NULL) {
+                        delete_spd(iph2);
+                        unbindph12(iph2);
+                        remph2(iph2);
+                        delph2(iph2);
+                }
+
+                plog(LLV_INFO, LOCATION, NULL,
+                         "purged IPsec-SA spi=%u.\n",
+                         ntohl(sa->sadb_sa_spi));
+
+                msg = next;
+        }
+
+        if (buf)
+                vfree(buf);
+
+}
+/* End of change */
+
+
 void
 delete_spd(iph2)
        struct ph2handle *iph2;
diff -uNr ipsec-tools-0.6.5.orig/src/racoon/isakmp_var.h ipsec-tools-0.6.5/src/racoon/isakmp_var.h
--- ipsec-tools-0.6.5.orig/src/racoon/isakmp_var.h      2007-05-24 16:31:02.000000000 -0500
+++ ipsec-tools-0.6.5/src/racoon/isakmp_var.h   2007-05-24 20:16:20.000000000 -0500
@@ -123,6 +123,12 @@
 extern int script_exec __P((int, int, char * const *));
 
 void purge_remote __P((struct ph1handle *));
+
+/* Start of change: Enable the racoonctl command to delete Phase 2 SAs */
+/* Add new function purge_ph2_sa() */
+void purge_ph2_sa __P((struct sockaddr *, struct sockaddr *));
+/* End of change */
+
 void delete_spd __P((struct ph2handle *));
 #ifdef INET6
 u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *));