2 * Routines for the Check Point High-Availability Protocol (CPHAP)
3 * Copyright 2002, Yaniv Kaul <ykaul-at-netvision.net.il>
5 * $Id: packet-cpha.c,v 1.6 2003/04/15 22:07:21 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
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.
35 #ifdef NEED_SNPRINTF_H
36 # include "snprintf.h"
39 #include <epan/packet.h>
42 static int proto_cphap = -1;
44 static int hf_magic_number = -1;
45 static int hf_cpha_protocol_ver = -1;
46 static int hf_cluster_number = -1;
47 static int hf_opcode = -1;
48 static int hf_src_if_num = -1;
49 static int hf_random_id = -1;
50 static int hf_src_machine_id = -1;
51 static int hf_dst_machine_id = -1;
52 static int hf_policy_id = -1;
53 static int hf_filler = -1;
54 static int hf_id_num = -1;
55 static int hf_report_code = -1;
56 static int hf_ha_mode = -1;
57 static int hf_ha_time_unit = -1;
58 /*static int hf_problem = -1;*/
59 static int hf_num_reported_ifs = -1;
60 static int hf_ethernet_add = -1;
61 static int hf_is_if_trusted = -1;
62 static int hf_ip = -1;
63 static int hf_slot_num = -1;
64 static int hf_machine_num = -1;
65 static int hf_seed = -1;
66 static int hf_hash_len = -1;
67 static int hf_status = -1;
68 static int hf_in_up_num = -1;
69 static int hf_in_assumed_up_num = -1;
70 static int hf_out_up_num = -1;
71 static int hf_out_assumed_up_num = -1;
72 static int hf_ifn = -1;
74 static gint ett_cphap = -1;
76 #define UDP_PORT_CPHA 8116
77 #define CPHA_MAGIC 0x1A90
81 guint16 ha_protocol_ver;
82 guint16 cluster_number;
86 guint16 src_machine_id;
87 guint16 dst_machine_id;
93 struct fwha_my_state_hdr {
101 struct conf_reply_hdr {
102 guint32 num_reported_ifs;
103 guint8 ethernet_add[6];
104 guint16 is_if_trusted;
112 guint32 hash_list_len;
115 struct fwhap_if_state_s {
117 guint8 in_assumed_up_num;
119 guint8 out_assumed_up_num;
122 #define NUM_OPCODE_TYPES 10
124 static const char *opcode_type_str_short[NUM_OPCODE_TYPES+1] = {
129 "FWHA_IF_PROBE_REPLY",
134 "FWHA_POLICY_CHANGE",
138 static const char *opcode_type_str_long[NUM_OPCODE_TYPES+1] = {
140 "Report source machine's state",
141 "Query other machine's state",
142 "Interface active check request",
143 "Interface active check reply",
144 "Interface configuration request",
145 "Interface configuration reply",
146 "LB configuration report request",
147 "LB configuration report reply",
148 "Policy ID change request/notification",
153 static const char *state_str[NUM_STATES+1] = {
158 "Active/Active-Attention"
162 static const char *status_str[NUM_STATUS+1] = {
164 "New policy arrived - no need to modify HA configuration",
165 "New policy arrived - need to modify HA configuration",
166 "Ready to change configuration"
169 #define NUM_HA_MODES 4
170 static const char *ha_mode_str[NUM_HA_MODES+1] = {
172 "FWHA_NOT_ACTIVE_MODE - CPHA is not active",
173 "FWHA_BALANCE_MODE - More than one machine active",
174 "FWHA_PRIMARY_UP_MODE",
178 static const char *ha_magic_num2str(guint16 magic);
179 static const char *version2str(guint16 version);
180 static const char *opcode2str_short(guint16 opcode);
181 static const char *opcode2str_long(guint16 opcode);
182 static void dissect_my_state(tvbuff_t *, int, proto_tree *);
183 static void dissect_lb_conf(tvbuff_t *, int, proto_tree *);
184 static void dissect_policy_change(tvbuff_t *, int, proto_tree *);
185 static void dissect_probe(tvbuff_t *, int, proto_tree *);
186 static void dissect_conf_reply(tvbuff_t *, int, proto_tree *);
187 int is_report_ifs(guint16);
188 static const char *report_code2str(guint16);
189 static const char *ha_mode2str(guint16);
190 static const char *status2str(guint16);
191 static const char *state2str(guint8);
194 dissect_cpha(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
200 proto_tree * cpha_tree = NULL;
201 proto_tree * ntree = NULL;
205 * If the magic number or protocol version is unknown, don't treat this
206 * frame as a CPHA frame.
208 if (!tvb_bytes_exist(tvb, 0, 4)) {
209 /* Not enough data for the magic number or protocol version */
212 hdr.magic_number = tvb_get_ntohs(tvb, 0);
213 hdr.ha_protocol_ver = tvb_get_ntohs(tvb, 2);
214 if (ha_magic_num2str(hdr.magic_number) == NULL) {
215 /* Bad magic number */
218 if (version2str(hdr.ha_protocol_ver) == NULL) {
219 /* Bad version number */
223 if (check_col(pinfo->cinfo, COL_PROTOCOL))
224 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CPHA");
225 if (check_col(pinfo->cinfo, COL_INFO))
226 col_clear(pinfo->cinfo, COL_INFO);
228 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
229 hdr.magic_number = g_ntohs(hdr.magic_number);
230 hdr.ha_protocol_ver = g_ntohs(hdr.ha_protocol_ver);
231 hdr.random_id = g_ntohs(hdr.random_id);
232 hdr.src_if_num = g_ntohs(hdr.src_if_num);
233 hdr.src_machine_id = g_ntohs(hdr.src_machine_id);
234 hdr.dst_machine_id = g_ntohs(hdr.dst_machine_id);
235 hdr.policy_id = g_ntohs(hdr.policy_id);
236 hdr.filler = g_ntohs(hdr.filler);
237 opcode = g_ntohs(hdr.opcode);
239 if (check_col(pinfo->cinfo, COL_INFO))
240 col_add_fstr(pinfo->cinfo, COL_INFO, "CPHAv%d: %s",
241 g_ntohs(hdr.ha_protocol_ver), opcode2str_short(opcode));
244 ti = proto_tree_add_item(tree, proto_cphap, tvb, offset, -1, FALSE);
245 cpha_tree = proto_item_add_subtree(ti, ett_cphap);
248 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));
249 offset += sizeof(hdr.magic_number);
251 proto_tree_add_uint_format(cpha_tree, hf_cpha_protocol_ver, tvb, offset, sizeof(hdr.ha_protocol_ver), hdr.ha_protocol_ver, "Protocol Version: %d (%s)", hdr.ha_protocol_ver,version2str(hdr.ha_protocol_ver));
252 offset += sizeof(hdr.ha_protocol_ver);
254 proto_tree_add_uint(cpha_tree, hf_cluster_number, tvb, offset, sizeof(hdr.cluster_number), g_ntohs(hdr.cluster_number));
255 offset += sizeof(hdr.cluster_number);
257 proto_tree_add_uint_format(cpha_tree, hf_opcode, tvb, offset, sizeof(hdr.opcode), opcode,
258 "HA OpCode: %d (%s - %s)", opcode, opcode2str_short(opcode), opcode2str_long(opcode));
259 offset += sizeof(hdr.opcode);
261 proto_tree_add_uint(cpha_tree, hf_src_if_num, tvb, offset, sizeof(hdr.src_if_num),
263 offset += sizeof(hdr.src_if_num);
265 proto_tree_add_uint(cpha_tree, hf_random_id, tvb, offset, sizeof(hdr.random_id), hdr.random_id);
266 offset += sizeof(hdr.random_id);
268 proto_tree_add_uint(cpha_tree, hf_src_machine_id, tvb, offset, sizeof(hdr.src_machine_id), hdr.src_machine_id);
269 offset += sizeof(hdr.src_machine_id);
271 proto_tree_add_uint(cpha_tree, hf_dst_machine_id, tvb, offset, sizeof(hdr.dst_machine_id), hdr.dst_machine_id);
272 offset += sizeof(hdr.dst_machine_id);
273 if(hdr.ha_protocol_ver != 1) {/* 4.1 - no policy_id and filler*/
274 proto_tree_add_uint(cpha_tree, hf_policy_id, tvb, offset, sizeof(hdr.policy_id), hdr.policy_id);
275 offset += sizeof(hdr.policy_id);
277 proto_tree_add_uint(cpha_tree, hf_filler, tvb, offset, sizeof(hdr.filler), g_ntohs(hdr.filler));
278 offset += sizeof(hdr.filler);
280 nti = proto_tree_add_text(cpha_tree, tvb, offset, -1, opcode2str_short(opcode));
281 ntree = proto_item_add_subtree(nti, ett_cphap);
284 case 1: dissect_my_state(tvb, offset, ntree); /* FWHAP_MY_STATE */
287 case 3: /* FWHAP_IF_PROBE_REQ */
288 case 4: dissect_probe(tvb, offset, ntree); /* FWHAP_IF_PROBE_RPLY */
291 case 6: dissect_conf_reply(tvb, offset, ntree); /* FWHAP_IFCONF_RPLY */
293 case 7: dissect_lb_conf(tvb, offset, ntree); /* FWHAP_LB_CONF */
295 case 9: dissect_policy_change(tvb, offset, ntree); /* FWHAP_POLICY_CHANGE */
301 return tvb_length(tvb);
304 static void dissect_my_state(tvbuff_t * tvb, int offset, proto_tree * tree) {
305 struct fwha_my_state_hdr hdr;
306 struct fwhap_if_state_s if_hdr;
308 proto_item * nti = NULL;
309 proto_tree * ntree = NULL;
311 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
312 hdr.id_num = g_ntohs(hdr.id_num);
313 hdr.report_code = g_ntohs(hdr.report_code);
314 hdr.ha_mode = g_ntohs(hdr.ha_mode);
315 hdr.ha_time_unit = g_ntohs(hdr.ha_time_unit);
317 proto_tree_add_uint(tree, hf_id_num, tvb, offset, sizeof(hdr.id_num), hdr.id_num);
318 offset += sizeof(hdr.id_num);
320 proto_tree_add_text(tree, tvb, offset, sizeof(hdr.report_code), "Report Code: %s",report_code2str(hdr.report_code));
321 offset += sizeof(hdr.report_code);
323 proto_tree_add_uint_format(tree, hf_ha_mode, tvb, offset, sizeof(hdr.ha_mode), hdr.ha_mode, "HA mode: %d (%s)", hdr.ha_mode, ha_mode2str(hdr.ha_mode));
324 offset += sizeof(hdr.ha_mode);
326 proto_tree_add_uint_format(tree, hf_ha_time_unit, tvb, offset, sizeof(hdr.ha_time_unit), hdr.ha_time_unit, "HA Time unit: %d miliseconds", hdr.ha_time_unit);
327 offset += sizeof(hdr.ha_time_unit);
329 rep_mode = is_report_ifs(hdr.report_code);
330 if (hdr.report_code & 1) {
332 nti = proto_tree_add_text(tree, tvb, offset, hdr.id_num * sizeof(guint8), "Machine states");
333 ntree = proto_item_add_subtree(nti, ett_cphap);
334 for(i=0; i < hdr.id_num; i++) {
335 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)));
336 offset += sizeof(guint8);
339 if (hdr.report_code & 2) {
340 /* interface information */
341 nti = proto_tree_add_text(tree, tvb, offset, sizeof(struct fwhap_if_state_s), "Interface states");
342 ntree = proto_item_add_subtree(nti, ett_cphap);
343 tvb_memcpy(tvb, (guint8 *)&if_hdr, offset, sizeof(if_hdr));
344 proto_tree_add_int(ntree, hf_in_up_num, tvb, offset, sizeof(if_hdr.in_up_num), if_hdr.in_up_num);
345 offset += sizeof(if_hdr.in_up_num);
346 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);
347 offset += sizeof(if_hdr.in_assumed_up_num);
348 proto_tree_add_int(ntree, hf_out_up_num, tvb, offset, sizeof(if_hdr.out_up_num), if_hdr.out_up_num);
349 offset += sizeof(if_hdr.out_up_num);
350 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);
351 offset += sizeof(if_hdr.out_assumed_up_num);
353 for(i=0; i < hdr.id_num; i++) {
354 proto_tree_add_text(tree, tvb, offset, sizeof(guint8), "Cluster %d: last packet seen %d time units ago", i, tvb_get_guint8(tvb, offset));
355 offset += sizeof(guint8);
361 static void dissect_lb_conf(tvbuff_t * tvb, int offset, proto_tree * tree) {
362 struct lb_conf_hdr hdr;
364 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
365 hdr.slot_num = g_ntohs(hdr.slot_num);
366 hdr.machine_num = g_ntohs(hdr.machine_num);
367 hdr.seed = g_ntohs(hdr.seed);
368 hdr.hash_list_len = g_ntohs(hdr.hash_list_len);
370 proto_tree_add_uint(tree, hf_slot_num, tvb, offset, sizeof(hdr.slot_num), hdr.slot_num);
371 offset += sizeof(hdr.slot_num);
373 proto_tree_add_int(tree, hf_machine_num, tvb, offset, sizeof(hdr.machine_num), hdr.machine_num);
374 offset += sizeof(hdr.machine_num);
376 proto_tree_add_uint(tree, hf_seed, tvb, offset, sizeof(hdr.seed), hdr.seed);
377 offset += sizeof(hdr.seed);
379 proto_tree_add_uint(tree, hf_hash_len, tvb, offset, sizeof(hdr.hash_list_len), hdr.hash_list_len);
380 offset += sizeof(hdr.hash_list_len);
384 static void dissect_policy_change(tvbuff_t * tvb, int offset, proto_tree * tree) {
387 status = tvb_get_ntohl(tvb, offset);
389 proto_tree_add_uint_format(tree, hf_status, tvb, offset, sizeof(status), status, "Status %d (%s)", status, status2str(status));
390 offset += sizeof(guint32);
393 static void dissect_probe(tvbuff_t * tvb, int offset, proto_tree * tree) {
396 ifn = tvb_get_ntohl(tvb, offset);
398 proto_tree_add_uint(tree, hf_ifn, tvb, offset, sizeof(ifn), ifn);
399 offset += sizeof(guint32);
402 static void dissect_conf_reply(tvbuff_t * tvb, int offset, proto_tree * tree) {
403 struct conf_reply_hdr hdr;
405 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
406 hdr.num_reported_ifs = g_ntohl(hdr.num_reported_ifs);
407 hdr.is_if_trusted = g_ntohs(hdr.is_if_trusted);
409 proto_tree_add_uint(tree, hf_num_reported_ifs, tvb, offset, sizeof(hdr.num_reported_ifs), hdr.num_reported_ifs);
410 offset += sizeof(hdr.num_reported_ifs);
411 proto_tree_add_ether(tree, hf_ethernet_add, tvb, offset, 6, hdr.ethernet_add);
414 proto_tree_add_boolean(tree, hf_is_if_trusted, tvb, offset, sizeof(hdr.is_if_trusted), hdr.is_if_trusted);
415 offset += sizeof(hdr.is_if_trusted);
417 proto_tree_add_ipv4(tree, hf_ip, tvb, offset, sizeof(hdr.ip), hdr.ip);
421 int is_report_ifs(guint16 report_code) {
428 report_code2str(guint16 report_code) {
430 ret = is_report_ifs(report_code);
431 if(!(report_code & 1))
432 return "Machine information NOT present";
434 return "Interface information included";
435 return "Unknown report code!";
438 ha_magic_num2str(guint16 magic) {
439 if(magic == CPHA_MAGIC)
445 version2str(guint16 version) {
447 case 1: return "4.1";
448 case 6: return "NG Feature Pack 2";
450 case 530: return "NG Feature Pack 3";
455 opcode2str_short(guint16 opcode) {
456 if(opcode <= NUM_OPCODE_TYPES)
457 return opcode_type_str_short[opcode];
458 return opcode_type_str_short[0];
462 ha_mode2str(guint16 hamode) {
463 if(hamode <= NUM_HA_MODES)
464 return ha_mode_str[hamode];
465 return "Unknown HA mode";
469 status2str(guint16 status) {
470 if(status <= NUM_STATUS)
471 return status_str[status];
472 return status_str[0];
476 state2str(guint8 state) {
477 if(state <= NUM_STATES)
478 return state_str[state];
484 opcode2str_long(guint16 opcode) {
485 if(opcode <= NUM_OPCODE_TYPES)
486 return opcode_type_str_long[opcode];
487 return opcode_type_str_long[0];
491 proto_register_cpha(void)
493 static hf_register_info hf[] = {
495 { "CPHAP Magic Number", "cphap.magic_number", FT_UINT16, BASE_HEX, NULL, 0x0, "CPHAP Magic Number", HFILL}},
496 { &hf_cpha_protocol_ver,
497 { "Protocol Version", "cphap.version", FT_UINT16, BASE_DEC, NULL, 0x0, "CPHAP Version", HFILL}},
498 { &hf_cluster_number,
499 { "Cluster Number", "cphap.cluster_number", FT_UINT16, BASE_DEC, NULL, 0x0, "Cluster Number", HFILL}},
501 { "OpCode", "cphap.opcode", FT_UINT16, BASE_DEC, NULL, 0x0, "OpCode", HFILL}},
503 { "Source Interface", "cphap.src_if", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Interface", HFILL}},
505 { "Random ID", "cphap.random_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Random ID", HFILL}},
506 { &hf_src_machine_id,
507 { "Source Machine ID", "cphap.src_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Machine ID", HFILL}},
508 { &hf_dst_machine_id,
509 { "Destination Machine ID", "cphap.dst_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Machine ID", HFILL}},
511 { "Policy ID", "cphap.policy_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Policy ID", HFILL}},
513 { "Filler", "cphap.filler", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
515 { "Number of IDs reported", "cphap.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of IDs reported", HFILL}},
517 { "Report code", "cphap.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, "Report Code", HFILL}},
519 { "HA mode", "cphap.ha_mode", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Mode", HFILL}},
521 { "HA Time unit (ms)", "cphap.ha_time_unit", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Time unit", HFILL}},
522 { &hf_num_reported_ifs,
523 { "Reported Interfaces", "cphap.reported_ifs", FT_UINT32, BASE_DEC, NULL, 0x0, "Reported Interfaces", HFILL}},
525 { "Ethernet Address", "cphap.ethernet_addr", FT_ETHER, BASE_HEX, NULL, 0x0, "Ethernet Address", HFILL}},
527 { "Interface Trusted", "cphap.if_trusted", FT_BOOLEAN, BASE_DEC, NULL, 0x0, "Interface Trusted", HFILL}},
529 { "IP Address", "cphap.ip", FT_IPv4, BASE_DEC, NULL, 0x0, "IP Address", HFILL}},
531 { "Slot Number", "cphap.slot_num", FT_INT16, BASE_DEC, NULL, 0x0, "Slot Number", HFILL}},
533 { "Machine Number", "cphap.machine_num", FT_INT16, BASE_DEC, NULL, 0x0, "Machine Number", HFILL}},
535 { "Seed", "cphap.seed", FT_UINT32, BASE_DEC, NULL, 0x0, "Seed", HFILL}},
537 { "Hash list length", "cphap.hash_len", FT_INT32, BASE_DEC, NULL, 0x0, "Hash list length", HFILL}},
539 { "Interfaces up in the Inbound", "cphap.in_up", FT_INT8, BASE_DEC, NULL, 0x0, "Interfaces up in the Inbound", HFILL}},
540 { &hf_in_assumed_up_num,
541 { "Interfaces assumed up in the Inbound", "cphap.in_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
543 { "Interfaces up in the Outbound", "cphap.out_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
544 { &hf_out_assumed_up_num,
545 { "Interfaces assumed up in the Outbound", "cphap.out_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
547 { "Status", "cphap.status", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
549 { "Interface Number", "cpha.ifn", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
551 static gint *ett[] = {
555 proto_cphap = proto_register_protocol("Check Point High Availability Protocol",
557 proto_register_field_array(proto_cphap, hf, array_length(hf));
558 proto_register_subtree_array(ett, array_length(ett));
562 proto_reg_handoff_cpha(void)
564 dissector_handle_t cpha_handle;
566 cpha_handle = new_create_dissector_handle(dissect_cpha, proto_cphap);
567 dissector_add("udp.port", UDP_PORT_CPHA, cpha_handle);