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.9 2003/12/18 00:25:24 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"
161 static const value_string status_vals[] = {
162 { 1, "New policy arrived - no need to modify HA configuration" },
163 { 2, "New policy arrived - need to modify HA configuration" },
164 { 3, "Ready to change configuration" },
168 #define NUM_HA_MODES 4
169 static const char *ha_mode_str[NUM_HA_MODES+1] = {
171 "FWHA_NOT_ACTIVE_MODE - CPHA is not active",
172 "FWHA_BALANCE_MODE - More than one machine active",
173 "FWHA_PRIMARY_UP_MODE",
177 static const char *ha_magic_num2str(guint16 magic);
178 static const char *version2str(guint16 version);
179 static const char *opcode2str_short(guint16 opcode);
180 static const char *opcode2str_long(guint16 opcode);
181 static void dissect_my_state(tvbuff_t *, int, proto_tree *);
182 static void dissect_lb_conf(tvbuff_t *, int, proto_tree *);
183 static void dissect_policy_change(tvbuff_t *, int, proto_tree *);
184 static void dissect_probe(tvbuff_t *, int, proto_tree *);
185 static void dissect_conf_reply(tvbuff_t *, int, proto_tree *);
186 int is_report_ifs(guint16);
187 static const char *report_code2str(guint16);
188 static const char *ha_mode2str(guint16);
189 static const char *state2str(guint8);
192 dissect_cpha(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
198 proto_tree * cpha_tree = NULL;
199 proto_tree * ntree = NULL;
203 * If the magic number or protocol version is unknown, don't treat this
204 * frame as a CPHA frame.
206 if (!tvb_bytes_exist(tvb, 0, 4)) {
207 /* Not enough data for the magic number or protocol version */
210 hdr.magic_number = tvb_get_ntohs(tvb, 0);
211 hdr.ha_protocol_ver = tvb_get_ntohs(tvb, 2);
212 if (ha_magic_num2str(hdr.magic_number) == NULL) {
213 /* Bad magic number */
216 if (version2str(hdr.ha_protocol_ver) == NULL) {
217 /* Bad version number */
221 if (check_col(pinfo->cinfo, COL_PROTOCOL))
222 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CPHA");
223 if (check_col(pinfo->cinfo, COL_INFO))
224 col_clear(pinfo->cinfo, COL_INFO);
226 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
227 hdr.magic_number = g_ntohs(hdr.magic_number);
228 hdr.ha_protocol_ver = g_ntohs(hdr.ha_protocol_ver);
229 hdr.random_id = g_ntohs(hdr.random_id);
230 hdr.src_if_num = g_ntohs(hdr.src_if_num);
231 hdr.src_machine_id = g_ntohs(hdr.src_machine_id);
232 hdr.dst_machine_id = g_ntohs(hdr.dst_machine_id);
233 hdr.policy_id = g_ntohs(hdr.policy_id);
234 hdr.filler = g_ntohs(hdr.filler);
235 opcode = g_ntohs(hdr.opcode);
237 if (check_col(pinfo->cinfo, COL_INFO))
238 col_add_fstr(pinfo->cinfo, COL_INFO, "CPHAv%d: %s",
239 hdr.ha_protocol_ver, opcode2str_short(opcode));
242 ti = proto_tree_add_item(tree, proto_cphap, tvb, offset, -1, FALSE);
243 cpha_tree = proto_item_add_subtree(ti, ett_cphap);
246 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));
247 offset += sizeof(hdr.magic_number);
249 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));
250 offset += sizeof(hdr.ha_protocol_ver);
252 proto_tree_add_uint(cpha_tree, hf_cluster_number, tvb, offset, sizeof(hdr.cluster_number), g_ntohs(hdr.cluster_number));
253 offset += sizeof(hdr.cluster_number);
255 proto_tree_add_uint_format(cpha_tree, hf_opcode, tvb, offset, sizeof(hdr.opcode), opcode,
256 "HA OpCode: %d (%s - %s)", opcode, opcode2str_short(opcode), opcode2str_long(opcode));
257 offset += sizeof(hdr.opcode);
259 proto_tree_add_uint(cpha_tree, hf_src_if_num, tvb, offset, sizeof(hdr.src_if_num),
261 offset += sizeof(hdr.src_if_num);
263 proto_tree_add_uint(cpha_tree, hf_random_id, tvb, offset, sizeof(hdr.random_id), hdr.random_id);
264 offset += sizeof(hdr.random_id);
266 proto_tree_add_uint(cpha_tree, hf_src_machine_id, tvb, offset, sizeof(hdr.src_machine_id), hdr.src_machine_id);
267 offset += sizeof(hdr.src_machine_id);
269 proto_tree_add_uint(cpha_tree, hf_dst_machine_id, tvb, offset, sizeof(hdr.dst_machine_id), hdr.dst_machine_id);
270 offset += sizeof(hdr.dst_machine_id);
271 if(hdr.ha_protocol_ver != 1) {/* 4.1 - no policy_id and filler*/
272 proto_tree_add_uint(cpha_tree, hf_policy_id, tvb, offset, sizeof(hdr.policy_id), hdr.policy_id);
273 offset += sizeof(hdr.policy_id);
275 proto_tree_add_uint(cpha_tree, hf_filler, tvb, offset, sizeof(hdr.filler), g_ntohs(hdr.filler));
276 offset += sizeof(hdr.filler);
278 nti = proto_tree_add_text(cpha_tree, tvb, offset, -1, opcode2str_short(opcode));
279 ntree = proto_item_add_subtree(nti, ett_cphap);
282 case 1: dissect_my_state(tvb, offset, ntree); /* FWHAP_MY_STATE */
285 case 3: /* FWHAP_IF_PROBE_REQ */
286 case 4: dissect_probe(tvb, offset, ntree); /* FWHAP_IF_PROBE_RPLY */
289 case 6: dissect_conf_reply(tvb, offset, ntree); /* FWHAP_IFCONF_RPLY */
291 case 7: dissect_lb_conf(tvb, offset, ntree); /* FWHAP_LB_CONF */
293 case 9: dissect_policy_change(tvb, offset, ntree); /* FWHAP_POLICY_CHANGE */
299 return tvb_length(tvb);
302 static void dissect_my_state(tvbuff_t * tvb, int offset, proto_tree * tree) {
303 struct fwha_my_state_hdr hdr;
304 struct fwhap_if_state_s if_hdr;
306 proto_item * nti = NULL;
307 proto_tree * ntree = NULL;
309 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
310 hdr.id_num = g_ntohs(hdr.id_num);
311 hdr.report_code = g_ntohs(hdr.report_code);
312 hdr.ha_mode = g_ntohs(hdr.ha_mode);
313 hdr.ha_time_unit = g_ntohs(hdr.ha_time_unit);
315 proto_tree_add_uint(tree, hf_id_num, tvb, offset, sizeof(hdr.id_num), hdr.id_num);
316 offset += sizeof(hdr.id_num);
318 proto_tree_add_text(tree, tvb, offset, sizeof(hdr.report_code), "Report Code: %s",report_code2str(hdr.report_code));
319 offset += sizeof(hdr.report_code);
321 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));
322 offset += sizeof(hdr.ha_mode);
324 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);
325 offset += sizeof(hdr.ha_time_unit);
327 rep_mode = is_report_ifs(hdr.report_code);
328 if (hdr.report_code & 1) {
330 nti = proto_tree_add_text(tree, tvb, offset, hdr.id_num * sizeof(guint8), "Machine states");
331 ntree = proto_item_add_subtree(nti, ett_cphap);
332 for(i=0; i < hdr.id_num; i++) {
333 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)));
334 offset += sizeof(guint8);
337 if (hdr.report_code & 2) {
338 /* interface information */
339 nti = proto_tree_add_text(tree, tvb, offset, sizeof(struct fwhap_if_state_s), "Interface states");
340 ntree = proto_item_add_subtree(nti, ett_cphap);
341 tvb_memcpy(tvb, (guint8 *)&if_hdr, offset, sizeof(if_hdr));
342 proto_tree_add_int(ntree, hf_in_up_num, tvb, offset, sizeof(if_hdr.in_up_num), if_hdr.in_up_num);
343 offset += sizeof(if_hdr.in_up_num);
344 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);
345 offset += sizeof(if_hdr.in_assumed_up_num);
346 proto_tree_add_int(ntree, hf_out_up_num, tvb, offset, sizeof(if_hdr.out_up_num), if_hdr.out_up_num);
347 offset += sizeof(if_hdr.out_up_num);
348 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);
349 offset += sizeof(if_hdr.out_assumed_up_num);
351 for(i=0; i < hdr.id_num; i++) {
352 proto_tree_add_text(tree, tvb, offset, sizeof(guint8), "Cluster %d: last packet seen %d time units ago", i, tvb_get_guint8(tvb, offset));
353 offset += sizeof(guint8);
359 static void dissect_lb_conf(tvbuff_t * tvb, int offset, proto_tree * tree) {
360 struct lb_conf_hdr hdr;
362 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
363 hdr.slot_num = g_ntohs(hdr.slot_num);
364 hdr.machine_num = g_ntohs(hdr.machine_num);
365 hdr.seed = g_ntohs(hdr.seed);
366 hdr.hash_list_len = g_ntohs(hdr.hash_list_len);
368 proto_tree_add_uint(tree, hf_slot_num, tvb, offset, sizeof(hdr.slot_num), hdr.slot_num);
369 offset += sizeof(hdr.slot_num);
371 proto_tree_add_int(tree, hf_machine_num, tvb, offset, sizeof(hdr.machine_num), hdr.machine_num);
372 offset += sizeof(hdr.machine_num);
374 proto_tree_add_uint(tree, hf_seed, tvb, offset, sizeof(hdr.seed), hdr.seed);
375 offset += sizeof(hdr.seed);
377 proto_tree_add_uint(tree, hf_hash_len, tvb, offset, sizeof(hdr.hash_list_len), hdr.hash_list_len);
378 offset += sizeof(hdr.hash_list_len);
382 static void dissect_policy_change(tvbuff_t * tvb, int offset, proto_tree * tree) {
385 status = tvb_get_ntohl(tvb, offset);
387 proto_tree_add_uint(tree, hf_status, tvb, offset, sizeof(status), status);
388 offset += sizeof(guint32);
391 static void dissect_probe(tvbuff_t * tvb, int offset, proto_tree * tree) {
394 ifn = tvb_get_ntohl(tvb, offset);
396 proto_tree_add_uint(tree, hf_ifn, tvb, offset, sizeof(ifn), ifn);
397 offset += sizeof(guint32);
400 static void dissect_conf_reply(tvbuff_t * tvb, int offset, proto_tree * tree) {
401 struct conf_reply_hdr hdr;
403 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
404 hdr.num_reported_ifs = g_ntohl(hdr.num_reported_ifs);
405 hdr.is_if_trusted = g_ntohs(hdr.is_if_trusted);
407 proto_tree_add_uint(tree, hf_num_reported_ifs, tvb, offset, sizeof(hdr.num_reported_ifs), hdr.num_reported_ifs);
408 offset += sizeof(hdr.num_reported_ifs);
409 proto_tree_add_ether(tree, hf_ethernet_add, tvb, offset, 6, hdr.ethernet_add);
412 proto_tree_add_boolean(tree, hf_is_if_trusted, tvb, offset, sizeof(hdr.is_if_trusted), hdr.is_if_trusted);
413 offset += sizeof(hdr.is_if_trusted);
415 proto_tree_add_ipv4(tree, hf_ip, tvb, offset, sizeof(hdr.ip), hdr.ip);
419 int is_report_ifs(guint16 report_code) {
426 report_code2str(guint16 report_code) {
428 ret = is_report_ifs(report_code);
429 if(!(report_code & 1))
430 return "Machine information NOT present";
432 return "Interface information included";
433 return "Unknown report code!";
436 ha_magic_num2str(guint16 magic) {
437 if(magic == CPHA_MAGIC)
443 version2str(guint16 version) {
445 case 1: return "4.1";
447 case 6: return "NG Feature Pack 2";
449 case 530: return "NG Feature Pack 3";
451 case 540: return "NG with Application Intelligence (Early Availability)";
453 case 541: return "NG with Application Intelligence";
455 default: return "Unknown Version";
461 opcode2str_short(guint16 opcode) {
462 if(opcode <= NUM_OPCODE_TYPES)
463 return opcode_type_str_short[opcode];
464 return opcode_type_str_short[0];
468 ha_mode2str(guint16 hamode) {
469 if(hamode <= NUM_HA_MODES)
470 return ha_mode_str[hamode];
471 return "Unknown HA mode";
475 state2str(guint8 state) {
476 if(state <= NUM_STATES)
477 return state_str[state];
483 opcode2str_long(guint16 opcode) {
484 if(opcode <= NUM_OPCODE_TYPES)
485 return opcode_type_str_long[opcode];
486 return opcode_type_str_long[0];
490 proto_register_cpha(void)
492 static hf_register_info hf[] = {
494 { "CPHAP Magic Number", "cphap.magic_number", FT_UINT16, BASE_HEX, NULL, 0x0, "CPHAP Magic Number", HFILL}},
495 { &hf_cpha_protocol_ver,
496 { "Protocol Version", "cphap.version", FT_UINT16, BASE_DEC, NULL, 0x0, "CPHAP Version", HFILL}},
497 { &hf_cluster_number,
498 { "Cluster Number", "cphap.cluster_number", FT_UINT16, BASE_DEC, NULL, 0x0, "Cluster Number", HFILL}},
500 { "OpCode", "cphap.opcode", FT_UINT16, BASE_DEC, NULL, 0x0, "OpCode", HFILL}},
502 { "Source Interface", "cphap.src_if", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Interface", HFILL}},
504 { "Random ID", "cphap.random_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Random ID", HFILL}},
505 { &hf_src_machine_id,
506 { "Source Machine ID", "cphap.src_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Machine ID", HFILL}},
507 { &hf_dst_machine_id,
508 { "Destination Machine ID", "cphap.dst_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Machine ID", HFILL}},
510 { "Policy ID", "cphap.policy_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Policy ID", HFILL}},
512 { "Filler", "cphap.filler", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
514 { "Number of IDs reported", "cphap.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of IDs reported", HFILL}},
516 { "Report code", "cphap.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, "Report Code", HFILL}},
518 { "HA mode", "cphap.ha_mode", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Mode", HFILL}},
520 { "HA Time unit (ms)", "cphap.ha_time_unit", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Time unit", HFILL}},
521 { &hf_num_reported_ifs,
522 { "Reported Interfaces", "cphap.reported_ifs", FT_UINT32, BASE_DEC, NULL, 0x0, "Reported Interfaces", HFILL}},
524 { "Ethernet Address", "cphap.ethernet_addr", FT_ETHER, BASE_HEX, NULL, 0x0, "Ethernet Address", HFILL}},
526 { "Interface Trusted", "cphap.if_trusted", FT_BOOLEAN, BASE_DEC, NULL, 0x0, "Interface Trusted", HFILL}},
528 { "IP Address", "cphap.ip", FT_IPv4, BASE_DEC, NULL, 0x0, "IP Address", HFILL}},
530 { "Slot Number", "cphap.slot_num", FT_INT16, BASE_DEC, NULL, 0x0, "Slot Number", HFILL}},
532 { "Machine Number", "cphap.machine_num", FT_INT16, BASE_DEC, NULL, 0x0, "Machine Number", HFILL}},
534 { "Seed", "cphap.seed", FT_UINT32, BASE_DEC, NULL, 0x0, "Seed", HFILL}},
536 { "Hash list length", "cphap.hash_len", FT_INT32, BASE_DEC, NULL, 0x0, "Hash list length", HFILL}},
538 { "Interfaces up in the Inbound", "cphap.in_up", FT_INT8, BASE_DEC, NULL, 0x0, "Interfaces up in the Inbound", HFILL}},
539 { &hf_in_assumed_up_num,
540 { "Interfaces assumed up in the Inbound", "cphap.in_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
542 { "Interfaces up in the Outbound", "cphap.out_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
543 { &hf_out_assumed_up_num,
544 { "Interfaces assumed up in the Outbound", "cphap.out_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
546 { "Status", "cphap.status", FT_UINT32, BASE_DEC, VALS(status_vals), 0x0, "", HFILL}},
548 { "Interface Number", "cpha.ifn", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
550 static gint *ett[] = {
554 proto_cphap = proto_register_protocol("Check Point High Availability Protocol",
556 proto_register_field_array(proto_cphap, hf, array_length(hf));
557 proto_register_subtree_array(ett, array_length(ett));
561 proto_reg_handoff_cpha(void)
563 dissector_handle_t cpha_handle;
565 cpha_handle = new_create_dissector_handle(dissect_cpha, proto_cphap);
566 dissector_add("udp.port", UDP_PORT_CPHA, cpha_handle);