/* packet-fortinet-fgcp.c * Routines for FortiGate Cluster Protocol dissection * Copyright 2023, Alexis La Goutte * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later * * No spec/doc is available based on reverse/analysis of protocol... * */ #include "config.h" #include #include #include #include #include void proto_reg_handoff_fortinet_fgcp(void); void proto_register_fortinet_fgcp(void); static int proto_fortinet_fgcp_hb = -1; static int hf_fortinet_fgcp_hb_magic = -1; static int hf_fortinet_fgcp_hb_flag = -1; static int hf_fortinet_fgcp_hb_flag_b74 = -1; static int hf_fortinet_fgcp_hb_flag_b3 = -1; static int hf_fortinet_fgcp_hb_flag_b2 = -1; static int hf_fortinet_fgcp_hb_flag_authentication = -1; static int hf_fortinet_fgcp_hb_flag_encryption = -1; static int hf_fortinet_fgcp_hb_mode = -1; static int hf_fortinet_fgcp_hb_gn = -1; static int hf_fortinet_fgcp_hb_group_id = -1; static int hf_fortinet_fgcp_hb_port = -1; static int hf_fortinet_fgcp_hb_revision = -1; static int hf_fortinet_fgcp_hb_sn = -1; static int hf_fortinet_fgcp_hb_payload_encrypted = -1; static int hf_fortinet_fgcp_hb_authentication = -1; static int hf_fortinet_fgcp_hb_tlv = -1; static int hf_fortinet_fgcp_hb_tlv_type = -1; static int hf_fortinet_fgcp_hb_tlv_length = -1; static int hf_fortinet_fgcp_hb_tlv_value = -1; static int hf_fortinet_fgcp_hb_tlv_vcluster_id = -1; static int hf_fortinet_fgcp_hb_tlv_priority = -1; static int hf_fortinet_fgcp_hb_tlv_override = -1; //static int hf_fortinet_fgcp_hb_unknown = -1; static int hf_fortinet_fgcp_hb_unknown_uint16 = -1; static dissector_handle_t fortinet_fgcp_hb_handle; static gint ett_fortinet_fgcp_hb = -1; static gint ett_fortinet_fgcp_hb_flag = -1; static gint ett_fortinet_fgcp_hb_tlv = -1; static const value_string fortinet_fgcp_hb_mode_vals[] = { { 0x1, "A/A (Active/Active)"}, { 0x2, "A/P (Active/Passive)"}, {0, NULL } }; #define HB_TLV_END_OF_TLV 0x00 #define HB_TLV_VCLUSTER_ID 0x0B #define HB_TLV_PRIORITY 0x0C #define HB_TLV_OVERRIDE 0x0D static const value_string fortinet_fgcp_hb_tlv_vals[] = { { HB_TLV_END_OF_TLV, "End of TLV" }, { HB_TLV_PRIORITY, "Port Priority" }, { HB_TLV_OVERRIDE, "Override" }, { 0, NULL } }; static int dissect_fortinet_fgcp_hb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { proto_item *ti; proto_tree *fortinet_hb_tree; guint offset = 0, length, auth_len=0; guint8 flags; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FGCP-HB"); col_add_fstr(pinfo->cinfo, COL_INFO, "Cluster: %s(%u) - monitor: %s - SN: %s", tvb_get_string_enc(pinfo->pool, tvb, offset+4, 32, ENC_ASCII), /* Group Name*/ tvb_get_guint16(tvb, (offset+4+32+2), ENC_LITTLE_ENDIAN), /* Group ID*/ tvb_get_string_enc(pinfo->pool, tvb, offset+4+32+2+14, 16, ENC_ASCII), /* Port */ tvb_get_string_enc(pinfo->pool, tvb, offset+4+32+2+14+16+2+2, 16, ENC_ASCII) /* Serial Number */); ti = proto_tree_add_item(tree, proto_fortinet_fgcp_hb, tvb, 0, -1, ENC_NA); fortinet_hb_tree = proto_item_add_subtree(ti, ett_fortinet_fgcp_hb); proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_magic, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_mode, tvb, offset, 1, ENC_NA); offset += 1; static int * const fortinet_fgcp_hb_flag[] = { &hf_fortinet_fgcp_hb_flag_b74, &hf_fortinet_fgcp_hb_flag_b3, &hf_fortinet_fgcp_hb_flag_b2, &hf_fortinet_fgcp_hb_flag_authentication, &hf_fortinet_fgcp_hb_flag_encryption, NULL }; proto_tree_add_bitmask(fortinet_hb_tree, tvb, offset, hf_fortinet_fgcp_hb_flag, ett_fortinet_fgcp_hb_flag, fortinet_fgcp_hb_flag, ENC_NA); flags = tvb_get_guint8(tvb, offset); offset += 1; /* Group Name */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_gn, tvb, offset, 32, ENC_ASCII); offset += 32; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* Group Id */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_group_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* Heartbeat Port */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_port, tvb, offset, 16, ENC_ASCII); offset += 16; /* Revision ? */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_revision, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* Hash/crc ? change after each revision*/ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_unknown_uint16, tvb, offset, 2, ENC_NA); offset += 2; /* Serial Number */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_sn, tvb, offset, 16, ENC_ASCII); offset += 16; if (flags & 0x02) { /* Authentication ? */ /* the payload finish with 32bits of authentication (hash ?) */ auth_len = 32; } if (flags & 0x01) { /* Encrypted Payload ?*/ length = tvb_reported_length_remaining(tvb, offset) - auth_len; proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_payload_encrypted, tvb, offset, length, ENC_NA); offset += length; } else { guint next_offset; length = tvb_reported_length_remaining(tvb, offset) - auth_len; next_offset = offset + length; while (offset < next_offset) { guint32 type, len; proto_item *ti_tlv; proto_tree *tlv_tree; ti_tlv = proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_tlv, tvb, offset, 3, ENC_NA); tlv_tree = proto_item_add_subtree(ti_tlv, ett_fortinet_fgcp_hb_tlv); proto_tree_add_item_ret_uint(tlv_tree, hf_fortinet_fgcp_hb_tlv_type, tvb, offset, 2, ENC_LITTLE_ENDIAN, &type); offset += 2; proto_tree_add_item_ret_uint(tlv_tree, hf_fortinet_fgcp_hb_tlv_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &len); offset += 2; proto_item_append_text(ti_tlv, ": (t=%u,l=%d) %s", type, len, val_to_str_const(type, fortinet_fgcp_hb_tlv_vals ,"Unknown type") ); proto_item_set_len(ti_tlv, 2 + 2 + len); proto_tree_add_item(tlv_tree, hf_fortinet_fgcp_hb_tlv_value, tvb, offset, len, ENC_NA); switch (type) { case HB_TLV_VCLUSTER_ID:{ guint32 vcluster_id; proto_tree_add_item_ret_uint(tlv_tree, hf_fortinet_fgcp_hb_tlv_vcluster_id, tvb, offset, 1, ENC_NA, &vcluster_id); proto_item_append_text(ti_tlv, ": %u", vcluster_id); offset += 1; } break; case HB_TLV_PRIORITY:{ guint32 priority; proto_tree_add_item_ret_uint(tlv_tree, hf_fortinet_fgcp_hb_tlv_priority, tvb, offset, 1, ENC_NA, &priority); proto_item_append_text(ti_tlv, ": %u", priority); offset += 1; } break; case HB_TLV_OVERRIDE:{ guint32 override; proto_tree_add_item_ret_uint(tlv_tree, hf_fortinet_fgcp_hb_tlv_override, tvb, offset, 1, ENC_NA, &override); if (override){ proto_item_append_text(ti_tlv, ": True"); } else { proto_item_append_text(ti_tlv, ": False"); } offset += 1; } break; default: offset += len; break; } } } if (auth_len) { /* Authentication ? */ proto_tree_add_item(fortinet_hb_tree, hf_fortinet_fgcp_hb_authentication, tvb, offset, 32, ENC_NA); offset += 32; } return offset; } void proto_register_fortinet_fgcp(void) { static hf_register_info hf[] = { /* HeartBeat */ { &hf_fortinet_fgcp_hb_magic, { "Magic Number", "fortinet_fgcp.hb.magic", FT_UINT16, BASE_HEX_DEC, NULL, 0x0, "Magic Number ?", HFILL } }, { &hf_fortinet_fgcp_hb_flag, { "Flag", "fortinet_fgcp.hb.flag", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_flag_b74, { "Bit 7 to 4", "fortinet_fgcp.hb.flag.b74", FT_UINT8, BASE_HEX, NULL, 0xF0, "Unknown", HFILL } }, { &hf_fortinet_fgcp_hb_flag_b3, { "Bit b3", "fortinet_fgcp.hb.flag.b3", FT_UINT8, BASE_HEX, NULL, 0x08, "Unknown", HFILL } }, { &hf_fortinet_fgcp_hb_flag_b2, { "Bit b2", "fortinet_fgcp.hb.flag.b2", FT_UINT8, BASE_HEX, NULL, 0x04, "Unknown", HFILL } }, { &hf_fortinet_fgcp_hb_flag_authentication, { "Authentication", "fortinet_fgcp.hb.flag.authentication", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_flag_encryption, { "Encryption", "fortinet_fgcp.hb.flag.encryption", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_mode, { "Mode", "fortinet_fgcp.hb.mode", FT_UINT8, BASE_DEC, VALS(fortinet_fgcp_hb_mode_vals), 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_gn, { "Group Name", "fortinet_fgcp.hb.gn", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_group_id, { "Group Id", "fortinet_fgcp.hb.group_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_port, { "Port", "fortinet_fgcp.hb.port", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_revision, { "Revision", "fortinet_fgcp.hb.revision", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of revision config for HA", HFILL } }, { &hf_fortinet_fgcp_hb_sn, { "Serial Number", "fortinet_fgcp.hb.sn", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_payload_encrypted, { "Payload (encrypted)", "fortinet_fgcp.hb.payload_encrypted", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_authentication, { "Authentication", "fortinet_fgcp.hb.authentication", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv, { "TLV", "fortinet_fgcp.hb.tlv", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_type, { "Type", "fortinet_fgcp.hb.tlv.type", FT_UINT16, BASE_HEX, VALS(fortinet_fgcp_hb_tlv_vals), 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_length, { "Length", "fortinet_fgcp.hb.tlv.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_value, { "Value", "fortinet_fgcp.hb.tlv.value", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_vcluster_id, { "Vcluster ID", "fortinet_fgcp.hb.tlv.vcluster_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_priority, { "Port Priority", "fortinet_fgcp.hb.tlv.priority", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_fortinet_fgcp_hb_tlv_override, { "Override", "fortinet_fgcp.hb.tlv.override", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, /* { &hf_fortinet_fgcp_hb_unknown, { "Unknown", "fortinet_fgcp.hb.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, "Always NULL ?", HFILL } }, */ { &hf_fortinet_fgcp_hb_unknown_uint16, { "Unknown", "fortinet_fgcp.hb.unknown.uint16", FT_UINT16, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_fortinet_fgcp_hb, &ett_fortinet_fgcp_hb_flag, &ett_fortinet_fgcp_hb_tlv }; /* Register the protocol name and description */ proto_fortinet_fgcp_hb = proto_register_protocol("FortiGate Cluster Protocol - HeartBeat", "fortinet_fgcp_hb", "fortinet_fgcp_hb"); /* Required function calls to register the header fields and subtrees */ proto_register_field_array(proto_fortinet_fgcp_hb, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); fortinet_fgcp_hb_handle = register_dissector("fortinet_fgcp_hb", dissect_fortinet_fgcp_hb, proto_fortinet_fgcp_hb); } void proto_reg_handoff_fortinet_fgcp(void) { dissector_add_uint("ethertype", ETHERTYPE_FORTINET_FGCP_HB, fortinet_fgcp_hb_handle); } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */