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