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.2 2002/08/20 22:56:29 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;
202 static char info[30];
206 * If the magic number or protocol version is unknown, don't treat this
207 * frame as a CPHA frame.
209 if (!tvb_bytes_exist(tvb, 0, 4)) {
210 /* Not enough data for the magic number or protocol version */
213 hdr.magic_number = tvb_get_ntohs(tvb, 0);
214 hdr.ha_protocol_ver = tvb_get_ntohs(tvb, 2);
215 if (ha_magic_num2str(hdr.magic_number) == NULL) {
216 /* Bad magic number */
219 if (version2str(hdr.ha_protocol_ver) == NULL) {
220 /* Bad version number */
224 if (check_col(pinfo->cinfo, COL_PROTOCOL))
225 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CPHA");
226 if (check_col(pinfo->cinfo, COL_INFO))
227 col_clear(pinfo->cinfo, COL_INFO);
229 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
230 hdr.magic_number = g_ntohs(hdr.magic_number);
231 hdr.ha_protocol_ver = g_ntohs(hdr.ha_protocol_ver);
232 hdr.random_id = g_ntohs(hdr.random_id);
233 hdr.src_if_num = g_ntohs(hdr.src_if_num);
234 hdr.src_machine_id = g_ntohs(hdr.src_machine_id);
235 hdr.dst_machine_id = g_ntohs(hdr.dst_machine_id);
236 hdr.policy_id = g_ntohs(hdr.policy_id);
237 hdr.filler = g_ntohs(hdr.filler);
238 opcode = g_ntohs(hdr.opcode);
240 snprintf(info,50,"CPHAv%d: %s",g_ntohs(hdr.ha_protocol_ver), opcode2str_short(opcode));
241 if (check_col(pinfo->cinfo, COL_INFO))
242 col_add_str(pinfo->cinfo, COL_INFO,info);
245 ti = proto_tree_add_item(tree, proto_cphap, tvb, offset, -1, FALSE);
246 cpha_tree = proto_item_add_subtree(ti, ett_cphap);
249 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));
250 offset += sizeof(hdr.magic_number);
252 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));
253 offset += sizeof(hdr.ha_protocol_ver);
255 proto_tree_add_uint(cpha_tree, hf_cluster_number, tvb, offset, sizeof(hdr.cluster_number), g_ntohs(hdr.cluster_number));
256 offset += sizeof(hdr.cluster_number);
258 proto_tree_add_uint_format(cpha_tree, hf_opcode, tvb, offset, sizeof(hdr.opcode), opcode,
259 "HA OpCode: %d (%s - %s)", opcode, opcode2str_short(opcode), opcode2str_long(opcode));
260 offset += sizeof(hdr.opcode);
262 proto_tree_add_uint(cpha_tree, hf_src_if_num, tvb, offset, sizeof(hdr.src_if_num),
264 offset += sizeof(hdr.src_if_num);
266 proto_tree_add_uint(cpha_tree, hf_random_id, tvb, offset, sizeof(hdr.random_id), hdr.random_id);
267 offset += sizeof(hdr.random_id);
269 proto_tree_add_uint(cpha_tree, hf_src_machine_id, tvb, offset, sizeof(hdr.src_machine_id), hdr.src_machine_id);
270 offset += sizeof(hdr.src_machine_id);
272 proto_tree_add_uint(cpha_tree, hf_dst_machine_id, tvb, offset, sizeof(hdr.dst_machine_id), hdr.dst_machine_id);
273 offset += sizeof(hdr.dst_machine_id);
274 if(hdr.ha_protocol_ver != 1) {/* 4.1 - no policy_id and filler*/
275 proto_tree_add_uint(cpha_tree, hf_policy_id, tvb, offset, sizeof(hdr.policy_id), hdr.policy_id);
276 offset += sizeof(hdr.policy_id);
278 proto_tree_add_uint(cpha_tree, hf_filler, tvb, offset, sizeof(hdr.filler), g_ntohs(hdr.filler));
279 offset += sizeof(hdr.filler);
281 nti = proto_tree_add_text(cpha_tree, tvb, offset, -1, opcode2str_short(opcode));
282 ntree = proto_item_add_subtree(nti, ett_cphap);
285 case 1: dissect_my_state(tvb, offset, ntree); /* FWHAP_MY_STATE */
288 case 3: /* FWHAP_IF_PROBE_REQ */
289 case 4: dissect_probe(tvb, offset, ntree); /* FWHAP_IF_PROBE_RPLY */
292 case 6: dissect_conf_reply(tvb, offset, ntree); /* FWHAP_IFCONF_RPLY */
294 case 7: dissect_lb_conf(tvb, offset, ntree); /* FWHAP_LB_CONF */
296 case 9: dissect_policy_change(tvb, offset, ntree); /* FWHAP_POLICY_CHANGE */
302 return tvb_length(tvb);
305 static void dissect_my_state(tvbuff_t * tvb, int offset, proto_tree * tree) {
306 struct fwha_my_state_hdr hdr;
307 struct fwhap_if_state_s if_hdr;
309 proto_item * nti = NULL;
310 proto_tree * ntree = NULL;
312 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
313 hdr.id_num = g_ntohs(hdr.id_num);
314 hdr.report_code = g_ntohs(hdr.report_code);
315 hdr.ha_mode = g_ntohs(hdr.ha_mode);
316 hdr.ha_time_unit = g_ntohs(hdr.ha_time_unit);
318 proto_tree_add_uint(tree, hf_id_num, tvb, offset, sizeof(hdr.id_num), hdr.id_num);
319 offset += sizeof(hdr.id_num);
321 proto_tree_add_text(tree, tvb, offset, sizeof(hdr.report_code), "Report Code: %s",report_code2str(hdr.report_code));
322 offset += sizeof(hdr.report_code);
324 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));
325 offset += sizeof(hdr.ha_mode);
327 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);
328 offset += sizeof(hdr.ha_time_unit);
330 rep_mode = is_report_ifs(hdr.report_code);
331 if (hdr.report_code & 1) {
333 nti = proto_tree_add_text(tree, tvb, offset, hdr.id_num * sizeof(guint8), "Machine states");
334 ntree = proto_item_add_subtree(nti, ett_cphap);
335 for(i=0; i < hdr.id_num; i++) {
336 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)));
337 offset += sizeof(guint8);
340 if (hdr.report_code & 2) {
341 /* interface information */
342 nti = proto_tree_add_text(tree, tvb, offset, sizeof(struct fwhap_if_state_s), "Interface states");
343 ntree = proto_item_add_subtree(nti, ett_cphap);
344 tvb_memcpy(tvb, (guint8 *)&if_hdr, offset, sizeof(if_hdr));
345 proto_tree_add_int(ntree, hf_in_up_num, tvb, offset, sizeof(if_hdr.in_up_num), if_hdr.in_up_num);
346 offset += sizeof(if_hdr.in_up_num);
347 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);
348 offset += sizeof(if_hdr.in_assumed_up_num);
349 proto_tree_add_int(ntree, hf_out_up_num, tvb, offset, sizeof(if_hdr.out_up_num), if_hdr.out_up_num);
350 offset += sizeof(if_hdr.out_up_num);
351 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);
352 offset += sizeof(if_hdr.out_assumed_up_num);
354 for(i=0; i < hdr.id_num; i++) {
355 proto_tree_add_text(tree, tvb, offset, sizeof(guint8), "Cluster %d: last packet seen %d time units ago", i, tvb_get_guint8(tvb, offset));
356 offset += sizeof(guint8);
362 static void dissect_lb_conf(tvbuff_t * tvb, int offset, proto_tree * tree) {
363 struct lb_conf_hdr hdr;
365 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
366 hdr.slot_num = g_ntohs(hdr.slot_num);
367 hdr.machine_num = g_ntohs(hdr.machine_num);
368 hdr.seed = g_ntohs(hdr.seed);
369 hdr.hash_list_len = g_ntohs(hdr.hash_list_len);
371 proto_tree_add_uint(tree, hf_slot_num, tvb, offset, sizeof(hdr.slot_num), hdr.slot_num);
372 offset += sizeof(hdr.slot_num);
374 proto_tree_add_int(tree, hf_machine_num, tvb, offset, sizeof(hdr.machine_num), hdr.machine_num);
375 offset += sizeof(hdr.machine_num);
377 proto_tree_add_uint(tree, hf_seed, tvb, offset, sizeof(hdr.seed), hdr.seed);
378 offset += sizeof(hdr.seed);
380 proto_tree_add_uint(tree, hf_hash_len, tvb, offset, sizeof(hdr.hash_list_len), hdr.hash_list_len);
381 offset += sizeof(hdr.hash_list_len);
385 static void dissect_policy_change(tvbuff_t * tvb, int offset, proto_tree * tree) {
388 status = tvb_get_ntohl(tvb, offset);
390 proto_tree_add_uint_format(tree, hf_status, tvb, offset, sizeof(status), status, "Status %d (%s)", status, status2str(status));
391 offset += sizeof(guint32);
394 static void dissect_probe(tvbuff_t * tvb, int offset, proto_tree * tree) {
397 ifn = tvb_get_ntohl(tvb, offset);
399 proto_tree_add_uint(tree, hf_ifn, tvb, offset, sizeof(ifn), ifn);
400 offset += sizeof(guint32);
403 static void dissect_conf_reply(tvbuff_t * tvb, int offset, proto_tree * tree) {
404 struct conf_reply_hdr hdr;
406 tvb_memcpy(tvb, (guint8 *)&hdr, offset, sizeof(hdr));
407 hdr.num_reported_ifs = g_ntohl(hdr.num_reported_ifs);
408 hdr.is_if_trusted = g_ntohs(hdr.is_if_trusted);
410 proto_tree_add_uint(tree, hf_num_reported_ifs, tvb, offset, sizeof(hdr.num_reported_ifs), hdr.num_reported_ifs);
411 offset += sizeof(hdr.num_reported_ifs);
412 proto_tree_add_ether(tree, hf_ethernet_add, tvb, offset, 6, hdr.ethernet_add);
415 proto_tree_add_boolean(tree, hdr.is_if_trusted, tvb, offset, sizeof(hdr.is_if_trusted), hdr.is_if_trusted);
416 offset += sizeof(hdr.is_if_trusted);
418 proto_tree_add_ipv4(tree, hf_ip, tvb, offset, sizeof(hdr.ip), hdr.ip);
422 int is_report_ifs(guint16 report_code) {
429 report_code2str(guint16 report_code) {
431 ret = is_report_ifs(report_code);
432 if(!(report_code & 1))
433 return "Machine information NOT present";
435 return "Interface information included";
436 return "Unknown report code!";
439 ha_magic_num2str(guint16 magic) {
440 if(magic == CPHA_MAGIC)
446 version2str(guint16 version) {
448 case 1: return "4.1";
449 case 6: return "NG Feature Pack 2";
451 case 530: return "NG Feature Pack 3";
456 opcode2str_short(guint16 opcode) {
457 if(opcode <= NUM_OPCODE_TYPES)
458 return opcode_type_str_short[opcode];
459 return opcode_type_str_short[0];
463 ha_mode2str(guint16 hamode) {
464 if(hamode <= NUM_HA_MODES)
465 return ha_mode_str[hamode];
466 return "Unknown HA mode";
470 status2str(guint16 status) {
471 if(status <= NUM_STATUS)
472 return status_str[status];
473 return status_str[0];
477 state2str(guint8 state) {
478 if(state <= NUM_STATES)
479 return state_str[state];
485 opcode2str_long(guint16 opcode) {
486 if(opcode <= NUM_OPCODE_TYPES)
487 return opcode_type_str_long[opcode];
488 return opcode_type_str_long[0];
492 proto_register_cpha(void)
494 static hf_register_info hf[] = {
496 { "CPHAP Magic Number", "cphap.magic_number", FT_UINT16, BASE_HEX, NULL, 0x0, "CPHAP Magic Number", HFILL}},
497 { &hf_cpha_protocol_ver,
498 { "Protocol Version", "cphap.version", FT_UINT16, BASE_DEC, NULL, 0x0, "CPHAP Version", HFILL}},
499 { &hf_cluster_number,
500 { "Cluster Number", "cphap.cluster_number", FT_UINT16, BASE_DEC, NULL, 0x0, "Cluster Number", HFILL}},
502 { "OpCode", "cphap.opcode", FT_UINT16, BASE_DEC, NULL, 0x0, "OpCode", HFILL}},
504 { "Source Interface", "cphap.src_if", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Interface", HFILL}},
506 { "Random ID", "cphap.random_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Random ID", HFILL}},
507 { &hf_src_machine_id,
508 { "Source Machine ID", "cphap.src_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Machine ID", HFILL}},
509 { &hf_dst_machine_id,
510 { "Destination Machine ID", "cphap.dst_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Machine ID", HFILL}},
512 { "Policy ID", "cphap.policy_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Policy ID", HFILL}},
514 { "Filler", "cphap.filler", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL}},
516 { "Number of IDs reported", "cphap.id_num", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of IDs reported", HFILL}},
518 { "Report code", "cphap.id_num", FT_UINT16, BASE_BIN, NULL, 0x0, "Report Code", HFILL}},
520 { "HA mode", "cphap.ha_mode", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Mode", HFILL}},
522 { "HA Time unit (ms)", "cphap.ha_time_unit", FT_UINT16, BASE_DEC, NULL, 0x0, "HA Time unit", HFILL}},
523 { &hf_num_reported_ifs,
524 { "Reported Interfaces", "cphap.reported_ifs", FT_UINT32, BASE_DEC, NULL, 0x0, "Reported Interfaces", HFILL}},
526 { "Ethernet Address", "cphap.ethernet_addr", FT_ETHER, BASE_HEX, NULL, 0x0, "Ethernet Address", HFILL}},
528 { "Interface Trusted", "cphap.if_trusted", FT_BOOLEAN, BASE_DEC, NULL, 0x0, "Interface Trusted", HFILL}},
530 { "IP Address", "cphap.ip", FT_IPv4, BASE_DEC, NULL, 0x0, "IP Address", HFILL}},
532 { "Slot Number", "cphap.slot_num", FT_INT16, BASE_DEC, NULL, 0x0, "Slot Number", HFILL}},
534 { "Machine Number", "cphap.machine_num", FT_INT16, BASE_DEC, NULL, 0x0, "Machine Number", HFILL}},
536 { "Seed", "cphap.seed", FT_UINT32, BASE_DEC, NULL, 0x0, "Seed", HFILL}},
538 { "Hash list length", "cphap.hash_len", FT_INT32, BASE_DEC, NULL, 0x0, "Hash list length", HFILL}},
540 { "Interfaces up in the Inbound", "cphap.in_up", FT_INT8, BASE_DEC, NULL, 0x0, "Interfaces up in the Inbound", HFILL}},
541 { &hf_in_assumed_up_num,
542 { "Interfaces assumed up in the Inbound", "cphap.in_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
544 { "Interfaces up in the Outbound", "cphap.out_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
545 { &hf_out_assumed_up_num,
546 { "Interfaces assumed up in the Outbound", "cphap.out_assume_up", FT_INT8, BASE_DEC, NULL, 0x0, "", HFILL}},
548 { "Status", "cphap.status", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
550 { "Interface Number", "cpha.ifn", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL}},
552 static gint *ett[] = {
556 proto_cphap = proto_register_protocol("Check Point High Availability Protocol",
558 proto_register_field_array(proto_cphap, hf, array_length(hf));
559 proto_register_subtree_array(ett, array_length(ett));
563 proto_reg_handoff_cpha(void)
565 dissector_handle_t cpha_handle;
567 cpha_handle = new_create_dissector_handle(dissect_cpha, proto_cphap);
568 dissector_add("udp.port", UDP_PORT_CPHA, cpha_handle);