Dissect NAT-Discovery and NAT-Original Address payloads, and just use
[obnox/wireshark/wip.git] / packet-isakmp.c
1 /* packet-isakmp.c
2  * Routines for the Internet Security Association and Key Management Protocol
3  * (ISAKMP) (RFC 2408) and the Internet IP Security Domain of Interpretation
4  * for ISAKMP (RFC 2407)
5  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
6  *
7  * $Id: packet-isakmp.c,v 1.70 2003/10/08 05:36:19 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <glib.h>
36
37 #ifdef NEED_SNPRINTF_H
38 # include "snprintf.h"
39 #endif
40
41 #include <epan/packet.h>
42 #include <epan/ipv6-utils.h>
43 #include "ipproto.h"
44
45 #define isakmp_min(a, b)  ((a<b) ? a : b)
46
47 static int proto_isakmp = -1;
48
49 static gint ett_isakmp = -1;
50 static gint ett_isakmp_flags = -1;
51 static gint ett_isakmp_payload = -1;
52
53 #define UDP_PORT_ISAKMP 500
54 #define TCP_PORT_ISAKMP 500
55
56 #define NUM_PROTO_TYPES 5
57 #define proto2str(t)    \
58   ((t < NUM_PROTO_TYPES) ? prototypestr[t] : "UNKNOWN-PROTO-TYPE")
59
60 static const char *prototypestr[NUM_PROTO_TYPES] = {
61   "RESERVED",
62   "ISAKMP",
63   "IPSEC_AH",
64   "IPSEC_ESP",
65   "IPCOMP"
66 };
67
68 #define NUM_P1_ATT_TYPES        17
69 #define p1_atttype2str(t)       \
70   ((t < NUM_P1_ATT_TYPES) ? p1_atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
71
72 static const char *p1_atttypestr[NUM_P1_ATT_TYPES] = {
73   "UNKNOWN-ATTRIBUTE-TYPE",
74   "Encryption-Algorithm",
75   "Hash-Algorithm",
76   "Authentication-Method",
77   "Group-Description",
78   "Group-Type",
79   "Group-Prime",
80   "Group-Generator-One",
81   "Group-Generator-Two",
82   "Group-Curve-A",
83   "Group-Curve-B",
84   "Life-Type",
85   "Life-Duration",
86   "PRF",
87   "Key-Length",
88   "Field-Size",
89   "Group-Order"
90 };
91
92 #define NUM_ATT_TYPES   11
93 #define atttype2str(t)  \
94   ((t < NUM_ATT_TYPES) ? atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
95
96 static const char *atttypestr[NUM_ATT_TYPES] = {
97   "UNKNOWN-ATTRIBUTE-TYPE",
98   "SA-Life-Type",
99   "SA-Life-Duration",
100   "Group-Description",
101   "Encapsulation-Mode",
102   "Authentication-Algorithm",
103   "Key-Length",
104   "Key-Rounds",
105   "Compress-Dictinary-Size",
106   "Compress-Private-Algorithm",
107   "ECN Tunnel"
108 };
109
110 #define NUM_TRANS_TYPES 2
111 #define trans2str(t)    \
112   ((t < NUM_TRANS_TYPES) ? transtypestr[t] : "UNKNOWN-TRANS-TYPE")
113
114 static const char *transtypestr[NUM_TRANS_TYPES] = {
115   "RESERVED",
116   "KEY_IKE"
117 };
118
119 #define NUM_AH_TRANS_TYPES      8
120 #define ah_trans2str(t)         \
121   ((t < NUM_AH_TRANS_TYPES) ? ah_transtypestr[t] : "UNKNOWN-AH-TRANS-TYPE")
122
123 static const char *ah_transtypestr[NUM_AH_TRANS_TYPES] = {
124   "RESERVED",
125   "RESERVED",
126   "MD5",
127   "SHA",
128   "DES",
129   "SHA2-256",
130   "SHA2-384",
131   "SHA2-512"
132 };
133
134 #define NUM_ESP_TRANS_TYPES     13
135 #define esp_trans2str(t)        \
136   ((t < NUM_ESP_TRANS_TYPES) ? esp_transtypestr[t] : "UNKNOWN-ESP-TRANS-TYPE")
137
138 static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
139   "RESERVED",
140   "DES-IV64",
141   "DES",
142   "3DES",
143   "RC5",
144   "IDEA",
145   "CAST",
146   "BLOWFISH",
147   "3IDEA",
148   "DES-IV32",
149   "RC4",
150   "NULL",
151   "AES"
152 };
153
154 #define NUM_IPCOMP_TRANS_TYPES    5
155 #define ipcomp_trans2str(t)  \
156   ((t < NUM_IPCOMP_TRANS_TYPES) ? ipcomp_transtypestr[t] : "UNKNOWN-IPCOMP-TRANS-TYPE")
157
158 static const char *ipcomp_transtypestr[NUM_IPCOMP_TRANS_TYPES] = {
159   "RESERVED",
160   "OUI",
161   "DEFLATE",
162   "LZS",
163   "LZJH"
164 };
165
166 #define NUM_ID_TYPES    12
167 #define id2str(t)       \
168   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
169
170 static const char *idtypestr[NUM_ID_TYPES] = {
171   "RESERVED",
172   "IPV4_ADDR",
173   "FQDN",
174   "USER_FQDN",
175   "IPV4_ADDR_SUBNET",
176   "IPV6_ADDR",
177   "IPV6_ADDR_SUBNET",
178   "IPV4_ADDR_RANGE",
179   "IPV6_ADDR_RANGE",
180   "DER_ASN1_DN",
181   "DER_ASN1_GN",
182   "KEY_ID"
183 };
184
185 #define NUM_GRPDESC_TYPES 19
186 #define grpdesc2str(t) ((t < NUM_GRPDESC_TYPES) ? grpdescstr[t] : "UNKNOWN-GROUP-DESCRIPTION")
187
188 static const char *grpdescstr[NUM_GRPDESC_TYPES] = {
189   "UNDEFINED - 0",
190   "Default 768-bit MODP group",
191   "Alternate 1024-bit MODP group",
192   "EC2N group on GP[2^155] group",
193   "EC2N group on GP[2^185] group",
194   "1536 bit MODP group",
195   "EC2N group over GF[2^163]",
196   "EC2N group over GF[2^163]",
197   "EC2N group over GF[2^283]",
198   "EC2N group over GF[2^283]",
199   "EC2N group over GF[2^409]",
200   "EC2N group over GF[2^409]",
201   "EC2N group over GF[2^571]",
202   "EC2N group over GF[2^571]",
203   "2048 bit MODP group",
204   "3072 bit MODP group",
205   "4096 bit MODP group",
206   "6144 bit MODP group",
207   "8192 bit MODP group",
208 };
209
210 struct isakmp_hdr {
211   guint8        icookie[8];
212   guint8        rcookie[8];
213   guint8        next_payload;
214   guint8        version;
215   guint8        exch_type;
216   guint8        flags;
217 #define E_FLAG          0x01
218 #define C_FLAG          0x02
219 #define A_FLAG          0x04
220   guint32       message_id;
221   guint32       length;
222 };
223
224 struct udp_encap_hdr {
225   guint8        non_esp_marker[4];
226   guint32       esp_SPI;
227 };
228
229 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
230     guint8 *, guint16 *, proto_tree *);
231
232 static void dissect_sa(tvbuff_t *, int, int, proto_tree *, int);
233 static void dissect_proposal(tvbuff_t *, int, int, proto_tree *, int);
234 static void dissect_transform(tvbuff_t *, int, int, proto_tree *, int);
235 static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *, int);
236 static void dissect_id(tvbuff_t *, int, int, proto_tree *, int);
237 static void dissect_cert(tvbuff_t *, int, int, proto_tree *, int);
238 static void dissect_certreq(tvbuff_t *, int, int, proto_tree *, int);
239 static void dissect_hash(tvbuff_t *, int, int, proto_tree *, int);
240 static void dissect_sig(tvbuff_t *, int, int, proto_tree *, int);
241 static void dissect_nonce(tvbuff_t *, int, int, proto_tree *, int);
242 static void dissect_notif(tvbuff_t *, int, int, proto_tree *, int);
243 static void dissect_delete(tvbuff_t *, int, int, proto_tree *, int);
244 static void dissect_vid(tvbuff_t *, int, int, proto_tree *, int);
245 static void dissect_config(tvbuff_t *, int, int, proto_tree *, int);
246 static void dissect_nat_discovery(tvbuff_t *, int, int, proto_tree *, int);
247 static void dissect_nat_original_address(tvbuff_t *, int, int, proto_tree *, int);
248
249 static const char *payloadtype2str(guint8);
250 static const char *exchtype2str(guint8);
251 static const char *doitype2str(guint32);
252 static const char *msgtype2str(guint16);
253 static const char *situation2str(guint32);
254 static const char *value2str(int, guint16, guint16);
255 static const char *attrtype2str(guint8);
256 static const char *cfgattrident2str(guint16);
257 static const char *certtype2str(guint8);
258
259 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
260
261 #define LOAD_TYPE_NONE          0       /* payload type for None */
262 #define LOAD_TYPE_PROPOSAL      2       /* payload type for Proposal */
263 #define LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
264 #define NUM_LOAD_TYPES          17
265 #define loadtype2str(t) \
266   ((t < NUM_LOAD_TYPES) ? strfuncs[t].str : "Unknown payload type")
267
268 static struct strfunc {
269   const char *  str;
270   void          (*func)(tvbuff_t *, int, int, proto_tree *, int);
271 } strfuncs[NUM_LOAD_TYPES] = {
272   {"NONE",                      NULL              },
273   {"Security Association",      dissect_sa        },
274   {"Proposal",                  dissect_proposal  },
275   {"Transform",                 dissect_transform },
276   {"Key Exchange",              dissect_key_exch  },
277   {"Identification",            dissect_id        },
278   {"Certificate",               dissect_cert      },
279   {"Certificate Request",       dissect_certreq   },
280   {"Hash",                      dissect_hash      },
281   {"Signature",                 dissect_sig       },
282   {"Nonce",                     dissect_nonce     },
283   {"Notification",              dissect_notif     },
284   {"Delete",                    dissect_delete    },
285   {"Vendor ID",                 dissect_vid       },
286   {"Attrib",                    dissect_config    },
287   {"NAT-Discovery",             dissect_nat_discovery }, /* draft-ietf-ipsec-nat-t-ike */
288   {"NAT-Original Address",      dissect_nat_original_address } /* draft-ietf-ipsec-nat-t-ike */
289 };
290
291 #define VID_LEN 16
292 #define VID_MS_LEN 20
293 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 */
294
295 #define VID_CP_LEN 20
296 static const guint8 VID_CP[VID_CP_LEN] = {0xF4, 0xED, 0x19, 0xE0, 0xC1, 0x14, 0xEB, 0x51, 0x6F, 0xAA, 0xAC, 0x0E, 0xE3, 0x7D, 0xAF, 0x28, 0x7, 0xB4, 0x38, 0x1F};
297
298 static const guint8 VID_CYBERGUARD[VID_LEN] = {0x9A, 0xA1, 0xF3, 0xB4, 0x34, 0x72, 0xA4, 0x5D, 0x5F, 0x50, 0x6A, 0xEB, 0x26, 0xC, 0xF2, 0x14};
299
300 static const guint8 VID_draft_ietf_ipsec_nat_t_ike_03[VID_LEN] = {0x7D, 0x94, 0x19, 0xA6, 0x53, 0x10, 0xCA, 0x6F, 0x2C, 0x17, 0x9D, 0x92, 0x15, 0x52, 0x9d, 0x56}; /* according to http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-03.txt */
301
302 /* 
303 *  Seen in Netscreen. Suppose to be ASCII HeartBeat_Notify - but I don't know the rest yet. I suspect it then proceeds with
304 *  8k10, which means every 8K (?), and version 1.0 of the protocol (?). I won't add it to the code, until I know what it really
305 *  means. ykaul-at-netvision.net.il
306 */
307 static const guint8 VID_HeartBeat_Notify[VID_LEN] = {0x48, 0x65, 0x61, 0x72, 0x74, 0x42, 0x65, 0x61, 0x74, 0x5f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79}; 
308
309 static dissector_handle_t esp_handle;
310 static dissector_handle_t ah_handle;
311
312 static void
313 dissect_payloads(tvbuff_t *tvb, proto_tree *tree, guint8 initial_payload,
314                  int offset, int length)
315 {
316   guint8 payload, next_payload;
317   guint16               payload_length;
318   proto_tree *          ntree;
319
320   for (payload = initial_payload; length != 0; payload = next_payload) {
321     if (payload == LOAD_TYPE_NONE) {
322       /*
323        * What?  There's more stuff in this chunk of data, but the
324        * previous payload had a "next payload" type of None?
325        */
326       proto_tree_add_text(tree, tvb, offset, length,
327                           "Extra data: %s",
328                           tvb_bytes_to_str(tvb, offset, length));
329       break;
330     }
331     ntree = dissect_payload_header(tvb, offset, length, payload,
332       &next_payload, &payload_length, tree);
333     if (ntree == NULL)
334       break;
335     if (payload_length >= 4) {  /* XXX = > 4? */
336       if (payload < NUM_LOAD_TYPES && strfuncs[payload].func != NULL) {
337         (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
338                                   -1);
339       }
340       else {
341         proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
342             "Payload");
343       }
344     }
345     else {
346         proto_tree_add_text(ntree, tvb, offset + 4, 0,
347             "Payload (bogus, length is %u, must be at least 4)",
348             payload_length);
349         payload_length = 4;
350     }
351     offset += payload_length;
352     length -= payload_length;
353   }
354 }
355
356 static void
357 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
358 {
359   int                   offset = 0;
360   struct isakmp_hdr     hdr;
361   proto_item *          ti;
362   proto_tree *          isakmp_tree = NULL;
363   struct udp_encap_hdr  encap_hdr;
364   guint32               len;
365   static const guint8   non_esp_marker[4] = { 0, 0, 0, 0 };
366   tvbuff_t *            next_tvb;
367
368   if (check_col(pinfo->cinfo, COL_PROTOCOL))
369     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISAKMP");
370   if (check_col(pinfo->cinfo, COL_INFO))
371     col_clear(pinfo->cinfo, COL_INFO);
372
373   hdr.length = tvb_get_ntohl(tvb, offset + sizeof(hdr) - sizeof(hdr.length));
374
375   if (tree) {
376     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, hdr.length, FALSE);
377     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
378   }
379
380   tvb_memcpy(tvb, (guint8 *)&encap_hdr, 0, sizeof(encap_hdr));
381
382   if (encap_hdr.non_esp_marker[0] == 0xFF) {
383     if (check_col(pinfo->cinfo, COL_INFO))
384       col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - NAT Keepalive");
385     return;
386   }
387   if (memcmp(encap_hdr.non_esp_marker,non_esp_marker,4) == 0) {
388     if (check_col(pinfo->cinfo, COL_INFO))
389           col_add_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - ESP");
390     if (tree)
391       proto_tree_add_text(isakmp_tree, tvb, offset,
392                           sizeof(encap_hdr.non_esp_marker),
393                           "Non-ESP-Marker");
394     offset += sizeof(encap_hdr.non_esp_marker);
395     next_tvb = tvb_new_subset(tvb, offset, -1, -1);
396     call_dissector(esp_handle, next_tvb, pinfo, tree);
397     return;
398   }
399   hdr.exch_type = tvb_get_guint8(tvb, sizeof(hdr.icookie) + sizeof(hdr.rcookie) + sizeof(hdr.next_payload) + sizeof(hdr.version));
400   if (check_col(pinfo->cinfo, COL_INFO))
401     col_add_str(pinfo->cinfo, COL_INFO, exchtype2str(hdr.exch_type));
402
403   if (tree) {
404     tvb_memcpy(tvb, (guint8 *)&hdr.icookie, offset, sizeof(hdr.icookie));
405     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.icookie),
406                         "Initiator cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.icookie)));
407     offset += sizeof(hdr.icookie);
408
409     tvb_memcpy(tvb, (guint8 *)&hdr.rcookie, offset, sizeof(hdr.rcookie));
410     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.rcookie),
411                         "Responder cookie: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.rcookie)));
412     offset += sizeof(hdr.rcookie);
413
414     hdr.next_payload = tvb_get_guint8(tvb, offset);
415     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.next_payload),
416                         "Next payload: %s (%u)",
417                         payloadtype2str(hdr.next_payload), hdr.next_payload);
418     offset += sizeof(hdr.next_payload);
419
420     hdr.version = tvb_get_guint8(tvb, offset);
421     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.version),
422                         "Version: %u.%u",
423                         hi_nibble(hdr.version), lo_nibble(hdr.version));
424     offset += sizeof(hdr.version);
425
426     hdr.exch_type = tvb_get_guint8(tvb, offset);
427     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.exch_type),
428                         "Exchange type: %s (%u)",
429                         exchtype2str(hdr.exch_type), hdr.exch_type);
430     offset += sizeof(hdr.exch_type);
431
432     {
433       proto_item *      fti;
434       proto_tree *      ftree;
435
436       hdr.flags = tvb_get_guint8(tvb, offset);
437       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.flags), "Flags");
438       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
439
440       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
441                           decode_boolean_bitfield(hdr.flags, E_FLAG, sizeof(hdr.flags)*8,
442                                                   "Encryption", "No encryption"));
443       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
444                           decode_boolean_bitfield(hdr.flags, C_FLAG, sizeof(hdr.flags)*8,
445                                                   "Commit", "No commit"));
446       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
447                           decode_boolean_bitfield(hdr.flags, A_FLAG, sizeof(hdr.flags)*8,
448                                                   "Authentication", "No authentication"));
449       offset += sizeof(hdr.flags);
450     }
451
452     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.message_id),
453         "Message ID: 0x%s", tvb_bytes_to_str(tvb, offset, sizeof(hdr.message_id)));
454     offset += sizeof(hdr.message_id);
455
456     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr.length),
457                         "Length: %u", hdr.length);
458     offset += sizeof(hdr.length);
459
460     len = hdr.length - sizeof(hdr);
461
462     if (hdr.flags & E_FLAG) {
463       if (len && isakmp_tree) {
464         proto_tree_add_text(isakmp_tree, tvb, offset, len,
465                         "Encrypted payload (%d byte%s)",
466                         len, plurality(len, "", "s"));
467       }
468     } else
469       dissect_payloads(tvb, isakmp_tree, hdr.next_payload, offset, len);
470   }
471 }
472
473 static proto_tree *
474 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
475     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
476 {
477   guint8                next_payload;
478   guint16               payload_length;
479   proto_item *          ti;
480   proto_tree *          ntree;
481
482   if (length < 4) {
483     proto_tree_add_text(tree, tvb, offset, length,
484           "Not enough room in payload for all transforms");
485     return NULL;
486   }
487   next_payload = tvb_get_guint8(tvb, offset);
488   payload_length = tvb_get_ntohs(tvb, offset + 2);
489
490   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
491             "%s payload", loadtype2str(payload));
492   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
493
494   proto_tree_add_text(ntree, tvb, offset, 1,
495                       "Next payload: %s (%u)",
496                       payloadtype2str(next_payload), next_payload);
497   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
498
499   *next_payload_p = next_payload;
500   *payload_length_p = payload_length;
501   return ntree;
502 }
503
504 static void
505 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
506     int unused _U_)
507 {
508   guint32               doi;
509   guint32               situation;
510
511   if (length < 4) {
512     proto_tree_add_text(tree, tvb, offset, length,
513                         "DOI %s (length is %u, should be >= 4)",
514                         tvb_bytes_to_str(tvb, offset, length), length);
515     return;
516   }
517   doi = tvb_get_ntohl(tvb, offset);
518   proto_tree_add_text(tree, tvb, offset, 4,
519                       "Domain of interpretation: %s (%u)",
520                       doitype2str(doi), doi);
521   offset += 4;
522   length -= 4;
523
524   if (doi == 1) {
525     /* IPSEC */
526     if (length < 4) {
527       proto_tree_add_text(tree, tvb, offset, length,
528                           "Situation: %s (length is %u, should be >= 4)",
529                           tvb_bytes_to_str(tvb, offset, length), length);
530       return;
531     }
532     situation = tvb_get_ntohl(tvb, offset);
533     proto_tree_add_text(tree, tvb, offset, 4,
534                         "Situation: %s (%u)",
535                         situation2str(situation), situation);
536     offset += 4;
537     length -= 4;
538
539     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length);
540   } else {
541     /* Unknown */
542     proto_tree_add_text(tree, tvb, offset, length,
543                         "Situation: %s",
544                         tvb_bytes_to_str(tvb, offset, length));
545   }
546 }
547
548 static void
549 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
550     int unused _U_)
551 {
552   guint8                protocol_id;
553   guint8                spi_size;
554   guint8                num_transforms;
555   guint8                next_payload;
556   guint16               payload_length;
557   proto_tree *          ntree;
558   guint8                proposal_num;
559
560   proposal_num = tvb_get_guint8(tvb, offset);
561
562   proto_item_append_text(tree, " # %d",proposal_num);
563   proto_tree_add_text(tree, tvb, offset, 1,
564                       "Proposal number: %u", proposal_num);
565   offset += 1;
566   length -= 1;
567
568   protocol_id = tvb_get_guint8(tvb, offset);
569   proto_tree_add_text(tree, tvb, offset, 1,
570                       "Protocol ID: %s (%u)",
571                       proto2str(protocol_id), protocol_id);
572   offset += 1;
573   length -= 1;
574
575   spi_size = tvb_get_guint8(tvb, offset);
576   proto_tree_add_text(tree, tvb, offset, 1,
577                       "SPI size: %u", spi_size);
578   offset += 1;
579   length -= 1;
580
581   num_transforms = tvb_get_guint8(tvb, offset);
582   proto_tree_add_text(tree, tvb, offset, 1,
583                       "Number of transforms: %u", num_transforms);
584   offset += 1;
585   length -= 1;
586
587   if (spi_size) {
588     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI: %s",
589                         tvb_bytes_to_str(tvb, offset, spi_size));
590     offset += spi_size;
591     length -= spi_size;
592   }
593
594   while (num_transforms > 0) {
595     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
596       &next_payload, &payload_length, tree);
597     if (ntree == NULL)
598       break;
599     if (length < payload_length) {
600       proto_tree_add_text(tree, tvb, offset + 4, length,
601           "Not enough room in payload for all transforms");
602       break;
603     }
604     if (payload_length >= 4)
605       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
606     else
607       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
608     offset += payload_length;
609     length -= payload_length;
610     num_transforms--;
611   }
612 }
613
614 static void
615 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
616     int protocol_id)
617 {
618   guint8                transform_id;
619   guint8                transform_num;
620
621   transform_num = tvb_get_guint8(tvb, offset);
622   proto_item_append_text(tree," # %d",transform_num);
623   proto_tree_add_text(tree, tvb, offset, 1,
624                       "Transform number: %u", transform_num);
625   offset += 1;
626   length -= 1;
627
628   transform_id = tvb_get_guint8(tvb, offset);
629   switch (protocol_id) {
630   default:
631     proto_tree_add_text(tree, tvb, offset, 1,
632                         "Transform ID: %u", transform_id);
633     break;
634   case 1:       /* ISAKMP */
635     proto_tree_add_text(tree, tvb, offset, 1,
636                         "Transform ID: %s (%u)",
637                         trans2str(transform_id), transform_id);
638     break;
639   case 2:       /* AH */
640     proto_tree_add_text(tree, tvb, offset, 1,
641                         "Transform ID: %s (%u)",
642                         ah_trans2str(transform_id), transform_id);
643     break;
644   case 3:       /* ESP */
645     proto_tree_add_text(tree, tvb, offset, 1,
646                         "Transform ID: %s (%u)",
647                         esp_trans2str(transform_id), transform_id);
648     break;
649   case 4:       /* IPCOMP */
650     proto_tree_add_text(tree, tvb, offset, 1,
651                         "Transform ID: %s (%u)",
652                         ipcomp_trans2str(transform_id), transform_id);
653     break;
654   }
655   offset += 3;
656   length -= 3;
657
658   while (length>0) {
659     const char *str;
660     int ike_phase1 = 0;
661     guint16 aft     = tvb_get_ntohs(tvb, offset);
662     guint16 type    = aft & 0x7fff;
663     guint16 len;
664     guint32 val;
665     guint pack_len;
666
667     if (protocol_id == 1 && transform_id == 1) {
668       ike_phase1 = 1;
669       str = p1_atttype2str(type);
670     }
671     else {
672       str = atttype2str(type);
673     }
674
675     if (aft & 0x8000) {
676       val = tvb_get_ntohs(tvb, offset + 2);
677       proto_tree_add_text(tree, tvb, offset, 4,
678                           "%s (%u): %s (%u)",
679                           str, type,
680                           value2str(ike_phase1, type, val), val);
681       offset += 4;
682       length -= 4;
683     }
684     else {
685       len = tvb_get_ntohs(tvb, offset + 2);
686       pack_len = 4 + len;
687       if (!get_num(tvb, offset + 4, len, &val)) {
688         proto_tree_add_text(tree, tvb, offset, pack_len,
689                             "%s (%u): <too big (%u bytes)>",
690                             str, type, len);
691       } else {
692         proto_tree_add_text(tree, tvb, offset, pack_len,
693                             "%s (%u): %s (%u)",
694                             str, type,
695                             value2str(ike_phase1, type, val), val);
696       }
697       offset += pack_len;
698       length -= pack_len;
699     }
700   }
701 }
702
703 static void
704 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
705     int unused _U_)
706 {
707   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
708 }
709
710 static void
711 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
712     int unused _U_)
713 {
714   guint8                id_type;
715   guint8                protocol_id;
716   guint16               port;
717
718   id_type = tvb_get_guint8(tvb, offset);
719   proto_tree_add_text(tree, tvb, offset, 1,
720                       "ID type: %s (%u)", id2str(id_type), id_type);
721   offset += 1;
722   length -= 1;
723
724   protocol_id = tvb_get_guint8(tvb, offset);
725   if (protocol_id == 0) {
726     proto_tree_add_text(tree, tvb, offset, 1,
727                         "Protocol ID: Unused");
728   } else {
729     proto_tree_add_text(tree, tvb, offset, 1,
730                         "Protocol ID: %s (%u)",
731                         ipprotostr(protocol_id), protocol_id);
732   }
733   offset += 1;
734   length -= 1;
735
736   port = tvb_get_ntohs(tvb, offset);
737   if (port == 0)
738     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
739   else
740     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
741   offset += 2;
742   length -= 2;
743
744   switch (id_type) {
745     case 1:
746       proto_tree_add_text(tree, tvb, offset, length,
747                           "Identification data: %s",
748                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
749       break;
750     case 2:
751     case 3:
752       proto_tree_add_text(tree, tvb, offset, length,
753                           "Identification data: %.*s", length,
754                           tvb_get_ptr(tvb, offset, length));
755       break;
756     case 4:
757       proto_tree_add_text(tree, tvb, offset, length,
758                           "Identification data: %s/%s",
759                           ip_to_str(tvb_get_ptr(tvb, offset, 4)),
760                           ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
761       break;
762     default:
763       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
764       break;
765   }
766 }
767
768 static void
769 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
770     int unused _U_)
771 {
772   guint8                cert_enc;
773
774   cert_enc = tvb_get_guint8(tvb, offset);
775   proto_tree_add_text(tree, tvb, offset, 1,
776                       "Certificate encoding: %u - %s",
777                       cert_enc, certtype2str(cert_enc));
778   offset += 1;
779   length -= 1;
780
781   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
782 }
783
784 static void
785 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
786     int unused _U_)
787 {
788   guint8                cert_type;
789
790   cert_type = tvb_get_guint8(tvb, offset);
791   proto_tree_add_text(tree, tvb, offset, 1,
792                       "Certificate type: %u - %s",
793                       cert_type, certtype2str(cert_type));
794   offset += 1;
795   length -= 1;
796
797   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
798 }
799
800 static void
801 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
802     int unused _U_)
803 {
804   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
805 }
806
807 static void
808 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
809     int unused _U_)
810 {
811   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
812 }
813
814 static void
815 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
816     int unused _U_)
817 {
818   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
819 }
820
821 static void
822 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
823     int unused _U_)
824 {
825   guint32               doi;
826   guint8                protocol_id;
827   guint8                spi_size;
828   guint16               msgtype;
829
830   doi = tvb_get_ntohl(tvb, offset);
831   proto_tree_add_text(tree, tvb, offset, 4,
832                       "Domain of Interpretation: %s (%u)",
833                       doitype2str(doi), doi);
834   offset += 4;
835   length -= 4;
836
837   protocol_id = tvb_get_guint8(tvb, offset);
838   proto_tree_add_text(tree, tvb, offset, 1,
839                       "Protocol ID: %s (%u)",
840                       proto2str(protocol_id), protocol_id);
841   offset += 1;
842   length -= 1;
843
844   spi_size = tvb_get_guint8(tvb, offset);
845   proto_tree_add_text(tree, tvb, offset, 1,
846                       "SPI size: %u", spi_size);
847   offset += 1;
848   length -= 1;
849
850   msgtype = tvb_get_ntohs(tvb, offset);
851   proto_tree_add_text(tree, tvb, offset, 2,
852                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
853   offset += 2;
854   length -= 2;
855
856   if (spi_size) {
857     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
858     offset += spi_size;
859     length -= spi_size;
860   }
861
862   if (length > 0)
863     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
864 }
865
866 static void
867 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
868     int unused _U_)
869 {
870   guint32               doi;
871   guint8                protocol_id;
872   guint8                spi_size;
873   guint16               num_spis;
874   guint16               i;
875
876   doi = tvb_get_ntohl(tvb, offset);
877   proto_tree_add_text(tree, tvb, offset, 4,
878                       "Domain of Interpretation: %s (%u)",
879                       doitype2str(doi), doi);
880   offset += 4;
881   length -= 4;
882
883   protocol_id = tvb_get_guint8(tvb, offset);
884   proto_tree_add_text(tree, tvb, offset, 1,
885                       "Protocol ID: %s (%u)",
886                       proto2str(protocol_id), protocol_id);
887   offset += 1;
888   length -= 1;
889
890   spi_size = tvb_get_guint8(tvb, offset);
891   proto_tree_add_text(tree, tvb, offset, 1,
892                       "SPI size: %u", spi_size);
893   offset += 1;
894   length -= 1;
895
896   num_spis = tvb_get_ntohs(tvb, offset);
897   proto_tree_add_text(tree, tvb, offset, 2,
898                       "Number of SPIs: %u", num_spis);
899   offset += 2;
900   length -= 2;
901
902   for (i = 0; i < num_spis; ++i) {
903     if (length < spi_size) {
904       proto_tree_add_text(tree, tvb, offset, length,
905           "Not enough room in payload for all SPI's");
906       break;
907     }
908     proto_tree_add_text(tree, tvb, offset, spi_size,
909                         "SPI (%d)", i);
910     offset += spi_size;
911     length -= spi_size;
912   }
913 }
914
915 static void
916 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
917     int unused _U_)
918 {
919   guint32 CPproduct, CPversion;
920   const guint8 * pVID;
921   proto_item * pt;
922   proto_tree * ntree;
923   pVID = tvb_get_ptr(tvb, offset, length);
924   pt = proto_tree_add_text(tree, tvb, offset, length, "Vendor ID: ");
925   if (memcmp(pVID, VID_MS_W2K_WXP, isakmp_min(VID_MS_LEN, length)) == 0)
926         proto_item_append_text(pt, "Microsoft Win2K/WinXP");
927   else
928   if (memcmp(pVID, VID_CP, isakmp_min(VID_CP_LEN, length)) == 0)
929   {
930         proto_item_append_text(pt, "Check Point");
931         offset += VID_CP_LEN;
932         CPproduct = tvb_get_ntohl(tvb, offset);
933         ntree = proto_item_add_subtree(pt, ett_isakmp_payload);
934         pt = proto_tree_add_text(ntree, tvb, offset, sizeof(CPproduct), "Check Point Product: ");
935         switch (CPproduct) {
936                 case 1: proto_item_append_text(pt, "VPN-1");
937                         break;
938                 case 2: proto_item_append_text(pt, "SecuRemote/SecureClient");
939                         break;
940                 default: proto_item_append_text(pt, "Unknown CP product!");
941                         break;
942         }
943         offset += sizeof(CPproduct);
944         CPversion = tvb_get_ntohl(tvb, offset);
945         pt = proto_tree_add_text(ntree, tvb, offset, length, "Version: ");
946         switch (CPversion) {
947                 case 2: proto_item_append_text(pt, "4.1");
948                         break;
949                 case 3: proto_item_append_text(pt, "4.1 SP-1");
950                         break;
951                 case 4002: proto_item_append_text(pt, "4.1 (SP-2 or above)");
952                         break;
953                 case 5000: proto_item_append_text(pt, "NG");
954                         break;
955                 case 5001: proto_item_append_text(pt, "NG Feature Pack 1");
956                         break;
957                 case 5002: proto_item_append_text(pt, "NG Feature Pack 2");
958                         break;
959                 case 5003: proto_item_append_text(pt, "NG Feature Pack 3");
960                         break;
961                 default: proto_item_append_text(pt, " Uknown CP version!");
962                         break;
963         }
964   }
965   else
966   if (memcmp(pVID, VID_CYBERGUARD, isakmp_min(VID_LEN, length)) == 0)
967         proto_item_append_text(pt, "Cyber Guard");
968   else
969   if (memcmp(pVID,  VID_draft_ietf_ipsec_nat_t_ike_03, isakmp_min(VID_LEN, length)) == 0)
970         proto_item_append_text(pt, "draft-ietf-ipsec-nat-t-ike-03");
971   else
972         proto_item_append_text(pt, "unknown vendor ID: 0x%s",tvb_bytes_to_str(tvb, offset, length));
973 }
974
975 static void
976 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
977     int unused _U_)
978 {
979   guint8                type;
980
981   type = tvb_get_guint8(tvb, offset);
982   proto_tree_add_text(tree, tvb, offset, 1,
983                       "Type %s (%u)",attrtype2str(type),type);
984
985   offset += 2;
986   length -= 2;
987
988   proto_tree_add_text(tree, tvb, offset, 2,
989                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
990   offset += 2;
991   length -= 2;
992
993   while(length>0) {
994     guint16 aft     = tvb_get_ntohs(tvb, offset);
995     guint16 type    = aft & 0x7fff;
996     guint16 len;
997     guint32 val;
998     guint pack_len;
999
1000     if (aft & 0x8000) {
1001       val = tvb_get_ntohs(tvb, offset + 2);
1002       proto_tree_add_text(tree, tvb, offset, 4,
1003                           "%s (%u)", cfgattrident2str(type), val);
1004       offset += 4;
1005       length -= 4;
1006     }
1007     else {
1008       len = tvb_get_ntohs(tvb, offset + 2);
1009       pack_len = 4 + len;
1010       if (!get_num(tvb, offset + 4, len, &val)) {
1011         proto_tree_add_text(tree, tvb, offset, pack_len,
1012                             "%s: <too big (%u bytes)>",
1013                             cfgattrident2str(type), len);
1014       } else {
1015         proto_tree_add_text(tree, tvb, offset, 4,
1016                             "%s (%ue)", cfgattrident2str(type),
1017                             val);
1018       }
1019       offset += pack_len;
1020       length -= pack_len;
1021     }
1022   }
1023 }
1024
1025 static void
1026 dissect_nat_discovery(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
1027     int unused _U_)
1028 {
1029   proto_tree_add_text(tree, tvb, offset, length,
1030                       "Hash of address and port: %s",
1031                       tvb_bytes_to_str(tvb, offset, length));
1032 }
1033
1034 static void
1035 dissect_nat_original_address(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
1036     int unused _U_)
1037 {
1038   guint8 id_type;
1039   guint32 addr_ipv4;
1040   struct e_in6_addr addr_ipv6;
1041
1042   id_type = tvb_get_guint8(tvb, offset);
1043   proto_tree_add_text(tree, tvb, offset, 1,
1044                       "ID type: %s (%u)", id2str(id_type), id_type);
1045   offset += 1;
1046   length -= 1;
1047
1048   offset += 3;          /* reserved */
1049   length -= 3;
1050
1051   switch (id_type) {
1052
1053   case 1:       /* ID_IPV4_ADDR */
1054     if (length == 4) {
1055       tvb_memcpy(tvb, (guint8 *)&addr_ipv4, offset, length);
1056       proto_tree_add_text(tree, tvb, offset, length,
1057                           "Original address: %s",
1058                           ip_to_str((guint8 *)&addr_ipv4));
1059     } else {
1060       proto_tree_add_text(tree, tvb, offset, length,
1061                           "Original address: bad length, should be 4, is %u",
1062                           length);
1063     }
1064     break;
1065
1066   case 5:       /* ID_IPV6_ADDR */
1067     if (length == 16) {
1068       tvb_memcpy(tvb, (guint8 *)&addr_ipv6, offset, length);
1069       proto_tree_add_text(tree, tvb, offset, length,
1070                           "Original address: %s",
1071                           ip6_to_str(&addr_ipv6));
1072     } else {
1073       proto_tree_add_text(tree, tvb, offset, length,
1074                           "Original address: bad length, should be 16, is %u",
1075                           length);
1076     }
1077     break;
1078
1079   default:
1080     proto_tree_add_text(tree, tvb, offset, length,
1081                         "Original address: bad address type");
1082     break;
1083   }
1084 }
1085
1086 static const char *
1087 payloadtype2str(guint8 type) {
1088
1089   if (type < NUM_LOAD_TYPES)
1090     return strfuncs[type].str;
1091   if (type < 128)
1092     return "RESERVED";
1093   return "Private USE";
1094 }
1095
1096 static const char *
1097 exchtype2str(guint8 type) {
1098
1099 #define NUM_EXCHSTRS    7
1100   static const char * exchstrs[NUM_EXCHSTRS] = {
1101     "NONE",
1102     "Base",
1103     "Identity Protection (Main Mode)",
1104     "Authentication Only",
1105     "Aggressive",
1106     "Informational",
1107     "Transaction (Config Mode)"
1108   };
1109
1110   if (type < NUM_EXCHSTRS) return exchstrs[type];
1111   if (type < 32)           return "ISAKMP Future Use";
1112   switch (type) {
1113   case 32:
1114     return "Quick Mode";
1115   case 33:
1116     return "New Group Mode";
1117   }
1118   if (type < 240)
1119     return "DOI Specific Use";
1120   return "Private Use";
1121 }
1122
1123 static const char *
1124 doitype2str(guint32 type) {
1125   if (type == 1) return "IPSEC";
1126   return "Unknown DOI Type";
1127 }
1128
1129 static const char *
1130 msgtype2str(guint16 type) {
1131
1132 #define NUM_PREDEFINED  31
1133   static const char *msgs[NUM_PREDEFINED] = {
1134     "<UNKNOWN>",
1135     "INVALID-PAYLOAD-TYPE",
1136     "DOI-NOT-SUPPORTED",
1137     "SITUATION-NOT-SUPPORTED",
1138     "INVALID-COOKIE",
1139     "INVALID-MAJOR-VERSION",
1140     "INVALID-MINOR-VERSION",
1141     "INVALID-EXCHANGE-TYPE",
1142     "INVALID-FLAGS",
1143     "INVALID-MESSAGE-ID",
1144     "INVALID-PROTOCOL-ID",
1145     "INVALID-SPI",
1146     "INVALID-TRANSFORM-ID",
1147     "ATTRIBUTES-NOT-SUPPORTED",
1148     "NO-PROPOSAL-CHOSEN",
1149     "BAD-PROPOSAL-SYNTAX",
1150     "PAYLOAD-MALFORMED",
1151     "INVALID-KEY-INFORMATION",
1152     "INVALID-ID-INFORMATION",
1153     "INVALID-CERT-ENCODING",
1154     "INVALID-CERTIFICATE",
1155     "CERT-TYPE-UNSUPPORTED",
1156     "INVALID-CERT-AUTHORITY",
1157     "INVALID-HASH-INFORMATION",
1158     "AUTHENTICATION-FAILED",
1159     "INVALID-SIGNATURE",
1160     "ADDRESS-NOTIFICATION",
1161     "NOTIFY-SA-LIFETIME",
1162     "CERTIFICATE-UNAVAILABLE",
1163     "UNSUPPORTED-EXCHANGE-TYPE",
1164     "UNEQUAL-PAYLOAD-LENGTHS"
1165   };
1166
1167   if (type < NUM_PREDEFINED) return msgs[type];
1168   if (type < 8192)           return "RESERVED (Future Use)";
1169   if (type < 16384)          return "Private Use";
1170   if (type < 16385)          return "CONNECTED";
1171   if (type < 24576)          return "RESERVED (Future Use) - status";
1172   if (type < 24577)          return "RESPONDER-LIFETIME";
1173   if (type < 24578)          return "REPLAY-STATUS";
1174   if (type < 24579)          return "INITIAL-CONTACT";
1175   if (type < 32768)          return "DOI-specific codes";
1176   if (type < 40960)          return "Private Use - status";
1177   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
1178
1179   return "Huh? You should never see this! Shame on you!";
1180 }
1181
1182 static const char *
1183 situation2str(guint32 type) {
1184
1185 #define SIT_MSG_NUM     1024
1186 #define SIT_IDENTITY    0x01
1187 #define SIT_SECRECY     0x02
1188 #define SIT_INTEGRITY   0x04
1189
1190   static char   msg[SIT_MSG_NUM];
1191   int           n = 0;
1192   char *        sep = "";
1193   int           ret;
1194
1195   if (type & SIT_IDENTITY) {
1196     ret = snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
1197     if (ret == -1 || ret >= SIT_MSG_NUM-n) {
1198       /* Truncated. */
1199       msg[SIT_MSG_NUM-1] = '\0';
1200       return msg;
1201     }
1202     n += ret;
1203     sep = " & ";
1204   }
1205   if (type & SIT_SECRECY) {
1206     if (n >= SIT_MSG_NUM) {
1207       /* No more room. */
1208       return msg;
1209     }
1210     ret = snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
1211     if (ret == -1 || ret >= SIT_MSG_NUM-n) {
1212       /* Truncated. */
1213       msg[SIT_MSG_NUM-1] = '\0';
1214       return msg;
1215     }
1216     n += ret;
1217     sep = " & ";
1218   }
1219   if (type & SIT_INTEGRITY) {
1220     if (n >= SIT_MSG_NUM) {
1221       /* No more room. */
1222       return msg;
1223     }
1224     ret = snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
1225     if (ret == -1 || ret >= SIT_MSG_NUM-n) {
1226       /* Truncated. */
1227       msg[SIT_MSG_NUM-1] = '\0';
1228       return msg;
1229     }
1230     n += ret;
1231     sep = " & ";
1232   }
1233
1234   return msg;
1235 }
1236
1237 static const char *
1238 value2str(int ike_p1, guint16 att_type, guint16 value) {
1239
1240   if (value == 0) return "RESERVED";
1241
1242   if (!ike_p1) {
1243   switch (att_type) {
1244     case 1:
1245       switch (value) {
1246         case 0: return "RESERVED";
1247         case 1:  return "Seconds";
1248         case 2:  return "Kilobytes";
1249         default: return "UNKNOWN-SA-VALUE";
1250       }
1251     case 2:
1252       return "Duration-Value";
1253     case 3:
1254       return "Group-Value";
1255     case 4:
1256       switch (value) {
1257         case 0:  return "RESERVED";
1258         case 1:  return "Tunnel";
1259         case 2:  return "Transport";
1260         case 3:  return "UDP-Encapsulated-Tunnel"; /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
1261         case 4:  return "UDP-Encapsulated-Transport"; /* http://www.ietf.org/internet-drafts/draft-ietf-ipsec-nat-t-ike-05.txt */
1262         case 61440: return "Check Point IPSec UDP Encapsulation";
1263         case 61443: return "UDP-Encapsulated-Tunnel (draft)";
1264         case 61444: return "UDP-Encapsulated-Transport (draft)";
1265         default: return "UNKNOWN-ENCAPSULATION-VALUE";
1266       }
1267     case 5:
1268       switch (value) {
1269         case 0:  return "RESERVED";
1270         case 1:  return "HMAC-MD5";
1271         case 2:  return "HMAC-SHA";
1272         case 3:  return "DES-MAC";
1273         case 4:  return "KPDK";
1274         case 5:  return "HMAC-SHA2-256";
1275         case 6:  return "HMAC-SHA2-384";
1276         case 7:  return "HMAC-SHA2-512";
1277         default: return "UNKNOWN-AUTHENTICATION-VALUE";
1278       }
1279     case 6:
1280       return "Key-Length";
1281     case 7:
1282       return "Key-Rounds";
1283     case 8:
1284       return "Compress-Dictionary-size";
1285     case 9:
1286       return "Compress Private Algorithm";
1287     default: return "UNKNOWN-ATTRIBUTE-TYPE";
1288   }
1289   }
1290   else {
1291     switch (att_type) {
1292       case 1:
1293         switch (value) {
1294           case 1:  return "DES-CBC";
1295           case 2:  return "IDEA-CBC";
1296           case 3:  return "BLOWFISH-CBC";
1297           case 4:  return "RC5-R16-B64-CBC";
1298           case 5:  return "3DES-CBC";
1299           case 6:  return "CAST-CBC";
1300           case 7:  return "AES-CBC";
1301           default: return "UNKNOWN-ENCRYPTION-ALG";
1302         }
1303       case 2:
1304         switch (value) {
1305           case 1:  return "MD5";
1306           case 2:  return "SHA";
1307           case 3:  return "TIGER";
1308           case 4:  return "SHA2-256";
1309           case 5:  return "SHA2-384";
1310           case 6:  return "SHA2-512";
1311           default: return "UNKNOWN-HASH-ALG";
1312         }
1313       case 3:
1314         switch (value) {
1315           case 1:  return "PSK";
1316           case 2:  return "DSS-SIG";
1317           case 3:  return "RSA-SIG";
1318           case 4:  return "RSA-ENC";
1319           case 5:  return "RSA-Revised-ENC";
1320           case 6:  return "Encryption with El-Gamal";
1321           case 7:  return "Revised encryption with El-Gamal";
1322           case 8:  return "ECDSA signatures";
1323           case 9:  return "AES-XCBC-MAC";
1324           case 64221: return "HybridInitRSA";
1325           case 64222: return "HybridRespRSA";
1326           case 64223: return "HybridInitDSS";
1327           case 64224: return "HybridRespDSS";
1328           case 65001: return "XAUTHInitPreShared";
1329           case 65002: return "XAUTHRespPreShared";
1330           case 65003: return "XAUTHInitDSS";
1331           case 65004: return "XAUTHRespDSS";
1332           case 65005: return "XAUTHInitRSA";
1333           case 65006: return "XAUTHRespRSA";
1334           case 65007: return "XAUTHInitRSAEncryption";
1335           case 65008: return "XAUTHRespRSAEncryption";
1336           case 65009: return "XAUTHInitRSARevisedEncryption";
1337           case 65010: return "XAUTHRespRSARevisedEncryption";
1338           default: return "UNKNOWN-AUTH-METHOD";
1339         }
1340       case 4: return grpdesc2str(value);
1341       case 6:
1342       case 7:
1343       case 8:
1344       case 9:
1345       case 10:
1346       case 16:
1347         return "Group-Value";
1348       case 5:
1349         switch (value) {
1350           case 1:  return "MODP";
1351           case 2:  return "ECP";
1352           case 3:  return "EC2N";
1353           default: return "UNKNOWN-GROUPT-TYPE";
1354         }
1355       case 11:
1356         switch (value) {
1357           case 1:  return "Seconds";
1358           case 2:  return "Kilobytes";
1359           default: return "UNKNOWN-SA-VALUE";
1360         }
1361       case 12:
1362         return "Duration-Value";
1363       case 13:
1364         return "PRF-Value";
1365       case 14:
1366         return "Key-Length";
1367       case 15:
1368         return "Field-Size";
1369       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1370     }
1371   }
1372 }
1373
1374 static const char *
1375 attrtype2str(guint8 type) {
1376   switch (type) {
1377   case 0: return "Reserved";
1378   case 1: return "ISAKMP_CFG_REQUEST";
1379   case 2: return "ISAKMP_CFG_REPLY";
1380   case 3: return "ISAKMP_CFG_SET";
1381   case 4: return "ISAKMP_CFG_ACK";
1382   }
1383   if(type < 127)
1384     return "Future use";
1385   return "Private use";
1386 }
1387
1388 static const char *
1389 cfgattrident2str(guint16 ident) {
1390 #define NUM_ATTR_DEFINED        12
1391   static const char *msgs[NUM_PREDEFINED] = {
1392     "RESERVED",
1393     "INTERNAL_IP4_ADDRESS",
1394     "INTERNAL_IP4_NETMASK",
1395     "INTERNAL_IP4_DNS",
1396     "INTERNAL_IP4_NBNS",
1397     "INTERNAL_ADDRESS_EXPIREY",
1398     "INTERNAL_IP4_DHCP",
1399     "APPLICATION_VERSION"
1400     "INTERNAL_IP6_ADDRESS",
1401     "INTERNAL_IP6_NETMASK",
1402     "INTERNAL_IP6_DNS",
1403     "INTERNAL_IP6_NBNS",
1404     "INTERNAL_IP6_DHCP",
1405   };
1406   if(ident < NUM_ATTR_DEFINED)
1407     return msgs[ident];
1408   if(ident < 16383)
1409     return "Future use";
1410   switch(ident) {
1411   case 16520: return "XAUTH_TYPE";
1412   case 16521: return "XAUTH_USER_NAME";
1413   case 16522: return "XAUTH_USER_PASSWORD";
1414   case 16523: return "XAUTH_PASSCODE";
1415   case 16524: return "XAUTH_MESSAGE";
1416   case 16525: return "XAUTH_CHALLANGE";
1417   case 16526: return "XAUTH_DOMAIN";
1418   case 16527: return "XAUTH_STATUS";
1419   case 16528: return "XAUTH_NEXT_PIN";
1420   case 16529: return "XAUTH_ANSWER";
1421   default: return "Private use";
1422   }
1423 }
1424
1425 static const char *
1426 certtype2str(guint8 type) {
1427 #define NUM_CERTTYPE 11
1428   static const char *msgs[NUM_CERTTYPE] = {
1429     "NONE",
1430     "PKCS #7 wrapped X.509 certificate",
1431     "PGP Certificate",
1432     "DNS Signed Key",
1433     "X.509 Certificate - Signature",
1434     "X.509 Certificate - Key Exchange",
1435     "Kerberos Tokens",
1436     "Certificate Revocation List (CRL)",
1437     "Authority Revocation List (ARL)",
1438     "SPKI Certificate",
1439     "X.509 Certificate - Attribute",
1440   };
1441   if(type > NUM_CERTTYPE)
1442     return "RESERVED";
1443   return msgs[type];
1444 }
1445
1446 static gboolean
1447 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1448
1449   switch (len) {
1450   case 1:
1451     *num_p = tvb_get_guint8(tvb, offset);
1452     break;
1453   case 2:
1454     *num_p = tvb_get_ntohs(tvb, offset);
1455     break;
1456   case 3:
1457     *num_p = tvb_get_ntoh24(tvb, offset);
1458     break;
1459   case 4:
1460     *num_p = tvb_get_ntohl(tvb, offset);
1461     break;
1462   default:
1463     return FALSE;
1464   }
1465
1466   return TRUE;
1467 }
1468
1469 void
1470 proto_register_isakmp(void)
1471 {
1472 /*  static hf_register_info hf[] = {
1473     { &variable,
1474     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1475   };*/
1476   static gint *ett[] = {
1477     &ett_isakmp,
1478     &ett_isakmp_flags,
1479     &ett_isakmp_payload,
1480   };
1481
1482   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1483                                                "ISAKMP", "isakmp");
1484 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1485   proto_register_subtree_array(ett, array_length(ett));
1486
1487   register_dissector("isakmp", dissect_isakmp, proto_isakmp);
1488 }
1489
1490 void
1491 proto_reg_handoff_isakmp(void)
1492 {
1493   dissector_handle_t isakmp_handle;
1494
1495   /*
1496    * Get handle for the AH & ESP dissectors.
1497    */
1498   esp_handle = find_dissector("esp");
1499   ah_handle = find_dissector("ah");
1500
1501   isakmp_handle = find_dissector("isakmp");
1502   dissector_add("udp.port", UDP_PORT_ISAKMP, isakmp_handle);
1503   dissector_add("tcp.port", TCP_PORT_ISAKMP, isakmp_handle);
1504 }