1 /* packet-fortinet-fgcp.c
2 * Routines for FortiGate Cluster Protocol dissection
3 * Copyright 2023, Alexis La Goutte <alexis.lagoutte at gmail dot com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 * No spec/doc is available based on reverse/analysis of protocol...
17 #include <wireshark.h>
19 #include <epan/packet.h>
20 #include <epan/expert.h>
21 #include <epan/prefs.h>
22 #include <epan/etypes.h>
24 void proto_reg_handoff_fortinet_fgcp(void);
25 void proto_register_fortinet_fgcp(void);
27 static int proto_fortinet_fgcp_hb
;
28 static int hf_fortinet_fgcp_hb_magic
;
29 static int hf_fortinet_fgcp_hb_flag
;
30 static int hf_fortinet_fgcp_hb_flag_b74
;
31 static int hf_fortinet_fgcp_hb_flag_b3
;
32 static int hf_fortinet_fgcp_hb_flag_b2
;
33 static int hf_fortinet_fgcp_hb_flag_authentication
;
34 static int hf_fortinet_fgcp_hb_flag_encryption
;
35 static int hf_fortinet_fgcp_hb_mode
;
36 static int hf_fortinet_fgcp_hb_gn
;
37 static int hf_fortinet_fgcp_hb_group_id
;
38 static int hf_fortinet_fgcp_hb_port
;
39 static int hf_fortinet_fgcp_hb_revision
;
40 static int hf_fortinet_fgcp_hb_sn
;
41 static int hf_fortinet_fgcp_hb_payload_encrypted
;
42 static int hf_fortinet_fgcp_hb_authentication
;
44 static int hf_fortinet_fgcp_hb_tlv
;
45 static int hf_fortinet_fgcp_hb_tlv_type
;
46 static int hf_fortinet_fgcp_hb_tlv_length
;
47 static int hf_fortinet_fgcp_hb_tlv_value
;
48 static int hf_fortinet_fgcp_hb_tlv_vcluster_id
;
49 static int hf_fortinet_fgcp_hb_tlv_priority
;
50 static int hf_fortinet_fgcp_hb_tlv_override
;
52 //static int hf_fortinet_fgcp_hb_unknown;
53 static int hf_fortinet_fgcp_hb_unknown_uint16
;
55 static dissector_handle_t fortinet_fgcp_hb_handle
;
57 static int ett_fortinet_fgcp_hb
;
58 static int ett_fortinet_fgcp_hb_flag
;
59 static int ett_fortinet_fgcp_hb_tlv
;
61 static int proto_fortinet_fgcp_session
;
62 static int hf_fortinet_fgcp_session_magic
;
63 static int hf_fortinet_fgcp_session_type
;
65 static dissector_handle_t fortinet_fgcp_session_handle
;
66 static dissector_handle_t ip_handle
;
68 static int ett_fortinet_fgcp_session
;
70 static const value_string fortinet_fgcp_hb_mode_vals
[] = {
71 { 0x1, "A/A (Active/Active)"},
72 { 0x2, "A/P (Active/Passive)"},
76 #define HB_TLV_END_OF_TLV 0x00
77 #define HB_TLV_VCLUSTER_ID 0x0B
78 #define HB_TLV_PRIORITY 0x0C
79 #define HB_TLV_OVERRIDE 0x0D
81 static const value_string fortinet_fgcp_hb_tlv_vals
[] = {
82 { HB_TLV_END_OF_TLV
, "End of TLV" },
83 { HB_TLV_PRIORITY
, "Port Priority" },
84 { HB_TLV_OVERRIDE
, "Override" },
90 dissect_fortinet_fgcp_hb(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
94 proto_tree
*fortinet_hb_tree
;
95 unsigned offset
= 0, length
, auth_len
=0;
98 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FGCP-HB");
100 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Cluster: %s(%u) - monitor: %s - SN: %s",
101 tvb_get_string_enc(pinfo
->pool
, tvb
, offset
+4, 32, ENC_ASCII
), /* Group Name*/
102 tvb_get_uint16(tvb
, (offset
+4+32+2), ENC_LITTLE_ENDIAN
), /* Group ID*/
103 tvb_get_string_enc(pinfo
->pool
, tvb
, offset
+4+32+2+14, 16, ENC_ASCII
), /* Port */
104 tvb_get_string_enc(pinfo
->pool
, tvb
, offset
+4+32+2+14+16+2+2, 16, ENC_ASCII
) /* Serial Number */);
106 ti
= proto_tree_add_item(tree
, proto_fortinet_fgcp_hb
, tvb
, 0, -1, ENC_NA
);
108 fortinet_hb_tree
= proto_item_add_subtree(ti
, ett_fortinet_fgcp_hb
);
110 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_magic
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
113 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_mode
, tvb
, offset
, 1, ENC_NA
);
116 static int * const fortinet_fgcp_hb_flag
[] = {
117 &hf_fortinet_fgcp_hb_flag_b74
,
118 &hf_fortinet_fgcp_hb_flag_b3
,
119 &hf_fortinet_fgcp_hb_flag_b2
,
120 &hf_fortinet_fgcp_hb_flag_authentication
,
121 &hf_fortinet_fgcp_hb_flag_encryption
,
125 proto_tree_add_bitmask(fortinet_hb_tree
, tvb
, offset
, hf_fortinet_fgcp_hb_flag
, ett_fortinet_fgcp_hb_flag
,
126 fortinet_fgcp_hb_flag
, ENC_NA
);
127 flags
= tvb_get_uint8(tvb
, offset
);
131 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_gn
, tvb
, offset
, 32, ENC_ASCII
);
134 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
138 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_group_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
141 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
144 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
147 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
150 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
153 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
156 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
160 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_port
, tvb
, offset
, 16, ENC_ASCII
);
164 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_revision
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
167 /* Hash/crc ? change after each revision*/
168 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_unknown_uint16
, tvb
, offset
, 2, ENC_NA
);
172 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_sn
, tvb
, offset
, 16, ENC_ASCII
);
175 if (flags
& 0x02) { /* Authentication ? */
176 /* the payload finish with 32bits of authentication (hash ?) */
180 if (flags
& 0x01) { /* Encrypted Payload ?*/
181 length
= tvb_reported_length_remaining(tvb
, offset
) - auth_len
;
182 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_payload_encrypted
, tvb
, offset
, length
, ENC_NA
);
185 unsigned next_offset
;
187 length
= tvb_reported_length_remaining(tvb
, offset
) - auth_len
;
188 next_offset
= offset
+ length
;
190 while (offset
< next_offset
) {
193 proto_tree
*tlv_tree
;
195 ti_tlv
= proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_tlv
, tvb
, offset
, 3, ENC_NA
);
196 tlv_tree
= proto_item_add_subtree(ti_tlv
, ett_fortinet_fgcp_hb_tlv
);
197 proto_tree_add_item_ret_uint(tlv_tree
, hf_fortinet_fgcp_hb_tlv_type
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &type
);
199 proto_tree_add_item_ret_uint(tlv_tree
, hf_fortinet_fgcp_hb_tlv_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &len
);
202 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") );
203 proto_item_set_len(ti_tlv
, 2 + 2 + len
);
205 proto_tree_add_item(tlv_tree
, hf_fortinet_fgcp_hb_tlv_value
, tvb
, offset
, len
, ENC_NA
);
207 case HB_TLV_VCLUSTER_ID
:{
208 uint32_t vcluster_id
;
209 proto_tree_add_item_ret_uint(tlv_tree
, hf_fortinet_fgcp_hb_tlv_vcluster_id
, tvb
, offset
, 1, ENC_NA
, &vcluster_id
);
210 proto_item_append_text(ti_tlv
, ": %u", vcluster_id
);
214 case HB_TLV_PRIORITY
:{
216 proto_tree_add_item_ret_uint(tlv_tree
, hf_fortinet_fgcp_hb_tlv_priority
, tvb
, offset
, 1, ENC_NA
, &priority
);
217 proto_item_append_text(ti_tlv
, ": %u", priority
);
221 case HB_TLV_OVERRIDE
:{
223 proto_tree_add_item_ret_uint(tlv_tree
, hf_fortinet_fgcp_hb_tlv_override
, tvb
, offset
, 1, ENC_NA
, &override
);
225 proto_item_append_text(ti_tlv
, ": True");
227 proto_item_append_text(ti_tlv
, ": False");
239 if (auth_len
) { /* Authentication ? */
240 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_hb_authentication
, tvb
, offset
, 32, ENC_NA
);
248 dissect_fortinet_fgcp_session(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
252 proto_tree
*fortinet_hb_tree
;
256 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "FGCP-SESSION");
258 ti
= proto_tree_add_item(tree
, proto_fortinet_fgcp_session
, tvb
, 0, -1, ENC_NA
);
260 fortinet_hb_tree
= proto_item_add_subtree(ti
, ett_fortinet_fgcp_session
);
262 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_session_magic
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
265 proto_tree_add_item(fortinet_hb_tree
, hf_fortinet_fgcp_session_type
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
268 data_tvb
= tvb_new_subset_remaining(tvb
, offset
);
269 call_dissector(ip_handle
, data_tvb
, pinfo
, tree
);
275 proto_register_fortinet_fgcp(void)
278 static hf_register_info hf
[] = {
280 { &hf_fortinet_fgcp_hb_magic
,
281 { "Magic Number", "fortinet_fgcp.hb.magic",
282 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0,
283 "Magic Number ?", HFILL
}
285 { &hf_fortinet_fgcp_hb_flag
,
286 { "Flag", "fortinet_fgcp.hb.flag",
287 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
290 { &hf_fortinet_fgcp_hb_flag_b74
,
291 { "Bit 7 to 4", "fortinet_fgcp.hb.flag.b74",
292 FT_UINT8
, BASE_HEX
, NULL
, 0xF0,
295 { &hf_fortinet_fgcp_hb_flag_b3
,
296 { "Bit b3", "fortinet_fgcp.hb.flag.b3",
297 FT_UINT8
, BASE_HEX
, NULL
, 0x08,
300 { &hf_fortinet_fgcp_hb_flag_b2
,
301 { "Bit b2", "fortinet_fgcp.hb.flag.b2",
302 FT_UINT8
, BASE_HEX
, NULL
, 0x04,
305 { &hf_fortinet_fgcp_hb_flag_authentication
,
306 { "Authentication", "fortinet_fgcp.hb.flag.authentication",
307 FT_BOOLEAN
, 8, NULL
, 0x02,
310 { &hf_fortinet_fgcp_hb_flag_encryption
,
311 { "Encryption", "fortinet_fgcp.hb.flag.encryption",
312 FT_BOOLEAN
, 8, NULL
, 0x01,
315 { &hf_fortinet_fgcp_hb_mode
,
316 { "Mode", "fortinet_fgcp.hb.mode",
317 FT_UINT8
, BASE_DEC
, VALS(fortinet_fgcp_hb_mode_vals
), 0x0,
320 { &hf_fortinet_fgcp_hb_gn
,
321 { "Group Name", "fortinet_fgcp.hb.gn",
322 FT_STRING
, BASE_NONE
, NULL
, 0x0,
325 { &hf_fortinet_fgcp_hb_group_id
,
326 { "Group Id", "fortinet_fgcp.hb.group_id",
327 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
330 { &hf_fortinet_fgcp_hb_port
,
331 { "Port", "fortinet_fgcp.hb.port",
332 FT_STRING
, BASE_NONE
, NULL
, 0x0,
335 { &hf_fortinet_fgcp_hb_revision
,
336 { "Revision", "fortinet_fgcp.hb.revision",
337 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
338 "Number of revision config for HA", HFILL
}
340 { &hf_fortinet_fgcp_hb_sn
,
341 { "Serial Number", "fortinet_fgcp.hb.sn",
342 FT_STRING
, BASE_NONE
, NULL
, 0x0,
345 { &hf_fortinet_fgcp_hb_payload_encrypted
,
346 { "Payload (encrypted)", "fortinet_fgcp.hb.payload_encrypted",
347 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
350 { &hf_fortinet_fgcp_hb_authentication
,
351 { "Authentication", "fortinet_fgcp.hb.authentication",
352 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
356 { &hf_fortinet_fgcp_hb_tlv
,
357 { "TLV", "fortinet_fgcp.hb.tlv",
358 FT_NONE
, BASE_NONE
, NULL
, 0x0,
361 { &hf_fortinet_fgcp_hb_tlv_type
,
362 { "Type", "fortinet_fgcp.hb.tlv.type",
363 FT_UINT16
, BASE_HEX
, VALS(fortinet_fgcp_hb_tlv_vals
), 0x0,
366 { &hf_fortinet_fgcp_hb_tlv_length
,
367 { "Length", "fortinet_fgcp.hb.tlv.length",
368 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
371 { &hf_fortinet_fgcp_hb_tlv_value
,
372 { "Value", "fortinet_fgcp.hb.tlv.value",
373 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
377 { &hf_fortinet_fgcp_hb_tlv_vcluster_id
,
378 { "Vcluster ID", "fortinet_fgcp.hb.tlv.vcluster_id",
379 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
382 { &hf_fortinet_fgcp_hb_tlv_priority
,
383 { "Port Priority", "fortinet_fgcp.hb.tlv.priority",
384 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
387 { &hf_fortinet_fgcp_hb_tlv_override
,
388 { "Override", "fortinet_fgcp.hb.tlv.override",
389 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
393 { &hf_fortinet_fgcp_hb_unknown,
394 { "Unknown", "fortinet_fgcp.hb.unknown",
395 FT_BYTES, BASE_NONE, NULL, 0x0,
396 "Always NULL ?", HFILL }
399 { &hf_fortinet_fgcp_hb_unknown_uint16
,
400 { "Unknown", "fortinet_fgcp.hb.unknown.uint16",
401 FT_UINT16
, BASE_DEC_HEX
, NULL
, 0x0,
406 { &hf_fortinet_fgcp_session_magic
,
407 { "Magic Number", "fortinet_fgcp.session.magic",
408 FT_UINT16
, BASE_HEX_DEC
, NULL
, 0x0,
409 "Magic Number ?", HFILL
}
411 { &hf_fortinet_fgcp_session_type
,
412 { "Type", "fortinet_fgcp.session.type",
413 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
418 /* Setup protocol subtree array */
419 static int *ett
[] = {
420 &ett_fortinet_fgcp_hb
,
421 &ett_fortinet_fgcp_hb_flag
,
422 &ett_fortinet_fgcp_hb_tlv
,
423 &ett_fortinet_fgcp_session
,
426 /* Register the protocol name and description */
427 proto_fortinet_fgcp_hb
= proto_register_protocol("FortiGate Cluster Protocol - HeartBeat",
428 "fortinet_fgcp_hb", "fortinet_fgcp_hb");
430 proto_fortinet_fgcp_session
= proto_register_protocol("FortiGate Cluster Protocol - Session",
431 "fortinet_fgcp_session", "fortinet_fgcp_session");
433 /* Required function calls to register the header fields and subtrees */
434 proto_register_field_array(proto_fortinet_fgcp_hb
, hf
, array_length(hf
));
435 proto_register_subtree_array(ett
, array_length(ett
));
437 fortinet_fgcp_hb_handle
= register_dissector("fortinet_fgcp_hb", dissect_fortinet_fgcp_hb
,
438 proto_fortinet_fgcp_hb
);
440 fortinet_fgcp_session_handle
= register_dissector("fortinet_fgcp_session", dissect_fortinet_fgcp_session
,
441 proto_fortinet_fgcp_session
);
447 proto_reg_handoff_fortinet_fgcp(void)
449 dissector_add_uint("ethertype", ETHERTYPE_FORTINET_FGCP_HB
, fortinet_fgcp_hb_handle
);
450 dissector_add_uint("ethertype", ETHERTYPE_FORTINET_FGCP_SESSION
, fortinet_fgcp_session_handle
);
452 ip_handle
= find_dissector_add_dependency("ip", proto_fortinet_fgcp_session
);
456 * Editor modelines - https://www.wireshark.org/tools/modelines.html
461 * indent-tabs-mode: nil
464 * vi: set shiftwidth=4 tabstop=8 expandtab:
465 * :indentSize=4:tabSize=8:noTabs=true: