2 * Routines for the Check Point High-Availability Protocol (CPHAP)
3 * Copyright 2002, Yaniv Kaul <ykaul-at-netvision.net.il>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include <epan/ipproto.h>
35 static int proto_cphap = -1;
37 static int hf_magic_number = -1;
38 static int hf_cpha_protocol_ver = -1;
39 static int hf_cluster_number = -1;
40 static int hf_opcode = -1;
41 static int hf_src_if_num = -1;
42 static int hf_random_id = -1;
43 static int hf_src_machine_id = -1;
44 static int hf_dst_machine_id = -1;
45 static int hf_policy_id = -1;
46 static int hf_filler = -1;
47 static int hf_id_num = -1;
48 static int hf_report_code = -1;
49 static int hf_ha_mode = -1;
50 static int hf_ha_time_unit = -1;
51 /*static int hf_problem = -1;*/
52 static int hf_num_reported_ifs = -1;
53 static int hf_ethernet_add = -1;
54 static int hf_is_if_trusted = -1;
55 static int hf_ip = -1;
56 static int hf_slot_num = -1;
57 static int hf_machine_num = -1;
58 static int hf_seed = -1;
59 static int hf_hash_len = -1;
60 static int hf_status = -1;
61 static int hf_in_up_num = -1;
62 static int hf_in_assumed_up_num = -1;
63 static int hf_out_up_num = -1;
64 static int hf_out_assumed_up_num = -1;
65 static int hf_ifn = -1;
67 static gint ett_cphap = -1;
69 #define UDP_PORT_CPHA 8116
70 #define CPHA_MAGIC 0x1A90
74 guint16 ha_protocol_ver;
75 guint16 cluster_number;
79 guint16 src_machine_id;
80 guint16 dst_machine_id;
86 struct fwha_my_state_hdr {
94 struct conf_reply_hdr {
95 guint32 num_reported_ifs;
96 guint8 ethernet_add[6];
97 guint16 is_if_trusted;
105 guint32 hash_list_len;
108 struct fwhap_if_state_s {
110 guint8 in_assumed_up_num;
112 guint8 out_assumed_up_num;
115 #define NUM_OPCODE_TYPES 10
117 static const char *opcode_type_str_short[NUM_OPCODE_TYPES+1] = {
122 "FWHA_IF_PROBE_REPLY",
127 "FWHA_POLICY_CHANGE",
131 static const char *opcode_type_str_long[NUM_OPCODE_TYPES+1] = {
133 "Report source machine's state",
134 "Query other machine's state",
135 "Interface active check request",
136 "Interface active check reply",
137 "Interface configuration request",
138 "Interface configuration reply",
139 "LB configuration report request",
140 "LB configuration report reply",
141 "Policy ID change request/notification",
146 static const char *state_str[NUM_STATES] = {
151 "Active/Active-Attention"
154 static const value_string status_vals[] = {
155 { 1, "New policy arrived - no need to modify HA configuration" },
156 { 2, "New policy arrived - need to modify HA configuration" },
157 { 3, "Ready to change configuration" },
161 #define NUM_HA_MODES 4
162 static const char *ha_mode_str[NUM_HA_MODES+1] = {
164 "FWHA_NOT_ACTIVE_MODE - CPHA is not active",
165 "FWHA_BALANCE_MODE - More than one machine active",
166 "FWHA_PRIMARY_UP_MODE",
170 static const char *ha_magic_num2str(guint16 magic);
171 static const char *version2str(guint16 version);
172 static const char *opcode2str_short(guint16 opcode);
173 static const char *opcode2str_long(guint16 opcode);
174 static void dissect_my_state(tvbuff_t *, int, proto_tree *);
175 static void dissect_lb_conf(tvbuff_t *, int, proto_tree *);
176 static void dissect_policy_change(tvbuff_t *, int, proto_tree *);
177 static void dissect_probe(tvbuff_t *, int, proto_tree *);
178 static void dissect_conf_reply(tvbuff_t *, int, proto_tree *);
179 static int is_report_ifs(guint16);
180 static const char *report_code2str(guint16);
181 static const char *ha_mode2str(guint16);
182 static const char *state2str(guint8);
185 dissect_cpha(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
191 proto_tree * cpha_tree = NULL;
192 proto_tree * ntree = NULL;
196 * If the magic number or protocol version is unknown, don't treat this
197 * frame as a CPHA frame.
199 if (tvb_length(tvb) < 4) {
200 /* Not enough data for the magic number or protocol version */
203 hdr.magic_number = tvb_get_ntohs(tvb, 0);
204 hdr.ha_protocol_ver = tvb_get_ntohs(tvb, 2);
205 if (ha_magic_num2str(hdr.magic_number) == NULL) {
206 /* Bad magic number */
209 if (version2str(hdr.ha_protocol_ver) == NULL) {
210 /* Bad version number */
214 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CPHA");
215 col_clear(pinfo->cinfo, COL_INFO);
217 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
218 hdr.magic_number = g_ntohs(hdr.magic_number);
219 hdr.ha_protocol_ver = g_ntohs(hdr.ha_protocol_ver);
220 hdr.random_id = g_ntohs(hdr.random_id);
221 hdr.src_if_num = g_ntohs(hdr.src_if_num);
222 hdr.src_machine_id = g_ntohs(hdr.src_machine_id);
223 hdr.dst_machine_id = g_ntohs(hdr.dst_machine_id);
224 hdr.policy_id = g_ntohs(hdr.policy_id);
225 hdr.filler = g_ntohs(hdr.filler);
226 opcode = g_ntohs(hdr.opcode);
228 if (check_col(pinfo->cinfo, COL_INFO))
229 col_add_fstr(pinfo->cinfo, COL_INFO, "CPHAv%d: %s",
230 hdr.ha_protocol_ver, opcode2str_short(opcode));
233 ti = proto_tree_add_item(tree, proto_cphap, tvb, offset, -1, FALSE);
234 cpha_tree = proto_item_add_subtree(ti, ett_cphap);
237 proto_tree_add_uint_format(cpha_tree, hf_magic_number, tvb, offset, sizeof(hdr.magic_number), hdr.magic_number, "Magic Number: 0x%x (%s)", hdr.magic_number, ha_magic_num2str(hdr.magic_number));
238 offset += sizeof(hdr.magic_number);
240 proto_tree_add_uint_format_value(cpha_tree, hf_cpha_protocol_ver, tvb, offset, sizeof(hdr.ha_protocol_ver), hdr.ha_protocol_ver, "%d (%s)", hdr.ha_protocol_ver,version2str(hdr.ha_protocol_ver));
241 offset += sizeof(hdr.ha_protocol_ver);
243 proto_tree_add_uint(cpha_tree, hf_cluster_number, tvb, offset, sizeof(hdr.cluster_number), g_ntohs(hdr.cluster_number));
244 offset += sizeof(hdr.cluster_number);
246 proto_tree_add_uint_format(cpha_tree, hf_opcode, tvb, offset, sizeof(hdr.opcode), opcode,
247 "HA OpCode: %d (%s - %s)", opcode, opcode2str_short(opcode), opcode2str_long(opcode));
248 offset += sizeof(hdr.opcode);
250 proto_tree_add_uint(cpha_tree, hf_src_if_num, tvb, offset, sizeof(hdr.src_if_num),
252 offset += sizeof(hdr.src_if_num);
254 proto_tree_add_uint(cpha_tree, hf_random_id, tvb, offset, sizeof(hdr.random_id), hdr.random_id);
255 offset += sizeof(hdr.random_id);
257 proto_tree_add_uint(cpha_tree, hf_src_machine_id, tvb, offset, sizeof(hdr.src_machine_id), hdr.src_machine_id);
258 offset += sizeof(hdr.src_machine_id);
260 proto_tree_add_uint(cpha_tree, hf_dst_machine_id, tvb, offset, sizeof(hdr.dst_machine_id), hdr.dst_machine_id);
261 offset += sizeof(hdr.dst_machine_id);
262 if(hdr.ha_protocol_ver != 1) {/* 4.1 - no policy_id and filler*/
263 proto_tree_add_uint(cpha_tree, hf_policy_id, tvb, offset, sizeof(hdr.policy_id), hdr.policy_id);
264 offset += sizeof(hdr.policy_id);
266 proto_tree_add_uint(cpha_tree, hf_filler, tvb, offset, sizeof(hdr.filler), g_ntohs(hdr.filler));
267 offset += sizeof(hdr.filler);
269 nti = proto_tree_add_text(cpha_tree, tvb, offset, -1, "%s", opcode2str_short(opcode));
270 ntree = proto_item_add_subtree(nti, ett_cphap);
273 case 1: dissect_my_state(tvb, offset, ntree); /* FWHAP_MY_STATE */
276 case 3: /* FWHAP_IF_PROBE_REQ */
277 case 4: dissect_probe(tvb, offset, ntree); /* FWHAP_IF_PROBE_RPLY */
280 case 6: dissect_conf_reply(tvb, offset, ntree); /* FWHAP_IFCONF_RPLY */
282 case 7: dissect_lb_conf(tvb, offset, ntree); /* FWHAP_LB_CONF */
284 case 9: dissect_policy_change(tvb, offset, ntree); /* FWHAP_POLICY_CHANGE */
290 return tvb_length(tvb);
293 static void dissect_my_state(tvbuff_t * tvb, int offset, proto_tree * tree) {
294 struct fwha_my_state_hdr hdr;
295 struct fwhap_if_state_s if_hdr;
297 proto_item * nti = NULL;
298 proto_tree * ntree = NULL;
300 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
301 hdr.id_num = g_ntohs(hdr.id_num);
302 hdr.report_code = g_ntohs(hdr.report_code);
303 hdr.ha_mode = g_ntohs(hdr.ha_mode);
304 hdr.ha_time_unit = g_ntohs(hdr.ha_time_unit);
306 proto_tree_add_uint(tree, hf_id_num, tvb, offset, sizeof(hdr.id_num), hdr.id_num);
307 offset += sizeof(hdr.id_num);
309 proto_tree_add_text(tree, tvb, offset, sizeof(hdr.report_code), "Report Code: %s",report_code2str(hdr.report_code));
310 offset += sizeof(hdr.report_code);
312 proto_tree_add_uint_format_value(tree, hf_ha_mode, tvb, offset, sizeof(hdr.ha_mode), hdr.ha_mode, "%d (%s)", hdr.ha_mode, ha_mode2str(hdr.ha_mode));
313 offset += sizeof(hdr.ha_mode);
315 proto_tree_add_uint_format_value(tree, hf_ha_time_unit, tvb, offset, sizeof(hdr.ha_time_unit), hdr.ha_time_unit, "%d milliseconds", hdr.ha_time_unit);
316 offset += sizeof(hdr.ha_time_unit);
318 rep_mode = is_report_ifs(hdr.report_code);
319 if (hdr.report_code & 1) {
321 nti = proto_tree_add_text(tree, tvb, offset, hdr.id_num * sizeof(guint8), "Machine states");
322 ntree = proto_item_add_subtree(nti, ett_cphap);
323 for(i=0; i < hdr.id_num; i++) {
324 proto_tree_add_text(ntree, tvb, offset, sizeof(guint8), "State of node %d: %d (%s)", i, tvb_get_guint8(tvb, offset), state2str(tvb_get_guint8(tvb, offset)));
325 offset += sizeof(guint8);
328 if (hdr.report_code & 2) {
329 /* interface information */
330 nti = proto_tree_add_text(tree, tvb, offset, sizeof(struct fwhap_if_state_s), "Interface states");
331 ntree = proto_item_add_subtree(nti, ett_cphap);
332 tvb_memcpy(tvb, (guint8 *)&if_hdr, offset, sizeof(if_hdr));
333 proto_tree_add_int(ntree, hf_in_up_num, tvb, offset, sizeof(if_hdr.in_up_num), if_hdr.in_up_num);
334 offset += sizeof(if_hdr.in_up_num);
335 proto_tree_add_int(ntree, hf_in_assumed_up_num, tvb, offset, sizeof(if_hdr.in_assumed_up_num), if_hdr.in_assumed_up_num);
336 offset += sizeof(if_hdr.in_assumed_up_num);
337 proto_tree_add_int(ntree, hf_out_up_num, tvb, offset, sizeof(if_hdr.out_up_num), if_hdr.out_up_num);
338 offset += sizeof(if_hdr.out_up_num);
339 proto_tree_add_int(ntree, hf_out_assumed_up_num, tvb, offset, sizeof(if_hdr.out_assumed_up_num), if_hdr.out_assumed_up_num);
340 offset += sizeof(if_hdr.out_assumed_up_num);
342 for(i=0; i < hdr.id_num; i++) {
343 proto_tree_add_text(tree, tvb, offset, sizeof(guint8), "Cluster %d: last packet seen %d time units ago", i, tvb_get_guint8(tvb, offset));
344 offset += sizeof(guint8);
350 static void dissect_lb_conf(tvbuff_t * tvb, int offset, proto_tree * tree) {
351 struct lb_conf_hdr hdr;
353 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
354 hdr.slot_num = g_ntohs(hdr.slot_num);
355 hdr.machine_num = g_ntohs(hdr.machine_num);
356 hdr.seed = g_ntohs(hdr.seed);
357 hdr.hash_list_len = g_ntohs(hdr.hash_list_len);
359 proto_tree_add_uint(tree, hf_slot_num, tvb, offset, sizeof(hdr.slot_num), hdr.slot_num);
360 offset += sizeof(hdr.slot_num);
362 proto_tree_add_int(tree, hf_machine_num, tvb, offset, sizeof(hdr.machine_num), hdr.machine_num);
363 offset += sizeof(hdr.machine_num);
365 proto_tree_add_uint(tree, hf_seed, tvb, offset, sizeof(hdr.seed), hdr.seed);
366 offset += sizeof(hdr.seed);
368 proto_tree_add_uint(tree, hf_hash_len, tvb, offset, sizeof(hdr.hash_list_len), hdr.hash_list_len);
369 offset += sizeof(hdr.hash_list_len);
373 static void dissect_policy_change(tvbuff_t * tvb, int offset, proto_tree * tree) {
376 status = tvb_get_ntohl(tvb, offset);
378 proto_tree_add_uint(tree, hf_status, tvb, offset, sizeof(status), status);
379 offset += sizeof(guint32);
382 static void dissect_probe(tvbuff_t * tvb, int offset, proto_tree * tree) {
385 ifn = tvb_get_ntohl(tvb, offset);
387 proto_tree_add_uint(tree, hf_ifn, tvb, offset, sizeof(ifn), ifn);
388 offset += sizeof(guint32);
391 static void dissect_conf_reply(tvbuff_t * tvb, int offset, proto_tree * tree) {
392 struct conf_reply_hdr hdr;
394 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
395 hdr.num_reported_ifs = g_ntohl(hdr.num_reported_ifs);
396 hdr.is_if_trusted = g_ntohs(hdr.is_if_trusted);
398 proto_tree_add_uint(tree, hf_num_reported_ifs, tvb, offset, sizeof(hdr.num_reported_ifs), hdr.num_reported_ifs);
399 offset += sizeof(hdr.num_reported_ifs);
400 proto_tree_add_ether(tree, hf_ethernet_add, tvb, offset, 6, hdr.ethernet_add);
403 proto_tree_add_boolean(tree, hf_is_if_trusted, tvb, offset, sizeof(hdr.is_if_trusted), hdr.is_if_trusted);
404 offset += sizeof(hdr.is_if_trusted);
406 proto_tree_add_ipv4(tree, hf_ip, tvb, offset, sizeof(hdr.ip), hdr.ip);
411 is_report_ifs(guint16 report_code) {
418 report_code2str(guint16 report_code) {
420 ret = is_report_ifs(report_code);
421 if(!(report_code & 1))
422 return "Machine information NOT present";
424 return "Interface information included";
425 return "Unknown report code!";
428 ha_magic_num2str(guint16 magic) {
429 if(magic == CPHA_MAGIC)
435 version2str(guint16 version) {
437 case 1: return "4.1";
438 case 6: return "NG Feature Pack 2";
439 case 530: return "NG Feature Pack 3";
440 case 540: return "NG with Application Intelligence (Early Availability)";
441 case 541: return "NG with Application Intelligence";
444 return "Unknown Version";
447 opcode2str_short(guint16 opcode) {
448 if(opcode <= NUM_OPCODE_TYPES)
449 return opcode_type_str_short[opcode];
450 return opcode_type_str_short[0];
454 ha_mode2str(guint16 hamode) {
455 if(hamode <= NUM_HA_MODES)
456 return ha_mode_str[hamode];
457 return "Unknown HA mode";
461 state2str(guint8 state) {
462 if(state < NUM_STATES)
463 return state_str[state];
469 opcode2str_long(guint16 opcode) {
470 if(opcode <= NUM_OPCODE_TYPES)
471 return opcode_type_str_long[opcode];
472 return opcode_type_str_long[0];
476 proto_register_cpha(void)
478 static hf_register_info hf[] = {
480 { "CPHAP Magic Number", "cpha.magic_number", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
481 { &hf_cpha_protocol_ver,
482 { "Protocol Version", "cpha.version", FT_UINT16, BASE_DEC, NULL, 0x0, "CPHAP Version", HFILL}},
483 { &hf_cluster_number,
484 { "Cluster Number", "cpha.cluster_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
486 { "OpCode", "cpha.opcode", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
488 { "Source Interface", "cpha.src_if", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
490 { "Random ID", "cpha.random_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
491 { &hf_src_machine_id,
492 { "Source Machine ID", "cpha.src_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
493 { &hf_dst_machine_id,
494 { "Destination Machine ID", "cpha.dst_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
496 { "Policy ID", "cpha.policy_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
498 { "Filler", "cpha.filler", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
500 { "Number of IDs reported", "cpha.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
502 { "Report code", "cpha.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
504 { "HA mode", "cpha.ha_mode", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
506 { "HA Time unit", "cpha.ha_time_unit", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Time unit (ms)", HFILL}},
507 { &hf_num_reported_ifs,
508 { "Reported Interfaces", "cpha.reported_ifs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
510 { "Ethernet Address", "cpha.ethernet_addr", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL}},
512 { "Interface Trusted", "cpha.if_trusted", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}},
514 { "IP Address", "cpha.ip", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL}},
516 { "Slot Number", "cpha.slot_num", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
518 { "Machine Number", "cpha.machine_num", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
520 { "Seed", "cpha.seed", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
522 { "Hash list length", "cpha.hash_len", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
524 { "Interfaces up in the Inbound", "cpha.in_up", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
525 { &hf_in_assumed_up_num,
526 { "Interfaces assumed up in the Inbound", "cpha.in_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
528 { "Interfaces up in the Outbound", "cpha.out_up", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
529 { &hf_out_assumed_up_num,
530 { "Interfaces assumed up in the Outbound", "cpha.out_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
532 { "Status", "cpha.status", FT_UINT32, BASE_DEC, VALS(status_vals), 0x0, NULL, HFILL}},
534 { "Interface Number", "cpha.ifn", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
536 static gint *ett[] = {
540 proto_cphap = proto_register_protocol("Check Point High Availability Protocol",
542 proto_register_field_array(proto_cphap, hf, array_length(hf));
543 proto_register_subtree_array(ett, array_length(ett));
547 proto_reg_handoff_cpha(void)
549 dissector_handle_t cpha_handle;
551 cpha_handle = new_create_dissector_handle(dissect_cpha, proto_cphap);
552 dissector_add_uint("udp.port", UDP_PORT_CPHA, cpha_handle);