Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Ethereal-dev: [Ethereal-dev] IKEv2 support

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Shoichi Sakane <sakane@xxxxxxxx>
Date: Wed, 23 Feb 2005 11:17:38 +0900
Hi, I improved packet-isakmp.c to support parsing the IKEv2 packets.
I made a diff from ethereal-0.10.9-SVN-13409.  I have checked it with
our IKEv2 implementation, and it looks working fine.  So could you
merge it to the main tree if you allow it ?  or could you give me
comments or advise if you can not ?  I attached the diff to this mail.

Best regards,
*** packet-isakmp.c.orig	Wed Feb 23 11:05:04 2005
--- packet-isakmp.c	Wed Feb 23 10:56:05 2005
***************
*** 4,9 ****
--- 4,13 ----
   * for ISAKMP (RFC 2407)
   * Brad Robel-Forrest <brad.robel-forrest@xxxxxxxxxxxxxx>
   *
+  * Added routines for the Internet Key Exchange (IKEv2) Protocol
+  * (draft-ietf-ipsec-ikev2-17.txt)
+  * Shoichi Sakane <sakane@xxxxxxxx>
+  *
   * $Id: packet-isakmp.c 12621 2004-11-29 19:30:12Z gerald $
   *
   * Ethereal - Network traffic analyzer
***************
*** 45,56 ****
--- 49,77 ----
  
  #define isakmp_min(a, b)  ((a<b) ? a : b)
  
+ #define ARLEN(a) (sizeof(a)/sizeof(a[0]))
+ 
+ #define FIND_TYPE2STR(list, t) \
+ do { \
+   guint i; \
+   for (i = 0; i < ARLEN(list); i++) { \
+     if (t == list[i].type) return list[i].str; \
+   } \
+ } while (0)
+ 
+ struct type2str_t {
+ 	guint type;
+ 	const char *str;
+ };
+ 
  static int proto_isakmp = -1;
  
  static gint ett_isakmp = -1;
  static gint ett_isakmp_flags = -1;
  static gint ett_isakmp_payload = -1;
  
+ static int isakmp_version = 0;
+ 
  #define UDP_PORT_ISAKMP	500
  #define TCP_PORT_ISAKMP 500
  
***************
*** 164,188 ****
    "LZJH"
  };
  
- #define NUM_ID_TYPES	12
- #define id2str(t)	\
-   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
- 
- static const char *idtypestr[NUM_ID_TYPES] = {
-   "RESERVED",
-   "IPV4_ADDR",
-   "FQDN",
-   "USER_FQDN",
-   "IPV4_ADDR_SUBNET",
-   "IPV6_ADDR",
-   "IPV6_ADDR_SUBNET",
-   "IPV4_ADDR_RANGE",
-   "IPV6_ADDR_RANGE",
-   "DER_ASN1_DN",
-   "DER_ASN1_GN",
-   "KEY_ID"
- };
- 
  #define NUM_GRPDESC_TYPES 19
  #define grpdesc2str(t) ((t < NUM_GRPDESC_TYPES) ? grpdescstr[t] : "UNKNOWN-GROUP-DESCRIPTION")
  
--- 185,190 ----
***************
*** 218,223 ****
--- 220,228 ----
  #define E_FLAG		0x01
  #define C_FLAG		0x02
  #define A_FLAG		0x04
+ #define I_FLAG		0x08
+ #define V_FLAG		0x10
+ #define R_FLAG		0x20
    guint32	message_id;
    guint32	length;
  };
***************
*** 231,236 ****
--- 236,243 ----
      packet_info *, int);
  static void dissect_transform(tvbuff_t *, int, int, proto_tree *,
      packet_info *, int);
+ static void dissect_transform2(tvbuff_t *, int, int, proto_tree *,
+     packet_info *, int);
  static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *,
      packet_info *, int);
  static void dissect_id(tvbuff_t *, int, int, proto_tree *,
***************
*** 241,246 ****
--- 248,255 ----
      packet_info *, int);
  static void dissect_hash(tvbuff_t *, int, int, proto_tree *,
      packet_info *, int);
+ static void dissect_auth(tvbuff_t *, int, int, proto_tree *,
+     packet_info *, int);
  static void dissect_sig(tvbuff_t *, int, int, proto_tree *,
      packet_info *, int);
  static void dissect_nonce(tvbuff_t *, int, int, proto_tree *,
***************
*** 257,270 ****
--- 266,289 ----
      packet_info *, int);
  static void dissect_nat_original_address(tvbuff_t *, int, int, proto_tree *,
      packet_info *, int);
+ static void dissect_ts(tvbuff_t *, int, int, proto_tree *,
+     packet_info *, int);
+ static void dissect_enc(tvbuff_t *, int, int, proto_tree *,
+     packet_info *, int);
+ static void dissect_eap(tvbuff_t *, int, int, proto_tree *,
+     packet_info *, int);
  
  static const char *payloadtype2str(guint8);
  static const char *exchtype2str(guint8);
  static const char *doitype2str(guint32);
  static const char *msgtype2str(guint16);
  static const char *situation2str(guint32);
+ static const char *v2_attrvalue2str(guint16, guint32);
  static const char *value2str(int, guint16, guint32);
  static const char *attrtype2str(guint8);
+ static const char *id2str(guint8);
+ static const char *v2_tstype2str(guint8);
+ static const char *v2_auth2str(guint8);
  static const char *cfgattrident2str(guint16);
  static const char *certtype2str(guint8);
  
***************
*** 273,303 ****
  #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		17
  
! static struct strfunc {
    const char *	str;
    void          (*func)(tvbuff_t *, int, int, proto_tree *, packet_info *, int);
- } strfuncs[NUM_LOAD_TYPES] = {
-   {"NONE",			NULL              },
-   {"Security Association",	dissect_sa        },
-   {"Proposal",			dissect_proposal  },
-   {"Transform",			dissect_transform },
-   {"Key Exchange",		dissect_key_exch  },
-   {"Identification",		dissect_id        },
-   {"Certificate",		dissect_cert      },
-   {"Certificate Request",	dissect_certreq   },
-   {"Hash",			dissect_hash      },
-   {"Signature",			dissect_sig       },
-   {"Nonce",			dissect_nonce     },
-   {"Notification",		dissect_notif     },
-   {"Delete",			dissect_delete    },
-   {"Vendor ID",			dissect_vid       },
-   {"Attrib",			dissect_config	  },
-   {"NAT-Discovery",		dissect_nat_discovery }, /* draft-ietf-ipsec-nat-t-ike-04 */
-   {"NAT-Original Address",	dissect_nat_original_address } /* draft-ietf-ipsec-nat-t-ike */
  };
  
  #define VID_LEN 16
  #define VID_MS_LEN 20
  static const guint8 VID_MS_W2K_WXP[VID_MS_LEN] = {0x1E, 0x2B, 0x51, 0x69, 0x5, 0x99, 0x1C, 0x7D, 0x7C, 0x96, 0xFC, 0xBF, 0xB5, 0x87, 0xE4, 0x61, 0x0, 0x0, 0x0, 0x2}; /* according to http://www.microsoft.com/technet/treeview/default.asp?url=/technet/columns/cableguy/cg0602.asp */
--- 292,347 ----
  #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 */
  
! struct strfunc {
!   gint8 type;
    const char *	str;
    void          (*func)(tvbuff_t *, int, int, proto_tree *, packet_info *, int);
  };
  
+ static struct strfunc strfuncs[] = {
+   {  0, "NONE",			NULL              },
+   {  1, "Security Association",	dissect_sa        },
+   {  2, "Proposal",		dissect_proposal  },
+   {  3, "Transform",		dissect_transform },
+   {  4, "Key Exchange",		dissect_key_exch  },
+   {  5, "Identification",	dissect_id        },
+   {  6, "Certificate",		dissect_cert      },
+   {  7, "Certificate Request",	dissect_certreq   },
+   {  8, "Hash",			dissect_hash      },
+   {  9, "Signature",		dissect_sig       },
+   { 10, "Nonce",		dissect_nonce     },
+   { 11, "Notification",		dissect_notif     },
+   { 12, "Delete",		dissect_delete    },
+   { 13, "Vendor ID",		dissect_vid       },
+   { 14, "Attrib",		dissect_config	  },
+   { 15, "NAT-Discovery",	dissect_nat_discovery }, /* draft-ietf-ipsec-nat-t-ike-04 */
+   { 16, "NAT-Original Address",	dissect_nat_original_address }, /* draft-ietf-ipsec-nat-t-ike */
+ };
+ 
+ static struct strfunc v2_strfuncs[] = {
+   {  2, "Proposal",		dissect_proposal  },
+   {  3, "Transform",		dissect_transform2 },
+   { 33, "Security Association",	dissect_sa        },
+   { 34, "Key Exchange",		dissect_key_exch  },
+   { 35, "Identification - I",	dissect_id        },
+   { 36, "Identification - R",	dissect_id        },
+   { 37, "Certificate",		dissect_cert      },
+   { 38, "Certificate Request",	dissect_certreq   },
+   { 39, "Authentication",	dissect_auth      },
+   { 40, "Nonce",		dissect_nonce     },
+   { 41, "Notification",		dissect_notif     },
+   { 42, "Delete",		dissect_delete    },
+   { 43, "Vendor ID",		dissect_vid       },
+   { 44, "Traffic Selector - I",	dissect_ts       },
+   { 45, "Traffic Selector - R",	dissect_ts       },
+   { 46, "Encrypted",		dissect_enc       },
+   { 47, "Configuration",	dissect_config	  },
+   { 48, "Extensible Authentication",	dissect_eap	  },
+ };
+ 
+ static struct strfunc * getstrfunc(guint8);
+ 
  #define VID_LEN 16
  #define VID_MS_LEN 20
  static const guint8 VID_MS_W2K_WXP[VID_MS_LEN] = {0x1E, 0x2B, 0x51, 0x69, 0x5, 0x99, 0x1C, 0x7D, 0x7C, 0x96, 0xFC, 0xBF, 0xB5, 0x87, 0xE4, 0x61, 0x0, 0x0, 0x0, 0x2}; /* according to http://www.microsoft.com/technet/treeview/default.asp?url=/technet/columns/cableguy/cg0602.asp */
***************
*** 423,428 ****
--- 467,473 ----
    guint8 payload, next_payload;
    guint16		payload_length;
    proto_tree *		ntree;
+   struct strfunc *	f;
  
    for (payload = initial_payload; length != 0; payload = next_payload) {
      if (payload == LOAD_TYPE_NONE) {
***************
*** 440,449 ****
      if (ntree == NULL)
        break;
      if (payload_length >= 4) {	/* XXX = > 4? */
!       if (payload < NUM_LOAD_TYPES && strfuncs[payload].func != NULL) {
!         (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
! 				  pinfo, -1);
!       }
        else {
  	if (payload == 130)
  	  dissect_nat_discovery(tvb, offset + 4, payload_length - 4, ntree,
--- 485,492 ----
      if (ntree == NULL)
        break;
      if (payload_length >= 4) {	/* XXX = > 4? */
!       if ((f = getstrfunc(payload)) != NULL)
!         (*f->func)(tvb, offset + 4, payload_length - 4, ntree, pinfo, -1);
        else {
  	if (payload == 130)
  	  dissect_nat_discovery(tvb, offset + 4, payload_length - 4, ntree,
***************
*** 473,478 ****
--- 516,542 ----
    }
  }
  
+ static struct strfunc *
+ getstrfunc(guint8 payload)
+ {
+   struct strfunc *f = 0;
+   int i, len;
+ 
+   if (isakmp_version == 1) {
+     f = strfuncs;
+     len = ARLEN(strfuncs);
+   } else if (isakmp_version == 2) {
+     f = v2_strfuncs;
+     len = ARLEN(v2_strfuncs);
+   } else
+     return NULL;
+   for (i = 0; i < len; i++) {
+     if (f[i].type == payload)
+       return &f[i];
+   }
+   return NULL;
+ }
+ 
  static void
  dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
***************
*** 493,498 ****
--- 557,564 ----
  
    hdr.length = tvb_get_ntohl(tvb, offset + sizeof(hdr) - sizeof(hdr.length));
    hdr.exch_type = tvb_get_guint8(tvb, sizeof(hdr.icookie) + sizeof(hdr.rcookie) + sizeof(hdr.next_payload) + sizeof(hdr.version));
+   hdr.version = tvb_get_guint8(tvb, sizeof(hdr.icookie) + sizeof(hdr.rcookie) + sizeof(hdr.next_payload));
+   isakmp_version = hi_nibble(hdr.version);	/* save the version */
    if (check_col(pinfo->cinfo, COL_INFO))
      col_add_str(pinfo->cinfo, COL_INFO, exchtype2str(hdr.exch_type));
  
***************
*** 513,519 ****
  			payloadtype2str(hdr.next_payload), hdr.next_payload);
      offset += sizeof(hdr.next_payload);
  
-     hdr.version = tvb_get_guint8(tvb, offset);
      proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.version),
  			"Version: %u.%u",
  			hi_nibble(hdr.version), lo_nibble(hdr.version));
--- 579,584 ----
***************
*** 533,547 ****
        fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.flags), "Flags");
        ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
  
!       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, E_FLAG, sizeof(hdr.flags)*8,
! 						  "Encryption", "No encryption"));
!       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, C_FLAG, sizeof(hdr.flags)*8,
  						  "Commit", "No commit"));
!       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, A_FLAG, sizeof(hdr.flags)*8,
  						  "Authentication", "No authentication"));
        offset += sizeof(hdr.flags);
      }
  
--- 598,624 ----
        fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.flags), "Flags");
        ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
  
!       if (isakmp_version == 1) {
!         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, E_FLAG, sizeof(hdr.flags)*8,
! 						  "Encrypted", "Not encrypted"));
!         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, C_FLAG, sizeof(hdr.flags)*8,
  						  "Commit", "No commit"));
!         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
  			  decode_boolean_bitfield(hdr.flags, A_FLAG, sizeof(hdr.flags)*8,
  						  "Authentication", "No authentication"));
+       } else if (isakmp_version == 2) {
+         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
+ 			  decode_boolean_bitfield(hdr.flags, I_FLAG, sizeof(hdr.flags)*8,
+ 						  "Initiator", "Responder"));
+         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
+ 			  decode_boolean_bitfield(hdr.flags, V_FLAG, sizeof(hdr.flags)*8,
+ 						  "A higher version enabled", ""));
+         proto_tree_add_text(ftree, tvb, offset, 1, "%s",
+ 			  decode_boolean_bitfield(hdr.flags, R_FLAG, sizeof(hdr.flags)*8,
+ 						  "Response", "Request"));
+       }
        offset += sizeof(hdr.flags);
      }
  
***************
*** 604,609 ****
--- 681,691 ----
    proto_tree_add_text(ntree, tvb, offset, 1,
  		      "Next payload: %s (%u)",
  		      payloadtype2str(next_payload), next_payload);
+   if (isakmp_version == 2) {
+     proto_tree_add_text(ntree, tvb, offset, 1, "%s",
+         	decode_boolean_bitfield(tvb_get_guint8(tvb, 1), 0x80, 8, 
+   		"Critical", "Not critical"));
+   }
    proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
  
    *next_payload_p = next_payload;
***************
*** 624,657 ****
  			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)",
  		      doitype2str(doi), doi);
!   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;
  
!     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length, pinfo);
!   } else {
!     /* Unknown */
!     proto_tree_add_text(tree, tvb, offset, length,
  			"Situation: %s",
  			tvb_bytes_to_str(tvb, offset, length));
    }
  }
  
--- 706,743 ----
  			tvb_bytes_to_str(tvb, offset, length), length);
      return;
    }
!   if (isakmp_version == 1) {
!     doi = tvb_get_ntohl(tvb, offset);
!     proto_tree_add_text(tree, tvb, offset, 4,
  		      "Domain of interpretation: %s (%u)",
  		      doitype2str(doi), doi);
!     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;
  
!       dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length, pinfo);
!     } else {
!       /* Unknown */
!       proto_tree_add_text(tree, tvb, offset, length,
  			"Situation: %s",
  			tvb_bytes_to_str(tvb, offset, length));
+     }
+   } else if (isakmp_version == 2) {
+     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length, pinfo);
    }
  }
  
***************
*** 711,719 ****
            "Not enough room in payload for all transforms");
        break;
      }
!     if (payload_length >= 4)
!       dissect_transform(tvb, offset + 4, payload_length - 4, ntree,
  			pinfo, protocol_id);
      else
        proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
      offset += payload_length;
--- 797,810 ----
            "Not enough room in payload for all transforms");
        break;
      }
!     if (payload_length >= 4) {
!       if (isakmp_version == 1)
!         dissect_transform(tvb, offset + 4, payload_length - 4, ntree,
! 			pinfo, protocol_id);
!       else if (isakmp_version == 2)
!         dissect_transform2(tvb, offset + 4, payload_length - 4, ntree,
  			pinfo, protocol_id);
+     }
      else
        proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
      offset += payload_length;
***************
*** 811,820 ****
--- 902,1109 ----
    }
  }
  
+ /* For Transform Type 1 (Encryption Algorithm), defined Transform IDs */
+ static const char *
+ v2_tid2encstr(guint16 tid)
+ {
+   static const char *strs[] = {
+     "RESERVED",
+     "ENCR_DES_IV64",
+     "ENCR_DES",
+     "ENCR_3DE",
+     "ENCR_RC5",
+     "ENCR_IDEA",
+     "ENCR_CAST",
+     "ENCR_BLOWFISH",
+     "ENCR_3IDEA",
+     "ENCR_DES_IV32",
+     "RESERVED",
+     "ENCR_NULL",
+     "ENCR_AES_CBC",
+     "ENCR_AES_CTR",
+   };
+   if (tid < ARLEN(strs)) return strs[tid];
+   return "RESERVED";
+ }
+ 
+ /* For Transform Type 2 (Pseudo-random Function), defined Transform IDs */
+ static const char *
+ v2_tid2prfstr(guint16 tid)
+ {
+   static const char *strs[] = {
+     "RESERVED",
+     "PRF_HMAC_MD5",
+     "PRF_HMAC_SHA1",
+     "PRF_HMAC_TIGER",
+     "PRF_AES128_CBC",
+   };
+   if (tid < ARLEN(strs)) return strs[tid];
+   return "RESERVED";
+ }
+ 
+ /* For Transform Type 3 (Integrity Algorithm), defined Transform IDs */
+ static const char *
+ v2_tid2iastr(guint16 tid)
+ {
+   static const char *strs[] = {
+     "NONE",
+     "AUTH_HMAC_MD5_96",
+     "AUTH_HMAC_SHA1_96",
+     "AUTH_DES_MAC",
+     "AUTH_KPDK_MD5",
+     "AUTH_AES_XCBC_96",
+   };
+   if (tid < ARLEN(strs)) return strs[tid];
+   return "RESERVED";
+ }
+ 
+ /* For Transform Type 4 (Diffie-Hellman Group), defined Transform IDs */
+ static const char *
+ v2_tid2dhstr(guint16 tid)
+ {
+   static struct type2str_t strs[] = {
+     {  0, "NONE" },
+     {  1, "Group 1 - 768 Bit MODP" },
+     {  2, "Group 2 - 1024 Bit MODP" },
+     {  3, "RESERVED" },
+     {  4, "RESERVED" },
+     {  5, "group 5 - 1536 Bit MODP" },
+     { 14, "2048-bit MODP Group" },
+     { 15, "3072-bit MODP Group" },
+     { 16, "4096-bit MODP Group" },
+     { 17, "6144-bit MODP Group" },
+     { 18, "8192-bit MODP Group" },
+   };
+   FIND_TYPE2STR(strs, tid);
+   if ((tid >= 6 && tid <= 13) || (tid >= 19 && tid <= 1023))
+     return "RESERVED TO IANA";
+   if (tid >= 1024)
+     return "PRIVATE USE";
+   return "RESERVED";
+ }
+ 
+ /* For Transform Type 5 (Extended Sequence Numbers), defined Transform */
+ static const char *
+ v2_tid2esnstr(guint16 tid)
+ {
+   static const char *strs[] = {
+     "No Extended Sequence Numbers",
+     "Extended Sequence Numbers",
+   };
+   if (tid < sizeof(strs)/sizeof(strs[0])) return strs[tid];
+   return "RESERVED";
+ }
+ 
+ static struct {
+   const char *str;
+   const char *(*func)(guint16);
+ } trans2str[] = {
+   { "RESERVED", NULL, },
+   { "Encryption Algorithm (ENCR)", v2_tid2encstr },
+   { "Pseudo-random Function (PRF)", v2_tid2prfstr }, 
+   { "Integrity Algorithm (INTEG)", v2_tid2iastr },
+   { "Diffie-Hellman Group (D-H)", v2_tid2dhstr },
+   { "Extended Sequence Numbers (ESN)", v2_tid2esnstr },
+ };
+ 
+ static const char *
+ v2_trans2str(guint8 type)
+ {
+   if (type < ARLEN(trans2str)) return trans2str[type].str;
+   if (type < 240) return "RESERVED TO IANA";
+   return "PRIVATE USE";
+ }
+ 
+ static const char *
+ v2_tid2str(guint8 type, guint16 tid)
+ {
+   if (type < ARLEN(trans2str) && trans2str[type].func != NULL) {
+     return (trans2str[type].func)(tid);
+   }
+   return "RESERVED";
+ }
+ 
+ static const char *
+ v2_aft2str(guint16 aft)
+ {
+     if (aft < 14 || (aft > 14 && aft < 18)) return "RESERVED";
+     if (aft == 14) return "Key Length (in bits)";
+     if (aft >= 18 && aft < 16384) return "RESERVED TO IANA";
+     return "PRIVATE USE";
+ }
+ 
+ static void
+ dissect_transform2(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+     packet_info *pinfo _U_, int unused _U_)
+ {
+   guint8 transform_type;
+   guint16 transform_id;
+ 
+   transform_type = tvb_get_guint8(tvb, offset);
+   proto_tree_add_text(tree, tvb, offset, 1,
+     "Transform type: %s (%u)", v2_trans2str(transform_type), transform_type);
+   offset += 2;
+   length -= 2;
+ 
+   transform_id = tvb_get_ntohs(tvb, offset);
+   proto_tree_add_text(tree, tvb, offset, 2,
+     "Transform ID: %s (%u)", v2_tid2str(transform_type, transform_id),
+     transform_id);
+   offset += 2;
+   length -= 2;
+ 
+   while (length>0) {
+     const char *str;
+     guint16 aft     = tvb_get_ntohs(tvb, offset);
+     guint16 type    = aft & 0x7fff;
+     guint16 len;
+     guint32 val;
+     guint pack_len;
+ 
+     str = v2_aft2str(aft);
+ 
+     if (aft & 0x8000) {
+       val = tvb_get_ntohs(tvb, offset + 2);
+       proto_tree_add_text(tree, tvb, offset, 4,
+ 			  "%s (%u): %s (%u)",
+ 			  str, type,
+ 			  v2_attrvalue2str(type, val), val);
+       offset += 4;
+       length -= 4;
+     }
+     else {
+       len = tvb_get_ntohs(tvb, offset + 2);
+       pack_len = 4 + len;
+       if (!get_num(tvb, offset + 4, len, &val)) {
+         proto_tree_add_text(tree, tvb, offset, pack_len,
+ 			    "%s (%u): <too big (%u bytes)>",
+ 			    str, type, len);
+       } else {
+         proto_tree_add_text(tree, tvb, offset, pack_len,
+ 			    "%s (%u): %s (%u)",
+ 			    str, type,
+ 			    v2_attrvalue2str(type, val), val);
+       }
+       offset += pack_len;
+       length -= pack_len;
+     }
+   }
+ }
+ 
  static void
  dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
      packet_info *pinfo _U_, int unused _U_)
  {
+   guint16 dhgroup;
+ 
+   if (isakmp_version == 2) {
+     dhgroup = tvb_get_ntohs(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 2,
+   		      "DH Group #: %u", dhgroup);
+     offset += 4;
+     length -= 4;
+   }
+ 
    proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
  }
  
***************
*** 927,932 ****
--- 1216,1236 ----
  }
  
  static void
+ dissect_auth(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+     packet_info *pinfo _U_, int unused _U_)
+ {
+   guint8 auth;
+ 
+   auth = tvb_get_guint8(tvb, offset);
+   proto_tree_add_text(tree, tvb, offset, 1,
+   		      "Auth Method: %s (%u)", v2_auth2str(auth), auth);
+   offset += 4;
+   length -= 4;
+ 
+   proto_tree_add_text(tree, tvb, offset, length, "Authentication Data");
+ }
+ 
+ static void
  dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
      packet_info *pinfo _U_, int unused _U_)
  {
***************
*** 949,960 ****
    guint8		spi_size;
    guint16		msgtype;
  
!   doi = tvb_get_ntohl(tvb, offset);
!   proto_tree_add_text(tree, tvb, offset, 4,
! 		      "Domain of Interpretation: %s (%u)",
! 		      doitype2str(doi), doi);
!   offset += 4;
!   length -= 4;
  
    protocol_id = tvb_get_guint8(tvb, offset);
    proto_tree_add_text(tree, tvb, offset, 1,
--- 1253,1266 ----
    guint8		spi_size;
    guint16		msgtype;
  
!   if (isakmp_version == 1) {
!     doi = tvb_get_ntohl(tvb, offset);
!     proto_tree_add_text(tree, tvb, offset, 4,
!   		      "Domain of Interpretation: %s (%u)",
!   		      doitype2str(doi), doi);
!     offset += 4;
!     length -= 4;
!   }
  
    protocol_id = tvb_get_guint8(tvb, offset);
    proto_tree_add_text(tree, tvb, offset, 1,
***************
*** 1355,1377 ****
    }
  }
  
  static const char *
! payloadtype2str(guint8 type) {
  
!   if (type < NUM_LOAD_TYPES)
!     return strfuncs[type].str;
!   if (type < 128)
      return "RESERVED";
!   if (type == 130)
!     return "NAT-D (draft-ietf-ipsec-nat-t-ike-01 to 03)";
!   if (type == 131)
!     return "NAT-OA (draft-ietf-ipsec-nat-t-ike-01 to 04)";
!   return "Private USE";
  }
  
  static const char *
! exchtype2str(guint8 type) {
! 
  #define NUM_EXCHSTRS	7
    static const char * exchstrs[NUM_EXCHSTRS] = {
      "NONE",
--- 1661,1792 ----
    }
  }
  
+ static void
+ dissect_ts(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+     packet_info *pinfo _U_, int unused _U_)
+ {
+   guint8	num, tstype, protocol_id, len, addrlen;
+   guint16	port;
+ 
+   proto_tree_add_text(tree, tvb, offset, length, "Traffic Selector");
+ 
+   num = tvb_get_guint8(tvb, offset);
+   proto_item_append_text(tree," # %d", num);
+   proto_tree_add_text(tree, tvb, offset, 1,
+   		      "Number of TSs: %u", num);
+   offset += 4;
+   length -= 4;
+ 
+   while (length > 0) {
+     tstype = tvb_get_guint8(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 1,
+   		      "TS Type: %s (%u)",
+   		      v2_tstype2str(tstype), tstype);
+     switch (tstype) {
+     case 7:
+       addrlen = 4;
+       break;
+     case 8:
+       addrlen = 16;
+       break;
+     default:
+       addrlen = 255;
+     }
+     /*
+      * XXX should the remaining of the length check be done here ?
+      * it seems other routines don't check the length.
+      */
+     if (length < (8 + addrlen * 2)) {
+       proto_tree_add_text(tree, tvb, offset, length,
+ 			  "Length mismatch (%u)", length);
+       return;
+     }
+     offset += 1;
+     length -= 1;
+ 
+     protocol_id = tvb_get_guint8(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 1,
+   		      "Protocol ID: (%u)", protocol_id);
+     offset += 1;
+     length -= 1;
+ 
+     len = tvb_get_ntohs(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 2,
+   		      "Selector Length: %u", len);
+     offset += 2;
+     length -= 2;
+ 
+     port = tvb_get_ntohs(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 2,
+   		      "Start Port: (%u)", port);
+     offset += 2;
+     length -= 2;
+ 
+     port = tvb_get_ntohs(tvb, offset);
+     proto_tree_add_text(tree, tvb, offset, 2,
+   		      "End Port: (%u)", port);
+     offset += 2;
+     length -= 2;
+ 
+     proto_tree_add_text(tree, tvb, offset, length,
+   			  "Starting Address: %s",
+   			  ip_to_str(tvb_get_ptr(tvb, offset, addrlen)));
+     offset += addrlen;
+     length -= addrlen;
+ 
+     proto_tree_add_text(tree, tvb, offset, length,
+   			  "Starting Address: %s",
+   			  ip_to_str(tvb_get_ptr(tvb, offset, addrlen)));
+     offset += addrlen;
+     length -= addrlen;
+   }
+ }
+ 
+ static void
+ dissect_enc(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+     packet_info *pinfo _U_, int unused _U_)
+ {
+   proto_tree_add_text(tree, tvb, offset, 4, "Initialization Vector: 0x%s",
+                       tvb_bytes_to_str(tvb, 8, 4));
+   proto_tree_add_text(tree, tvb, offset + 4, length, "Encrypted Data");
+ }
+ 
+ static void
+ dissect_eap(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
+     packet_info *pinfo _U_, int unused _U_)
+ {
+   proto_tree_add_text(tree, tvb, offset, length, "EAP Message");
+ }
+ 
  static const char *
! payloadtype2str(guint8 type)
! {
!   struct strfunc *f;
  
!   if ((f = getstrfunc(type)) != NULL)
!       return f->str;
!   /* non-predefined type */
!   if (isakmp_version == 1) {
!     if (type < 128)
!       return "RESERVED";
!     if (type == 130)
!       return "NAT-D (draft-ietf-ipsec-nat-t-ike-01 to 03)";
!     if (type == 131)
!       return "NAT-OA (draft-ietf-ipsec-nat-t-ike-01 to 04)";
!     return "Private USE";
!   } else if (isakmp_version == 2) {
!     if (type > 127)
!       return "PRIVATE USE";
!     if (type > 48)
!       return "RESERVED TO IANA";
      return "RESERVED";
!   }
!   return "Unknown payload type";
  }
  
  static const char *
! exchtype2str(guint8 type)
! {
  #define NUM_EXCHSTRS	7
    static const char * exchstrs[NUM_EXCHSTRS] = {
      "NONE",
***************
*** 1383,1409 ****
      "Transaction (Config Mode)"
    };
  
!   if (type < NUM_EXCHSTRS) return exchstrs[type];
!   if (type < 32)           return "ISAKMP Future Use";
!   switch (type) {
!   case 32:
!     return "Quick Mode";
!   case 33:
!     return "New Group Mode";
    }
!   if (type < 240)
!     return "DOI Specific Use";
!   return "Private Use";
  }
  
  static const char *
! doitype2str(guint32 type) {
    if (type == 1) return "IPSEC";
    return "Unknown DOI Type";
  }
  
  static const char *
! msgtype2str(guint16 type) {
  
  #define NUM_PREDEFINED	31
    static const char *msgs[NUM_PREDEFINED] = {
--- 1798,1843 ----
      "Transaction (Config Mode)"
    };
  
!   static struct type2str_t v2_exchstr[] = {
!     { 34, "IKE_SA_INIT" },
!     { 35, "IKE_AUTH " },
!     { 36, "CREATE_CHILD_SA" },
!     { 37, "INFORMATIONAL"},
!   };
! 
!   if (isakmp_version == 1) {
!     if (type < NUM_EXCHSTRS) return exchstrs[type];
!     if (type < 32)           return "ISAKMP Future Use";
!     switch (type) {
!     case 32:
!       return "Quick Mode";
!     case 33:
!       return "New Group Mode";
!     }
!     if (type < 240)
!       return "DOI Specific Use";
!     return "Private Use";
!   } else if (isakmp_version == 2) {
!     FIND_TYPE2STR(v2_exchstr, type);
!     if (type < 34)
!       return "RESERVED";
!     if (type < 240)
!       return "Reserved for IKEv2+";
!     return "Reserved for private use";
    }
!   return "Unknown exchange type";
  }
  
  static const char *
! doitype2str(guint32 type)
! {
    if (type == 1) return "IPSEC";
    return "Unknown DOI Type";
  }
  
  static const char *
! msgtype2str(guint16 type)
! {
  
  #define NUM_PREDEFINED	31
    static const char *msgs[NUM_PREDEFINED] = {
***************
*** 1440,1462 ****
      "UNEQUAL-PAYLOAD-LENGTHS"
    };
  
!   if (type < NUM_PREDEFINED) return msgs[type];
!   if (type < 8192)           return "RESERVED (Future Use)";
!   if (type < 16384)          return "Private Use";
!   if (type < 16385)          return "CONNECTED";
!   if (type < 24576)          return "RESERVED (Future Use) - status";
!   if (type < 24577)          return "RESPONDER-LIFETIME";
!   if (type < 24578)          return "REPLAY-STATUS";
!   if (type < 24579)          return "INITIAL-CONTACT";
!   if (type < 32768)          return "DOI-specific codes";
!   if (type < 40960)          return "Private Use - status";
!   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
! 
    return "Huh? You should never see this! Shame on you!";
  }
  
  static const char *
! situation2str(guint32 type) {
  
  #define SIT_MSG_NUM	1024
  #define SIT_IDENTITY	0x01
--- 1874,1935 ----
      "UNEQUAL-PAYLOAD-LENGTHS"
    };
  
!   static struct type2str_t v2_notifmsg[] = {
!     {     0, "RESERVED" },
!     {     4, "INVALID_IKE_SPI" },
!     {     5, "INVALID_MAJOR_VERSION" },
!     {     7, "INVALID_SYNTAX" },
!     {     9, "INVALID_MESSAGE_ID" },
!     {    11, "INVALID_SPI" },
!     {    14, "NO_PROPOSAL_CHOSEN" },
!     {    17, "INVALID_KE_PAYLOAD" },
!     {    24, "AUTHENTICATION_FAILED" },
!     {    34, "SINGLE_PAIR_REQUIRED" },
!     {    35, "NO_ADDITIONAL_SAS" },
!     {    36, "INTERNAL_ADDRESS_FAILURE" },
!     {    37, "FAILED_CP_REQUIRED" },
!     {    38, "TS_UNACCEPTABLE" },
!     {    39, "INVALID_SELECTORS" },
!     { 16384, "INITIAL_CONTACT" },
!     { 16385, "SET_WINDOW_SIZE" },
!     { 16386, "ADDITIONAL_TS_POSSIBLE" },
!     { 16387, "IPCOMP_SUPPORTED" },
!     { 16388, "NAT_DETECTION_SOURCE_IP" },
!     { 16389, "NAT_DETECTION_DESTINATION_IP" },
!     { 16390, "COOKIE" },
!     { 16391, "USE_TRANSPORT_MODE" },
!     { 16392, "HTTP_CERT_LOOKUP_SUPPORTED" },
!     { 16393, "REKEY_SA" },
!     { 16394, "ESP_TFC_PADDING_NOT_SUPPORTED" },
!     { 16395, "NON_FIRST_FRAGMENTS_ALSO" },
!   };
!   
!   if (isakmp_version == 1) {
!     if (type < NUM_PREDEFINED) return msgs[type];
!     if (type < 8192)           return "RESERVED (Future Use)";
!     if (type < 16384)          return "Private Use";
!     if (type < 16385)          return "CONNECTED";
!     if (type < 24576)          return "RESERVED (Future Use) - status";
!     if (type < 24577)          return "RESPONDER-LIFETIME";
!     if (type < 24578)          return "REPLAY-STATUS";
!     if (type < 24579)          return "INITIAL-CONTACT";
!     if (type < 32768)          return "DOI-specific codes";
!     if (type < 40960)          return "Private Use - status";
!     if (type < 65535)          return "RESERVED (Future Use) - status (2)";
!   } else if (isakmp_version == 2) {
!     FIND_TYPE2STR(v2_notifmsg, type);
!     if (type >= 40 && type <= 8191) return "RESERVED TO IANA - Error types";
!     if (type >= 16396 && type <= 40959) return "RESERVED TO IANA - STATUS TYPES";
!     if (type >= 8192 && type <= 16383) return "Private Use - Errors";
!     if (type >= 40960 && type <= 65535) return "Private Use - STATUS TYPES";
!   
!   } 
    return "Huh? You should never see this! Shame on you!";
  }
  
  static const char *
! situation2str(guint32 type)
! {
  
  #define SIT_MSG_NUM	1024
  #define SIT_IDENTITY	0x01
***************
*** 1511,1517 ****
  }
  
  static const char *
! value2str(int ike_p1, guint16 att_type, guint32 value) {
  
    if (value == 0) return "RESERVED";
  
--- 1984,2001 ----
  }
  
  static const char *
! v2_attrvalue2str(guint16 att_type, guint32 value)
! {
!   value = 0;	/* dummy to be less warning in compiling it */
!   switch (att_type) {
!   case 14: return "Key-Length";
!   default: return "UNKNOWN-ATTRIBUTE-TYPE";
!   }
! }
! 
! static const char *
! value2str(int ike_p1, guint16 att_type, guint32 value)
! {
  
    if (value == 0) return "RESERVED";
  
***************
*** 1648,1654 ****
  }
  
  static const char *
! attrtype2str(guint8 type) {
    switch (type) {
    case 0: return "Reserved";
    case 1: return "ISAKMP_CFG_REQUEST";
--- 2132,2139 ----
  }
  
  static const char *
! attrtype2str(guint8 type)
! {
    switch (type) {
    case 0: return "Reserved";
    case 1: return "ISAKMP_CFG_REQUEST";
***************
*** 1662,1668 ****
  }
  
  static const char *
! cfgattrident2str(guint16 ident) {
  #define NUM_ATTR_DEFINED	12
    static const char *msgs[NUM_PREDEFINED] = {
      "RESERVED",
--- 2147,2225 ----
  }
  
  static const char *
! id2str(guint8 type)
! {
!   static struct type2str_t idtypestr[] = {
!     {  0, "RESERVED" },
!     {  1, "IPV4_ADDR" },
!     {  2, "FQDN" },
!     {  3, "USER_FQDN" },
!     {  4, "IPV4_ADDR_SUBNET" },
!     {  5, "IPV6_ADDR" },
!     {  6, "IPV6_ADDR_SUBNET" },
!     {  7, "IPV4_ADDR_RANGE" },
!     {  8, "IPV6_ADDR_RANGE" },
!     {  9, "DER_ASN1_DN" },
!     { 10, "DER_ASN1_GN" },
!     { 11, "KEY_ID" },
!   };
!   static struct type2str_t v2_idtypestr[] = {
!     {  0, "RESERVED" },
!     {  1, "IPV4_ADDR" },
!     {  2, "FQDN" },
!     {  3, "USER_FQDN" },
!     {  4, "IPV4_ADDR_SUBNET" },
!     {  5, "IPV6_ADDR" },
!     {  9, "DER_ASN1_DN" },
!     { 10, "DER_ASN1_GN" },
!     { 11, "KEY_ID" },
!   };
! 
!   if (isakmp_version == 1)
!     FIND_TYPE2STR(idtypestr, type);
!   else if (isakmp_version == 2) {
!     FIND_TYPE2STR(v2_idtypestr, type);
!     if ((type >= 6 && type <=8) || (type >= 12 && type <= 200))
!       return "Reserved to IANA";
!     else if (type >= 201 && type <= 255)
!       return "Reserved for private use";
!   }
!   return "UNKNOWN-ID-TYPE";
! }
! 
! static const char *
! v2_tstype2str(guint8 type)
! {
!   static struct type2str_t v2_tstypestr[] = {
!     {     7, "TS_IPV4_ADDR_RANGE" },
!     {     8, "TS_IPV6_ADDR_RANGE" },
!   };
! 
!   FIND_TYPE2STR(v2_tstypestr, type);
!   if (type <= 6) return "RESERVED";
!   if (type >= 9 && type <= 240) return "RESERVED TO IANA";
!   if (type >= 241 && type <= 255) return "PRIVATE USE";
!   return "Huh? You should never see this! Shame on you!";
! }
! 
! static const char *
! v2_auth2str(guint8 type)
! {
!   static struct type2str_t v2_authstr[] = {
!     {     1, "RSA Digital Signature" },
!     {     2, "Shared Key Message Integrity Code" },
!     {     3, "DSS Digital Signature" },
!   };
! 
!   FIND_TYPE2STR(v2_authstr, type);
!   if (type == 0 || (type >= 4 && type <= 200)) return "RESERVED TO IANA";
!   if (type >= 201 && type <= 255) return "PRIVATE USE";
!   return "Huh? You should never see this! Shame on you!";
! }
! 
! static const char *
! cfgattrident2str(guint16 ident)
! {
  #define NUM_ATTR_DEFINED	12
    static const char *msgs[NUM_PREDEFINED] = {
      "RESERVED",
***************
*** 1699,1726 ****
  }
  
  static const char *
! certtype2str(guint8 type) {
! #define NUM_CERTTYPE 11
!   static const char *msgs[NUM_CERTTYPE] = {
!     "NONE",
!     "PKCS #7 wrapped X.509 certificate",
!     "PGP Certificate",
!     "DNS Signed Key",
!     "X.509 Certificate - Signature",
!     "X.509 Certificate - Key Exchange",
!     "Kerberos Tokens",
!     "Certificate Revocation List (CRL)",
!     "Authority Revocation List (ARL)",
!     "SPKI Certificate",
!     "X.509 Certificate - Attribute",
    };
!   if(type > NUM_CERTTYPE)
!     return "RESERVED";
!   return msgs[type];
  }
  
  static gboolean
! get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
  
    switch (len) {
    case 1:
--- 2256,2307 ----
  }
  
  static const char *
! certtype2str(guint8 type)
! {
!   static struct type2str_t certtypestr[] = {
!     {  0, "NONE" },
!     {  1, "PKCS #7 wrapped X.509 certificate" },
!     {  2, "PGP Certificate" },
!     {  3, "DNS Signed Key" },
!     {  4, "X.509 Certificate - Signature" },
!     {  5, "X.509 Certificate - Key Exchange" },
!     {  6, "Kerberos Tokens" },
!     {  7, "Certificate Revocation List (CRL)" },
!     {  8, "Authority Revocation List (ARL)" },
!     {  9, "SPKI Certificate" },
!     { 10, "X.509 Certificate - Attribute" },
    };
!   static struct type2str_t v2_certtypestr[] = {
!     {  0, "RESERVED" },
!     {  1, "PKCS #7 wrapped X.509 certificate" },
!     {  2, "PGP Certificate" },
!     {  3, "DNS Signed Key" },
!     {  4, "X.509 Certificate - Signature" },
!     {  5, "*undefined by any document*" },
!     {  6, "Kerberos Tokens" },
!     {  7, "Certificate Revocation List (CRL)" },
!     {  8, "Authority Revocation List (ARL)" },
!     {  9, "SPKI Certificate" },
!     { 10, "X.509 Certificate - Attribute" },
!     { 11, "Raw RSA Key" },
!     { 12, "Hash and URL of X.509 certificate" },
!     { 13, "Hash and URL of X.509 bundle" },
!   };
!   if (isakmp_version == 1)
!     FIND_TYPE2STR(certtypestr, type);
!   else if (isakmp_version == 2) {
!     FIND_TYPE2STR(v2_certtypestr, type);
!     if (type >= 14 && type <= 200)
!       return "RESERVED to IANA";
!     else if (type >= 201 && type <= 255)
!       return "PRIVATE USE";
!   }
!   return "RESERVED";
  }
  
  static gboolean
! get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p)
! {
  
    switch (len) {
    case 1: