summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-hsrp.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-hsrp.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-hsrp.c')
-rw-r--r--epan/dissectors/packet-hsrp.c857
1 files changed, 857 insertions, 0 deletions
diff --git a/epan/dissectors/packet-hsrp.c b/epan/dissectors/packet-hsrp.c
new file mode 100644
index 00000000..5c26754e
--- /dev/null
+++ b/epan/dissectors/packet-hsrp.c
@@ -0,0 +1,857 @@
+/* packet-hsrp.c
+ * Routines for the Cisco Hot Standby Router Protocol (HSRP)
+ *
+ * Heikki Vatiainen <hessu@cs.tut.fi>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-vrrp.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/*
+ * RFC 2281 describes opcodes 0 - 2
+ *
+ * Op Code 3: **** HSRP Interface State Advertisements ****
+ * http://www.cisco.com/en/US/products/sw/iosswrel/ps1834/products_feature_guide09186a00800e9763.html
+ *
+ * An HSRP interface-state advertisement is sent:
+ *
+ * * when HSRP on the interface enters or leaves the passive state
+ * * when a group on the interface learns a new Active router
+ * * periodically while the interface is in the passive state
+ *
+ * 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Version | Op Code = 3 | TLV Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TLV Length | State | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Active Group Count | Passive Group Count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Passive Group Count: 2 octet
+ *
+ * A count of the number of passive groups on the interface. The range
+ * of values are 0-256.
+ *
+ * Active Group Count: 2 octet
+ *
+ * A count of the number of active groups on the interface. The range
+ * of values are 0-256.
+ *
+ *
+ * HSRP Version 2
+ * Ref. http://www.smartnetworks.jp/2006/02/hsrp_8_hsrp_version_2.html (Japanese Only)
+ *
+ * Group State TLV
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type=1 | Length=40 | HSRP Version | Opcode |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | State | IP Version | Group Number |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Identifier(6octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Identifier | Priority(4octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Priority cont. | Hello Time(4octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Hello Time cont. | Hold Time(4octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Hold Time cont. | Virtual IP Address(16octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Virtual IP Address cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Virtual IP Address cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Virtual IP Address cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Virtual IP Address cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Interface State TLV
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type=2 | Length=4 | Active Groups |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Passive Groups |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Text Authentication TLV
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type=3 | Length=8 | Authentication Data(8octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * MD5 Authentication TLV
+ *
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type=4 | Length | Algorithm | Padding |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Flags | IP Address(4octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | IP Address cont. | Key ID(4octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Key ID cont. | Authentication Data(16octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Authentication Data cont. |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/to_str.h>
+#include <epan/expert.h>
+
+void proto_register_hsrp(void);
+void proto_reg_handoff_hsrp(void);
+
+static dissector_handle_t hsrp_handle;
+
+static gint proto_hsrp = -1;
+
+static gint hf_hsrp_version = -1;
+static gint hf_hsrp_opcode = -1;
+/* Opcode 0-2 */
+static gint hf_hsrp_state = -1;
+static gint hf_hsrp_hellotime = -1;
+static gint hf_hsrp_holdtime = -1;
+static gint hf_hsrp_priority = -1;
+static gint hf_hsrp_group = -1;
+static gint hf_hsrp_reserved = -1;
+static gint hf_hsrp_auth_data = -1;
+static gint hf_hsrp_virt_ip_addr = -1;
+/* Advertise (3) */
+static gint hf_hsrp_adv_type = -1;
+static gint hf_hsrp_adv_length = -1;
+static gint hf_hsrp_adv_state = -1;
+static gint hf_hsrp_adv_reserved1 = -1;
+static gint hf_hsrp_adv_activegrp = -1;
+static gint hf_hsrp_adv_passivegrp = -1;
+static gint hf_hsrp_adv_reserved2 = -1;
+
+static gint ett_hsrp = -1;
+
+/* HSRPv2 */
+static gint hf_hsrp2_version = -1;
+static gint hf_hsrp2_opcode = -1;
+static gint hf_hsrp2_state = -1;
+static gint hf_hsrp2_group_state_tlv = -1;
+static gint hf_hsrp2_interface_state_tlv = -1;
+static gint hf_hsrp2_text_auth_tlv = -1;
+static gint hf_hsrp2_md5_auth_tlv = -1;
+static gint hf_hsrp2_ipversion = -1;
+static gint hf_hsrp2_hellotime = -1;
+static gint hf_hsrp2_holdtime = -1;
+static gint hf_hsrp2_priority = -1;
+static gint hf_hsrp2_identifier = -1;
+static gint hf_hsrp2_group = -1;
+static gint hf_hsrp2_virt_ip_addr = -1;
+static gint hf_hsrp2_virt_ip_addr_v6 = -1;
+static gint hf_hsrp2_auth_data = -1;
+static gint hf_hsrp2_active_group = -1;
+static gint hf_hsrp2_passive_group = -1;
+static gint hf_hsrp2_md5_algorithm = -1;
+static gint hf_hsrp2_md5_padding = -1;
+static gint hf_hsrp2_md5_flags = -1;
+static gint hf_hsrp2_md5_ip_address= -1;
+static gint hf_hsrp2_md5_key_id= -1;
+static gint hf_hsrp2_md5_auth_data= -1;
+
+static gint ett_hsrp2_group_state_tlv = -1;
+static gint ett_hsrp2_interface_state_tlv = -1;
+static gint ett_hsrp2_text_auth_tlv = -1;
+static gint ett_hsrp2_md5_auth_tlv = -1;
+
+static expert_field ei_hsrp_unknown_tlv = EI_INIT;
+
+#define UDP_PORT_HSRP 1985
+#define UDP_PORT_HSRP2_V6 2029
+#define UDP_PORT_HSRP_RANGE "1985,2029"
+#define HSRP_DST_IP_ADDR 0xE0000002
+#define HSRP2_DST_IP_ADDR 0xE0000066
+
+struct hsrp_packet { /* Multicast to 224.0.0.2, TTL 1, UDP, port 1985 */
+ guint8 version; /* RFC2281 describes version 0 */
+ guint8 opcode;
+ guint8 state;
+#define HSRP_DEFAULT_HELLOTIME 3
+ guint8 hellotime; /* In seconds */
+#define HSRP_DEFAULT_HOLDTIME 10
+ guint8 holdtime; /* In seconds */
+ guint8 priority; /* Higher is stronger, highest IP address tie-breaker */
+ guint8 group; /* Identifies the standby group */
+ guint8 reserved;
+ guint8 auth_data[8]; /* Clear-text password, recommended default is `cisco' */
+ guint32 virt_ip_addr; /* The virtual IP address used by this group */
+};
+
+struct hsrpv2_packet { /* Multicast to 224.0.0.102, TTL 1, UDP, port 1985 */
+ guint8 version;
+ guint8 opcode;
+ guint8 state;
+#define HSRP2_DEFAULT_HELLOTIME 3000
+ guint32 hellotime; /* In msecs */
+#define HSRP2_DEFAULT_HOLDTIME 10000
+ guint32 holdtime; /* In msecs */
+ guint32 priority; /* Higher is stronger, highest IP address tie-breaker */
+ guint16 group; /* Identifies the standby group */
+ guint8 identifier[6]; /* Identifier of sender's MAC address */
+ guint8 auth_data[8]; /* Clear-text password, recommended default is `cisco' */
+ gchar virt_ip_addr[16]; /* The virtual IPv4/IPv6 address used by this group */
+ guint8 md5_algorithm; /* MD5 Hash algorithm */
+ guint8 md5_flags; /* Undefined */
+ guint8 md5_ip_address; /* IP address of sender interface */
+ guint8 md5_key_id; /* Name of key chain */
+ guint8 md5_auth_data[16]; /* MD5 digest data */
+};
+
+#define HSRP_OPCODE_HELLO 0
+#define HSRP_OPCODE_COUP 1
+#define HSRP_OPCODE_RESIGN 2
+#define HSRP_OPCODE_ADVERTISE 3
+static const value_string hsrp_opcode_vals[] = {
+ {HSRP_OPCODE_HELLO, "Hello"},
+ {HSRP_OPCODE_COUP, "Coup"},
+ {HSRP_OPCODE_RESIGN, "Resign"},
+ {HSRP_OPCODE_ADVERTISE, "Advertise"},
+ {0, NULL}
+};
+
+#define HSRP_STATE_INITIAL 0
+#define HSRP_STATE_LEARN 1
+#define HSRP_STATE_LISTEN 2
+#define HSRP_STATE_SPEAK 4
+#define HSRP_STATE_STANDBY 8
+#define HSRP_STATE_ACTIVE 16
+static const value_string hsrp_state_vals[] = {
+ {HSRP_STATE_INITIAL, "Initial"},
+ {HSRP_STATE_LEARN, "Learn"},
+ {HSRP_STATE_LISTEN, "Listen"},
+ {HSRP_STATE_SPEAK, "Speak"},
+ {HSRP_STATE_STANDBY, "Standby"},
+ {HSRP_STATE_ACTIVE, "Active"},
+ {0, NULL}
+};
+
+#define HSRP_ADV_TYPE_INTSTATE 1
+#define HSRP_ADV_TYPE_IPREDUN 2
+static const value_string hsrp_adv_type_vals[] = {
+ {HSRP_ADV_TYPE_INTSTATE, "HSRP interface state"},
+ {HSRP_ADV_TYPE_IPREDUN, "IP redundancy"},
+ {0, NULL}
+};
+
+#define HSRP_ADV_STATE_DORMANT 1
+#define HSRP_ADV_STATE_PASSIVE 2
+#define HSRP_ADV_STATE_ACTIVE 3
+static const value_string hsrp_adv_state_vals[] = {
+ {HSRP_ADV_STATE_DORMANT, "Dormant"},
+ {HSRP_ADV_STATE_PASSIVE, "Passive"},
+ {HSRP_ADV_STATE_ACTIVE, "Active"},
+ {0, NULL}
+};
+
+#define HSRP2_OPCODE_HELLO 0
+#define HSRP2_OPCODE_COUP 1
+#define HSRP2_OPCODE_RESIGN 2
+static const value_string hsrp2_opcode_vals[] = {
+ {HSRP2_OPCODE_HELLO, "Hello"},
+ {HSRP2_OPCODE_COUP, "Coup"},
+ {HSRP2_OPCODE_RESIGN, "Resign"},
+ {0, NULL}
+};
+
+#define HSRP2_STATE_DISABLED 0
+#define HSRP2_STATE_INIT 1
+#define HSRP2_STATE_LEARN 2
+#define HSRP2_STATE_LISTEN 3
+#define HSRP2_STATE_SPEAK 4
+#define HSRP2_STATE_STANDBY 5
+#define HSRP2_STATE_ACTIVE 6
+static const value_string hsrp2_state_vals[] = {
+ {HSRP2_STATE_INIT, "Init"},
+ {HSRP2_STATE_LEARN, "Learn"},
+ {HSRP2_STATE_LISTEN, "Listen"},
+ {HSRP2_STATE_SPEAK, "Speak"},
+ {HSRP2_STATE_STANDBY, "Standby"},
+ {HSRP2_STATE_ACTIVE, "Active"},
+ {0, NULL}
+};
+
+#define HSRP2_IPVERSION_IPV4 4
+#define HSRP2_IPVERSION_IPV6 6
+static const value_string hsrp2_ipversion_vals[] = {
+ {HSRP2_IPVERSION_IPV4, "IPv4"},
+ {HSRP2_IPVERSION_IPV6, "IPv6"},
+ {0, NULL}
+};
+
+#define HSRP2_MD5_ALGORITHM 1
+static const value_string hsrp2_md5_algorithm_vals[] = {
+ {HSRP2_MD5_ALGORITHM, "MD5"},
+ {0, NULL}
+};
+
+static void
+process_hsrp_md5_tlv_sequence(tvbuff_t *tvb, proto_tree *hsrp_tree, guint offset)
+{
+ guint8 type = tvb_get_guint8(tvb, offset);
+ guint8 len = tvb_get_guint8(tvb, offset+1);
+ proto_item *ti;
+ proto_tree *md5_auth_tlv;
+
+ ti = proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp2_md5_auth_tlv, tvb, offset, 1, type, "Type=%d Len=%d", type, len);
+ offset+=2;
+
+ /* Making MD5 Authentication TLV subtree */
+ md5_auth_tlv = proto_item_add_subtree(ti, ett_hsrp2_md5_auth_tlv);
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_algorithm, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ /* padding field */
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_padding, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_flags, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset+=2;
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_ip_address, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset+=4;
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_key_id, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset+=4; /* this now points to the start of the MD5 hash */
+ proto_tree_add_item(md5_auth_tlv, hf_hsrp2_md5_auth_data, tvb, offset, 16, ENC_NA);
+}
+
+static int
+dissect_hsrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ tvbuff_t *next_tvb;
+ guint32 hsrpv1 = g_htonl(HSRP_DST_IP_ADDR),
+ hsrpv2 = g_htonl(HSRP2_DST_IP_ADDR);
+
+ /* Return if this isn't really HSRP traffic
+ * (source and destination port must be UDP_PORT_HSRP on HSRPv1 or HSRPv2(IPv4))
+ * (source and destination port must be UDP_PORT_HSRP2_V6 on HSRPv2(IPv6))
+ */
+ if(pinfo->destport != UDP_PORT_HSRP && pinfo->destport != UDP_PORT_HSRP2_V6)
+ return 0;
+
+ /*
+ * To check whether this is an HSRPv1 packet or HSRPv2 on dest IPv4 addr.
+ */
+ if (pinfo->dst.type == AT_IPv4 && memcmp(pinfo->dst.data, &hsrpv1, 4) == 0) {
+ /* HSRPv1 */
+ guint8 opcode, state = 0;
+ proto_item *ti;
+ proto_tree *hsrp_tree;
+ gint offset;
+ guint8 hellotime, holdtime;
+ gchar *auth;
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSRP");
+
+ opcode = tvb_get_guint8(tvb, 1);
+ col_set_str(pinfo->cinfo, COL_INFO,
+ val_to_str_const(opcode, hsrp_opcode_vals, "Unknown"));
+
+ if (opcode < 3) {
+ state = tvb_get_guint8(tvb, 2);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (state %s)",
+ val_to_str_const(state, hsrp_state_vals, "Unknown"));
+ } else if (opcode == 3) {
+ state = tvb_get_guint8(tvb, 6);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (state %s)",
+ val_to_str_const(state, hsrp_adv_state_vals, "Unknown"));
+ }
+
+ offset = 0;
+ ti = proto_tree_add_item(tree, proto_hsrp, tvb, offset, -1, ENC_NA);
+ hsrp_tree = proto_item_add_subtree(ti, ett_hsrp);
+
+ proto_tree_add_item(hsrp_tree, hf_hsrp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_uint(hsrp_tree, hf_hsrp_opcode, tvb, offset, 1, opcode);
+ offset++;
+ if (opcode < 3) {
+ proto_tree_add_uint(hsrp_tree, hf_hsrp_state, tvb, offset, 1, state);
+ offset++;
+ hellotime = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp_hellotime, tvb, offset, 1, hellotime,
+ "%sDefault (%u)",
+ (hellotime == HSRP_DEFAULT_HELLOTIME) ? "" : "Non-",
+ hellotime);
+ offset++;
+ holdtime = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp_holdtime, tvb, offset, 1, holdtime,
+ "%sDefault (%u)",
+ (holdtime == HSRP_DEFAULT_HOLDTIME) ? "" : "Non-",
+ holdtime);
+ offset++;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_priority, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_group, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ auth = (gchar *) tvb_get_string_enc(pinfo->pool, tvb, offset, 8, ENC_ASCII|ENC_NA);
+ proto_tree_add_string_format_value(hsrp_tree, hf_hsrp_auth_data, tvb, offset, 8, auth,
+ "%sDefault (%s)",
+ (strcmp(auth, "cisco") == 0) ? "" : "Non-",
+ auth);
+ offset += 8;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_virt_ip_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /* offset += 4; */
+ } else if (opcode == 3) {
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_type, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_length, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_state, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_activegrp, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_passivegrp, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(hsrp_tree, hf_hsrp_adv_reserved2, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /* offset += 4; */
+ } else {
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_data_dissector(next_tvb, pinfo, hsrp_tree);
+ }
+ /* is MD5 authentication being used with HSRPv1? */
+ if (tvb_captured_length(tvb) == 50) { /* 20 bytes of regular HSRP data + 30 bytes of authentication payload */
+ guint offset2 = offset + 4; /* this now points to the start of a possible TLV sequence */
+ guint8 type = tvb_get_guint8(tvb, offset2);
+ guint8 len = tvb_get_guint8(tvb, offset2+1);
+ if (type == 4 && len == 28) {
+ /* MD5 Authentication TLV */
+ if (tree) {
+ process_hsrp_md5_tlv_sequence(tvb, hsrp_tree, offset2);
+ }
+ } else {
+ expert_add_info_format(pinfo, ti, &ei_hsrp_unknown_tlv,
+ "Unknown TLV sequence in HSRPv1 dissection, Type=(%d) Len=(%d)", type, len);
+ }
+ }
+ } else if ((pinfo->dst.type == AT_IPv4 && memcmp(pinfo->dst.data, &hsrpv2, 4) == 0) ||
+ (pinfo->dst.type == AT_IPv6 && pinfo->destport == UDP_PORT_HSRP2_V6)) {
+ /* HSRPv2 */
+ guint offset = 0, offset2;
+ proto_item *ti = NULL;
+ proto_tree *hsrp_tree = NULL;
+ guint8 type,len;
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "HSRPv2");
+
+ if (tree) {
+ ti = proto_tree_add_item(tree, proto_hsrp, tvb, offset, -1, ENC_NA);
+ hsrp_tree = proto_item_add_subtree(ti, ett_hsrp);
+ }
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ type = tvb_get_guint8(tvb, offset);
+ len = tvb_get_guint8(tvb, offset+1);
+
+ offset2 = offset;
+ if (type == 1 && len == 40) {
+ /* Group State TLV */
+ guint8 opcode, state = 0, ipver;
+ guint32 hellotime, holdtime;
+ proto_tree *group_state_tlv;
+
+ if (tree) {
+ ti = proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp2_group_state_tlv, tvb, offset, 2+len, type,
+ "Type=%d Len=%d", type, len);
+ }
+ offset+=2;
+
+ opcode = tvb_get_guint8(tvb, offset+1);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
+ val_to_str_const(opcode, hsrp2_opcode_vals, "Unknown"));
+
+ state = tvb_get_guint8(tvb, offset+2);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (state %s)",
+ val_to_str_const(state, hsrp2_state_vals, "Unknown"));
+
+ if (tree) {
+ /* Making Group State TLV subtree. */
+ group_state_tlv = proto_item_add_subtree(ti, ett_hsrp2_group_state_tlv);
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_version, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_uint(group_state_tlv, hf_hsrp2_opcode, tvb, offset, 1, opcode);
+ offset++;
+ proto_tree_add_uint(group_state_tlv, hf_hsrp2_state, tvb, offset, 1, state);
+ offset++;
+ ipver = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint(group_state_tlv, hf_hsrp2_ipversion, tvb, offset, 1, ipver);
+ offset++;
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_group, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset+=2;
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_identifier, tvb, offset, 6, ENC_NA);
+ offset+=6;
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_priority, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset+=4;
+
+ hellotime = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_uint_format_value(group_state_tlv, hf_hsrp2_hellotime, tvb, offset, 4, hellotime,
+ "%sDefault (%u)",
+ (hellotime == HSRP2_DEFAULT_HELLOTIME) ? "" : "Non-",
+ hellotime);
+ offset+=4;
+ holdtime = tvb_get_ntohl(tvb, offset);
+ proto_tree_add_uint_format_value(group_state_tlv, hf_hsrp2_holdtime, tvb, offset, 4, holdtime,
+ "%sDefault (%u)",
+ (holdtime == HSRP2_DEFAULT_HOLDTIME) ? "" : "Non-",
+ holdtime);
+ offset+=4;
+ if (ipver == 4) {
+ /* Fetch Virtual IP as IPv4 */
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_virt_ip_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ } else if (ipver == 6) {
+ /* Fetch Virtual IP as IPv6 */
+ proto_tree_add_item(group_state_tlv, hf_hsrp2_virt_ip_addr_v6, tvb, offset, 16, ENC_NA);
+ } else {
+ /* Unknown protocol */
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_data_dissector(next_tvb, pinfo, hsrp_tree);
+ break;
+ }
+ /* offset+=16; */
+ }
+ } else if (type == 2 && len == 4) {
+ /* Interface State TLV */
+ guint16 active,passive;
+ active = tvb_get_ntohs(tvb, offset+2);
+ passive = tvb_get_ntohs(tvb, offset+4);
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Interface State TLV (Act=%d Pass=%d)",active,passive);
+
+ if (tree) {
+ proto_tree *interface_state_tlv;
+ ti = proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp2_interface_state_tlv, tvb, offset, 1, type,
+ "Type=%d Len=%d", type, 2+len);
+ offset+=2;
+
+ /* Making Interface State TLV subtree */
+ interface_state_tlv = proto_item_add_subtree(ti, ett_hsrp2_interface_state_tlv);
+ proto_tree_add_item(interface_state_tlv, hf_hsrp2_active_group, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset+=2;
+ proto_tree_add_item(interface_state_tlv, hf_hsrp2_passive_group, tvb, offset, 2, ENC_BIG_ENDIAN);
+ /* offset+=2; */
+ }
+ } else if (type == 3 && len == 8) {
+ /* Text Authentication TLV */
+ /* FIXME: Is the length of the authentication string really restricted to 8 bytes
+ * or is it maybe padded to multiples of 4 or 8 bytes?
+ */
+ if (tree) {
+ proto_tree *text_auth_tlv;
+ gchar *auth;
+
+ ti = proto_tree_add_uint_format_value(hsrp_tree, hf_hsrp2_text_auth_tlv, tvb, offset, 2+len, type,
+ "Type=%d Len=%d", type, len);
+ offset+=2;
+
+ /* Making Text Authentication TLV subtree */
+ text_auth_tlv = proto_item_add_subtree(ti, ett_hsrp2_text_auth_tlv);
+
+ auth = (gchar *) tvb_get_string_enc(pinfo->pool, tvb, offset, 8, ENC_ASCII|ENC_NA);
+ proto_tree_add_string_format_value(text_auth_tlv, hf_hsrp2_auth_data, tvb, offset, 8, auth,
+ "%sDefault (%s)",
+ (strcmp(auth, "cisco") == 0) ? "" : "Non-",
+ auth);
+ /* offset += 8; */
+ }
+ } else if (type == 4 && len == 28) {
+ /* MD5 Authentication TLV */
+ if (tree) {
+ process_hsrp_md5_tlv_sequence(tvb, hsrp_tree, offset);
+ /* offset += 16; */
+ }
+ } else {
+ /* Undefined TLV */
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_data_dissector(next_tvb, pinfo, hsrp_tree);
+ break;
+ }
+ offset = offset2+len+2;
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+void proto_register_hsrp(void)
+{
+ expert_module_t* expert_hsrp;
+
+ static hf_register_info hf[] = {
+ { &hf_hsrp_version,
+ { "Version", "hsrp.version",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "The version of the HSRP messages", HFILL }},
+
+ { &hf_hsrp_opcode,
+ { "Op Code", "hsrp.opcode",
+ FT_UINT8, BASE_DEC, VALS(hsrp_opcode_vals), 0x0,
+ "The type of message contained in this packet", HFILL }},
+
+ { &hf_hsrp_state,
+ { "State", "hsrp.state",
+ FT_UINT8, BASE_DEC, VALS(hsrp_state_vals), 0x0,
+ "The current state of the router sending the message", HFILL }},
+
+ { &hf_hsrp_hellotime,
+ { "Hellotime", "hsrp.hellotime",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "The approximate period between the Hello messages that the router sends", HFILL }},
+
+ { &hf_hsrp_holdtime,
+ { "Holdtime", "hsrp.holdtime",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Time that the current Hello message should be considered valid", HFILL }},
+
+ { &hf_hsrp_priority,
+ { "Priority", "hsrp.priority",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Used to elect the active and standby routers. Numerically higher priority wins vote", HFILL }},
+
+ { &hf_hsrp_group,
+ { "Group", "hsrp.group",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "This field identifies the standby group", HFILL }},
+
+ { &hf_hsrp_reserved,
+ { "Reserved", "hsrp.reserved",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_hsrp_auth_data,
+ { "Authentication Data", "hsrp.auth_data",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Contains a clear-text 8 character reused password", HFILL }},
+
+ { &hf_hsrp_virt_ip_addr,
+ { "Virtual IP Address", "hsrp.virt_ip",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "The virtual IP address used by this group", HFILL }},
+
+ { &hf_hsrp_adv_type,
+ { "Adv type", "hsrp.adv.tlvtype",
+ FT_UINT16, BASE_DEC, VALS(hsrp_adv_type_vals), 0x0,
+ "Advertisement tlv type", HFILL }},
+
+ { &hf_hsrp_adv_length,
+ { "Adv length", "hsrp.adv.tlvlength",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Advertisement tlv length", HFILL }},
+
+ { &hf_hsrp_adv_state,
+ { "Adv state", "hsrp.adv.state",
+ FT_UINT8, BASE_DEC, VALS(hsrp_adv_state_vals), 0x0,
+ "Advertisement tlv length", HFILL }},
+
+ { &hf_hsrp_adv_reserved1,
+ { "Adv reserved1", "hsrp.adv.reserved1",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Advertisement tlv length", HFILL }},
+
+ { &hf_hsrp_adv_activegrp,
+ { "Adv active groups", "hsrp.adv.activegrp",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Advertisement active group count", HFILL }},
+
+ { &hf_hsrp_adv_passivegrp,
+ { "Adv passive groups", "hsrp.adv.passivegrp",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Advertisement passive group count", HFILL }},
+
+ { &hf_hsrp_adv_reserved2,
+ { "Adv reserved2", "hsrp.adv.reserved2",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Advertisement tlv length", HFILL }},
+
+ { &hf_hsrp2_version,
+ { "Version", "hsrp2.version",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "The version of the HSRP messages", HFILL }},
+
+ { &hf_hsrp2_opcode,
+ { "Op Code", "hsrp2.opcode",
+ FT_UINT8, BASE_DEC, VALS(hsrp2_opcode_vals), 0x0,
+ "The type of message contained in this packet", HFILL }},
+
+ { &hf_hsrp2_state,
+ { "State", "hsrp2.state",
+ FT_UINT8, BASE_DEC, VALS(hsrp2_state_vals), 0x0,
+ "The current state of the router sending the message", HFILL }},
+
+ { &hf_hsrp2_group_state_tlv,
+ { "Group State TLV", "hsrp2.group_state_tlv",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_hsrp2_interface_state_tlv,
+ { "Interface State TLV", "hsrp2.interface_state_tlv",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_hsrp2_text_auth_tlv,
+ { "Text Authentication TLV", "hsrp2.text_auth_tlv",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_hsrp2_md5_auth_tlv,
+ { "MD5 Authentication TLV", "hsrp2.md5_auth_tlv",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_hsrp2_ipversion,
+ { "IP Ver.", "hsrp2.ipversion",
+ FT_UINT8, BASE_DEC, VALS(hsrp2_ipversion_vals), 0x0,
+ "The IP protocol version used in this hsrp message", HFILL }},
+
+ { &hf_hsrp2_group,
+ { "Group", "hsrp2.group",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "This field identifies the standby group", HFILL }},
+
+ { &hf_hsrp2_identifier,
+ { "Identifier", "hsrp2.identifier",
+ FT_ETHER, BASE_NONE, NULL, 0x0,
+ "BIA value of a sender interface", HFILL }},
+
+ { &hf_hsrp2_hellotime,
+ { "Hellotime", "hsrp2.hellotime",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "The approximate period between the Hello messages that the router sends", HFILL }},
+
+ { &hf_hsrp2_holdtime,
+ { "Holdtime", "hsrp2.holdtime",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Time that the current Hello message should be considered valid", HFILL }},
+
+ { &hf_hsrp2_priority,
+ { "Priority", "hsrp2.priority",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Used to elect the active and standby routers. Numerically higher priority wins vote", HFILL }},
+
+ { &hf_hsrp2_auth_data,
+ { "Authentication Data", "hsrp2.auth_data",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Contains a clear-text 8 character reused password", HFILL }},
+
+ { &hf_hsrp2_virt_ip_addr,
+ { "Virtual IP Address", "hsrp2.virt_ip",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "The virtual IP address used by this group", HFILL }},
+
+ { &hf_hsrp2_virt_ip_addr_v6,
+ { "Virtual IPv6 Address", "hsrp2.virt_ip_v6",
+ FT_IPv6, BASE_NONE, NULL, 0x0,
+ "The virtual IPv6 address used by this group", HFILL }},
+
+ { &hf_hsrp2_active_group,
+ { "Active Groups", "hsrp2.active_groups",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Active group number which becomes the active router myself", HFILL }},
+
+ { &hf_hsrp2_passive_group,
+ { "Passive Groups", "hsrp2.passive_groups",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Standby group number which doesn't become the active router myself", HFILL }},
+
+ { &hf_hsrp2_md5_algorithm,
+ { "MD5 Algorithm", "hsrp2.md5_algorithm",
+ FT_UINT8, BASE_DEC, VALS(hsrp2_md5_algorithm_vals), 0x0,
+ "Hash Algorithm used by this group", HFILL }},
+
+ { &hf_hsrp2_md5_padding,
+ { "Padding", "hsrp2.md5_padding",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "Must be zero", HFILL }},
+
+ { &hf_hsrp2_md5_flags,
+ { "MD5 Flags", "hsrp2.md5_flags",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Undefined", HFILL }},
+
+ { &hf_hsrp2_md5_ip_address,
+ { "Sender's IP Address", "hsrp.md5_ip_address",
+ FT_IPv4, BASE_NONE, NULL, 0x0,
+ "IP Address of the sender interface", HFILL }},
+
+ { &hf_hsrp2_md5_key_id,
+ { "MD5 Key ID", "hsrp2.md5_key_id",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "This field contains Key chain ID", HFILL }},
+
+ { &hf_hsrp2_md5_auth_data,
+ { "MD5 Authentication Data", "hsrp2.md5_auth_data",
+ FT_BYTES, BASE_NONE, NULL, 0x0,
+ "MD5 digest string is contained.", HFILL }}
+ };
+
+ static gint *ett[] = {
+ &ett_hsrp,
+ &ett_hsrp2_group_state_tlv,
+ &ett_hsrp2_interface_state_tlv,
+ &ett_hsrp2_text_auth_tlv,
+ &ett_hsrp2_md5_auth_tlv
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_hsrp_unknown_tlv, { "hsrp.unknown_tlv", PI_UNDECODED, PI_WARN, "Unknown TLV sequence (HSRPv1)", EXPFILL }},
+ };
+
+ proto_hsrp = proto_register_protocol("Cisco Hot Standby Router Protocol", "HSRP", "hsrp");
+
+ proto_register_field_array(proto_hsrp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_hsrp = expert_register_protocol(proto_hsrp);
+ expert_register_field_array(expert_hsrp, ei, array_length(ei));
+
+ hsrp_handle = register_dissector("hsrp", dissect_hsrp, proto_hsrp);
+}
+
+void
+proto_reg_handoff_hsrp(void)
+{
+ dissector_add_uint_range_with_preference("udp.port", UDP_PORT_HSRP_RANGE, hsrp_handle);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 expandtab:
+ * :indentSize=8:tabSize=8:noTabs=true:
+ */