Remove "text2pcap-scanner.obj" and "tools\lemon\lemon.obj" when a "nmake
[obnox/wireshark/wip.git] / packet-isakmp.c
index 6195f34c90c6976cc17f8648c5fbbb55afd36ad8..9ae6252a7b473a14e0d067d1710b598a73c55a8f 100644 (file)
@@ -1,14 +1,14 @@
 /* packet-isakmp.c
  * Routines for the Internet Security Association and Key Management Protocol
- * (ISAKMP) (RFC 2408)
+ * (ISAKMP) (RFC 2408) and the Internet IP Security Domain of Interpretation
+ * for ISAKMP (RFC 2407)
  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
  *
- * $Id: packet-isakmp.c,v 1.36 2001/02/28 10:22:29 guy Exp $
+ * $Id: packet-isakmp.c,v 1.48 2001/11/05 21:36:06 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- *
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
 #endif
 
 #include <stdio.h>
+#include <string.h>
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -46,6 +47,7 @@
 #endif
 
 #include "packet.h"
+#include "ipproto.h"
 
 static int proto_isakmp = -1;
 
@@ -54,6 +56,7 @@ static gint ett_isakmp_flags = -1;
 static gint ett_isakmp_payload = -1;
 
 #define UDP_PORT_ISAKMP        500
+#define TCP_PORT_ISAKMP 500
 
 #define NUM_PROTO_TYPES        5
 #define proto2str(t)   \
@@ -153,6 +156,18 @@ static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
   "AES"
 };
 
+#define NUM_IPCOMP_TRANS_TYPES    5
+#define ipcomp_trans2str(t)  \
+  ((t < NUM_IPCOMP_TRANS_TYPES) ? ipcomp_transtypestr[t] : "UNKNOWN-IPCOMP-TRANS-TYPE")
+
+static const char *ipcomp_transtypestr[NUM_IPCOMP_TRANS_TYPES] = {
+  "RESERVED",
+  "OUI",
+  "DEFLATE",
+  "LZS",
+  "LZJH"
+};
+
 #define NUM_ID_TYPES   12
 #define id2str(t)      \
   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
@@ -186,24 +201,28 @@ struct isakmp_hdr {
   guint8       length[4];
 };
 
+struct udp_encap_hdr {
+  guint8       non_ike_marker[8];
+  guint32      esp_SPI;
+};
+
 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
     guint8 *, guint16 *, proto_tree *);
 
-static void dissect_none(tvbuff_t *, int, int, proto_tree *);
-static void dissect_sa(tvbuff_t *, int, int, proto_tree *);
-static void dissect_proposal(tvbuff_t *, int, int, proto_tree *);
-static void dissect_transform(tvbuff_t *, int, int, proto_tree *, guint8);
-static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *);
-static void dissect_id(tvbuff_t *, int, int, proto_tree *);
-static void dissect_cert(tvbuff_t *, int, int, proto_tree *);
-static void dissect_certreq(tvbuff_t *, int, int, proto_tree *);
-static void dissect_hash(tvbuff_t *, int, int, proto_tree *);
-static void dissect_sig(tvbuff_t *, int, int, proto_tree *);
-static void dissect_nonce(tvbuff_t *, int, int, proto_tree *);
-static void dissect_notif(tvbuff_t *, int, int, proto_tree *);
-static void dissect_delete(tvbuff_t *, int, int, proto_tree *);
-static void dissect_vid(tvbuff_t *, int, int, proto_tree *);
-static void dissect_config(tvbuff_t *, int, int, proto_tree *);
+static void dissect_sa(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_proposal(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_transform(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_id(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_cert(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_certreq(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_hash(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_sig(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_nonce(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_notif(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_delete(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_vid(tvbuff_t *, int, int, proto_tree *, int);
+static void dissect_config(tvbuff_t *, int, int, proto_tree *, int);
 
 static const char *payloadtype2str(guint8);
 static const char *exchtype2str(guint8);
@@ -217,6 +236,7 @@ static const char *certtype2str(guint8);
 
 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
 
+#define LOAD_TYPE_NONE         0       /* payload type for None */
 #define LOAD_TYPE_PROPOSAL     2       /* payload type for Proposal */
 #define        LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
 #define NUM_LOAD_TYPES         15
@@ -225,12 +245,12 @@ static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
 
 static struct strfunc {
   const char * str;
-  void          (*func)(tvbuff_t *, int, int, proto_tree *);
+  void          (*func)(tvbuff_t *, int, int, proto_tree *, int);
 } strfuncs[NUM_LOAD_TYPES] = {
-  {"NONE",                     dissect_none      },
+  {"NONE",                     NULL              },
   {"Security Association",     dissect_sa        },
   {"Proposal",                 dissect_proposal  },
-  {"Transform",                        NULL },
+  {"Transform",                        dissect_transform },
   {"Key Exchange",             dissect_key_exch  },
   {"Identification",           dissect_id        },
   {"Certificate",              dissect_cert      },
@@ -244,34 +264,136 @@ static struct strfunc {
   {"Attrib",                   dissect_config    }
 };
 
+static dissector_handle_t esp_handle;
+static dissector_handle_t ah_handle;
+
+static void
+dissect_payloads(tvbuff_t *tvb, proto_tree *tree, guint8 initial_payload,
+                int offset, int length)
+{
+  guint8 payload, next_payload;
+  guint16              payload_length;
+  proto_tree *         ntree;
+
+  for (payload = initial_payload; length != 0; payload = next_payload) {
+    if (payload == LOAD_TYPE_NONE) {
+      /*
+       * What?  There's more stuff in this chunk of data, but the
+       * previous payload had a "next payload" type of None?
+       */
+      proto_tree_add_text(tree, tvb, offset, length,
+                         "Extra data: %s",
+                         tvb_bytes_to_str(tvb, offset, length));
+      break;
+    }
+    ntree = dissect_payload_header(tvb, offset, length, payload,
+      &next_payload, &payload_length, tree);
+    if (ntree == NULL)
+      break;
+    if (payload_length >= 4) { /* XXX = > 4? */
+      if (payload < NUM_LOAD_TYPES) {
+        (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
+                                 -1);
+      }
+      else {
+        proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
+            "Payload");
+      }
+    }
+    else {
+        proto_tree_add_text(ntree, tvb, offset + 4, 0,
+            "Payload (bogus, length is %u, must be at least 4)",
+            payload_length);
+        payload_length = 4;
+    }
+    offset += payload_length;
+    length -= payload_length;
+  }
+}
+
 static void
 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   int                  offset = 0;
   struct isakmp_hdr *  hdr;
+  proto_item *         ti;
+  proto_tree *         isakmp_tree = NULL;
+  struct udp_encap_hdr * encap_hdr;
   guint32              len;
-  guint8               payload, next_payload;
-  guint16              payload_length;
-  proto_tree *         ntree;
+  static const guint8  non_ike_marker[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  tvbuff_t *           next_tvb;
 
   if (check_col(pinfo->fd, COL_PROTOCOL))
     col_set_str(pinfo->fd, COL_PROTOCOL, "ISAKMP");
   if (check_col(pinfo->fd, COL_INFO))
     col_clear(pinfo->fd, COL_INFO);
-  
+
   hdr = (struct isakmp_hdr *)tvb_get_ptr(tvb, 0, sizeof (struct isakmp_hdr));
   len = pntohl(&hdr->length);
   
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_str(pinfo->fd, COL_INFO, exchtype2str(hdr->exch_type));
-  
   if (tree) {
-    proto_item *       ti;
-    proto_tree *       isakmp_tree;
-    
     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, len, FALSE);
     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
+  }
     
+  encap_hdr = (struct udp_encap_hdr *)tvb_get_ptr(tvb, 0, sizeof(struct udp_encap_hdr));
+  
+  if (encap_hdr->non_ike_marker[0] == 0xFF) {
+    if (check_col(pinfo->fd, COL_INFO)) 
+      col_add_str(pinfo->fd, COL_INFO, "UDP encapsulated IPSec - NAT Keepalive");
+    return;
+  }
+  if (memcmp(encap_hdr->non_ike_marker,non_ike_marker,8) == 0) {
+    if (check_col(pinfo->fd, COL_INFO)) {
+      if (encap_hdr->esp_SPI != 0)
+          col_add_str(pinfo->fd, COL_INFO, "UDP encapsulated IPSec - ESP");
+      else
+         col_add_str(pinfo->fd, COL_INFO, "UDP encapsulated IPSec - AH");
+    } 
+    if (tree)
+      proto_tree_add_text(isakmp_tree, tvb, offset,
+                         sizeof(encap_hdr->non_ike_marker),
+                         "Non-IKE-Marker");
+    offset += sizeof(encap_hdr->non_ike_marker);
+      
+    if (encap_hdr->esp_SPI != 0) {
+      next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+      call_dissector(esp_handle, next_tvb, pinfo, tree);
+    } else {
+      if (tree)
+        proto_tree_add_text(isakmp_tree, tvb, offset,
+                           sizeof(encap_hdr->esp_SPI),
+                           "Non-ESP-Marker");
+      offset += sizeof(encap_hdr->esp_SPI);
+
+      if (tree)
+        proto_tree_add_text(isakmp_tree, tvb, offset, 1,
+                           "AH Envelope Version: %u",
+                           tvb_get_guint8(tvb, offset) >> 4);
+      offset += 1;
+
+      if (tree)
+        proto_tree_add_text(isakmp_tree, tvb, offset, 1,
+                           "AH Envelope Header Length: %u",
+                           (tvb_get_guint8(tvb, offset) & 0xF)*4);
+      offset += 1;
+
+      if (tree)
+        proto_tree_add_text(isakmp_tree, tvb, offset, 2,
+                           "AH Envelope Identification: 0x%04X",
+                           tvb_get_ntohs(tvb, offset));
+      offset += 2;
+
+      next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+      call_dissector(ah_handle, next_tvb, pinfo, tree);
+    }
+    return;
+  }
+
+  if (check_col(pinfo->fd, COL_INFO))
+    col_add_str(pinfo->fd, COL_INFO, exchtype2str(hdr->exch_type));
+
+  if (tree) {
     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->icookie),
                        "Initiator cookie");
     offset += sizeof(hdr->icookie);
@@ -330,29 +452,8 @@ dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        "Encrypted payload (%d byte%s)",
                        len, plurality(len, "", "s"));
       }
-    } else {
-      for (payload = hdr->next_payload; len != 0; payload = next_payload) {
-        ntree = dissect_payload_header(tvb, offset, len, payload,
-            &next_payload, &payload_length, isakmp_tree);
-        if (ntree == NULL)
-          break;
-        if (payload_length >= 4) {
-          if (payload < NUM_LOAD_TYPES) {
-            if (next_payload == LOAD_TYPE_TRANSFORM)
-              dissect_transform(tvb, offset + 4, payload_length - 4, ntree, 0);
-               /* XXX - protocol ID? */
-            else
-              (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree);
-          }
-          else {
-            proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
-                "Payload");
-          }
-        }
-        offset += payload_length;
-        len -= payload_length;
-      }
-    }
+    } else
+      dissect_payloads(tvb, isakmp_tree, hdr->next_payload, offset, len);
   }
 }
 
@@ -388,19 +489,18 @@ dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
 }
 
 static void
-dissect_none(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
-{
-}
-
-static void
-dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint32              doi;
   guint32              situation;
-  guint8               next_payload;
-  guint16              payload_length;
-  proto_tree *         ntree;
 
+  if (length < 4) {
+    proto_tree_add_text(tree, tvb, offset, length,
+                       "DOI %s (length is %u, should be >= 4)",
+                       tvb_bytes_to_str(tvb, offset, length), length);
+    return;
+  }
   doi = tvb_get_ntohl(tvb, offset);
   proto_tree_add_text(tree, tvb, offset, 4,
                      "Domain of interpretation: %s (%u)",
@@ -408,21 +508,33 @@ dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
   offset += 4;
   length -= 4;
   
-  situation = tvb_get_ntohl(tvb, offset);
-  proto_tree_add_text(tree, tvb, offset, 4,
-                     "Situation: %s (%u)",
-                     situation2str(situation), situation);
-  offset += 4;
-  length -= 4;
+  if (doi == 1) {
+    /* IPSEC */
+    if (length < 4) {
+      proto_tree_add_text(tree, tvb, offset, length,
+                         "Situation: %s (length is %u, should be >= 4)",
+                         tvb_bytes_to_str(tvb, offset, length), length);
+      return;
+    }
+    situation = tvb_get_ntohl(tvb, offset);
+    proto_tree_add_text(tree, tvb, offset, 4,
+                       "Situation: %s (%u)",
+                       situation2str(situation), situation);
+    offset += 4;
+    length -= 4;
   
-  ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_PROPOSAL,
-    &next_payload, &payload_length, tree);
-  if (ntree != NULL)
-    dissect_proposal(tvb, offset + 4, payload_length - 4, ntree);
+    dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length);
+  } else {
+    /* Unknown */
+    proto_tree_add_text(tree, tvb, offset, length,
+                       "Situation: %s",
+                       tvb_bytes_to_str(tvb, offset, length));
+  }
 }
 
 static void
-dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint8               protocol_id;
   guint8               spi_size;
@@ -456,7 +568,8 @@ dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
   length -= 1;
 
   if (spi_size) {
-    proto_tree_add_text(tree, tvb, offset, spi_size, "SPI");
+    proto_tree_add_text(tree, tvb, offset, spi_size, "SPI: %s",
+                       tvb_bytes_to_str(tvb, offset, spi_size));
     offset += spi_size;
     length -= spi_size;
   }
@@ -483,7 +596,7 @@ dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 
 static void
 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
-    guint8 protocol_id)
+    int protocol_id)
 {
   guint8               transform_id;
 
@@ -495,6 +608,9 @@ dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
   transform_id = tvb_get_guint8(tvb, offset);
   switch (protocol_id) {
   default:
+    proto_tree_add_text(tree, tvb, offset, 1,
+                       "Transform ID: %u", transform_id);
+    break;
   case 1:      /* ISAKMP */
     proto_tree_add_text(tree, tvb, offset, 1,
                        "Transform ID: %s (%u)",
@@ -510,6 +626,11 @@ dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
                        "Transform ID: %s (%u)",
                        esp_trans2str(transform_id), transform_id);
     break;
+  case 4:      /* IPCOMP */
+    proto_tree_add_text(tree, tvb, offset, 1,
+                       "Transform ID: %s (%u)",
+                       ipcomp_trans2str(transform_id), transform_id);
+    break;
   }
   offset += 3;
   length -= 3;
@@ -560,13 +681,15 @@ dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
 }
 
 static void
-dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
 }
 
 static void
-dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint8               id_type;
   guint8               protocol_id;
@@ -600,7 +723,6 @@ dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
   
   switch (id_type) {
     case 1:
-    case 4:
       proto_tree_add_text(tree, tvb, offset, length,
                          "Identification data: %s",
                          ip_to_str(tvb_get_ptr(tvb, offset, 4)));
@@ -611,6 +733,12 @@ dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
                          "Identification data: %.*s", length,
                          tvb_get_ptr(tvb, offset, length));
       break;
+    case 4:
+      proto_tree_add_text(tree, tvb, offset, length,
+                         "Identification data: %s/%s",
+                         ip_to_str(tvb_get_ptr(tvb, offset, 4)),
+                         ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
+      break;
     default:
       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
       break;
@@ -618,7 +746,8 @@ dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 }
 
 static void
-dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint8               cert_enc;
 
@@ -633,7 +762,8 @@ dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 }
 
 static void
-dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint8               cert_type;
 
@@ -648,25 +778,29 @@ dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 }
 
 static void
-dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
 }
 
 static void
-dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
 }
 
 static void
-dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
 }
 
 static void
-dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint32              doi;
   guint8               protocol_id;
@@ -710,7 +844,8 @@ dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 }
 
 static void
-dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint32              doi;
   guint8               protocol_id;
@@ -758,13 +893,15 @@ dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
 }
 
 static void
-dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   proto_tree_add_text(tree, tvb, offset, length, "Vendor ID");
 }
 
 static void
-dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree)
+dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+    int unused)
 {
   guint8               type;
 
@@ -920,17 +1057,41 @@ situation2str(guint32 type) {
   static char  msg[SIT_MSG_NUM];
   int          n = 0;
   char *       sep = "";
+  int          ret;
   
   if (type & SIT_IDENTITY) {
-    n += snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
+    ret = snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
+    if (ret == -1) {
+      /* Some versions of snprintf return -1 if they'd truncate the output. */
+      return msg;
+    }
+    n += ret;
     sep = " & ";
   }
   if (type & SIT_SECRECY) {
-    n += snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
+    if (n >= SIT_MSG_NUM) {
+      /* No more room. */
+      return msg;
+    }
+    ret = snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
+    if (ret == -1) {
+      /* Some versions of snprintf return -1 if they'd truncate the output. */
+      return msg;
+    }
+    n += ret;
     sep = " & ";
   }
   if (type & SIT_INTEGRITY) {
-    n += snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
+    if (n >= SIT_MSG_NUM) {
+      /* No more room. */
+      return msg;
+    }
+    ret = snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
+    if (ret == -1) {
+      /* Some versions of snprintf return -1 if they'd truncate the output. */
+      return msg;
+    }
+    n += ret;
     sep = " & ";
   }
 
@@ -958,6 +1119,9 @@ value2str(int ike_p1, guint16 att_type, guint16 value) {
       switch (value) {
         case 1:  return "Tunnel";
         case 2:  return "Transport";
+       case 61440: return "Check Point IPSec UDP Encapsulation";
+       case 61443: return "UDP-Encapsulated-Tunnel (draft)";
+       case 61444: return "UDP-Encapsulated-Transport (draft)";
         default: return "UNKNOWN-ENCAPSULATION-VALUE";
       }
     case 5:
@@ -1175,5 +1339,12 @@ proto_register_isakmp(void)
 void
 proto_reg_handoff_isakmp(void)
 {
+  /*
+   * Get handle for the AH & ESP dissectors.
+   */
+  esp_handle = find_dissector("esp");
+  ah_handle = find_dissector("ah");
+
   dissector_add("udp.port", UDP_PORT_ISAKMP, dissect_isakmp, proto_isakmp);
+  dissector_add("tcp.port", TCP_PORT_ISAKMP, dissect_isakmp, proto_isakmp);
 }