epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-ath.c
blob3dfc91d0be40e73daa52930122b5a04d017e565d
1 /* packet-ath.c
2 * Routines for ATH (Apache Tribes Heartbeat) dissection
3 * Copyright 2015, Eugene Adell <eugene.adell@d2-si.eu>
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
12 #include "config.h"
14 #include <epan/packet.h>
15 #include <epan/expert.h>
16 #include <epan/to_str.h>
18 void proto_register_ath(void);
19 void proto_reg_handoff_ath(void);
21 static dissector_handle_t ath_handle;
23 /* IMPORTANT IMPLEMENTATION NOTES
25 * You need to be looking at:
27 * http://tomcat.apache.org/tomcat-8.0-doc/cluster-howto.html
29 * Tomcat clustering uses two protocols :
31 * - UDP heartbeats to maintain a status of all the members of the cluster
33 * - TCP RMI to send data across members
35 * This dissector is about UDP heartbeats, that we will call ATH, standing for
36 * Apache Tribes Heartbeat. Tribes is the name of the clustering libraries
37 * package of Apache Tomcat.
41 #define ATH_PORT 45564 /* Not IANA registered */
43 static int proto_ath;
45 static int hf_ath_begin;
46 static int hf_ath_padding;
47 static int hf_ath_length;
48 static int hf_ath_alive;
49 static int hf_ath_port;
50 static int hf_ath_sport;
51 static int hf_ath_uport;
52 static int hf_ath_hlen;
53 static int hf_ath_ipv4;
54 static int hf_ath_ipv6;
55 static int hf_ath_clen;
56 static int hf_ath_comm;
57 static int hf_ath_dlen;
58 static int hf_ath_domain;
59 static int hf_ath_unique;
60 static int hf_ath_plen;
61 static int hf_ath_payload;
62 static int hf_ath_end;
64 static int ett_ath;
66 static expert_field ei_ath_hlen_invalid;
67 static expert_field ei_ath_hmark_invalid;
69 static bool
70 test_ath(tvbuff_t *tvb)
72 /* Apache Tribes packets start with "TRIBES-B" in ASCII.
73 * tvb_strneql returns -1 if there aren't enough bytes.
75 if (tvb_strneql(tvb, 0, "TRIBES-B", 8) != 0) {
76 return false;
79 return true;
82 static int
83 dissect_ath(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
85 int offset = 0;
87 /* various lengths as reported in the packet itself */
88 uint8_t hlen = 0;
89 int32_t clen = 0;
90 int32_t dlen = 0;
91 int32_t plen = 0;
93 /* detect the Tribes (Tomcat) version */
94 int tribes_version_mark;
96 /* store the info */
97 const char *info_srcaddr = "";
98 const char *info_domain = "";
99 const char *info_command = "";
101 proto_item *ti, *hlen_item;
102 proto_tree *ath_tree;
104 if (!test_ath(tvb)) {
105 return 0;
108 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATH");
110 /* Clear out stuff in the info column */
111 col_clear(pinfo->cinfo,COL_INFO);
113 ti = proto_tree_add_item(tree, proto_ath, tvb, 0, -1, ENC_NA);
114 ath_tree = proto_item_add_subtree(ti, ett_ath);
116 /* Determine the Tribes version, which means determining the Tomcat version.
117 * There are 2 versions : one for Tomcat 6, and one for Tomcat 7/8
118 * We know that Tomcat 6 packets end with "-E" (Ox2d 0x45 or 11589 in decimal)
119 * and Tomcat 7/8 packets end with "Ox01 0x00" (256 in decimal)
120 * This is why we read these 2 last bytes of the packet
122 tribes_version_mark = tvb_get_ntohs(tvb, tvb_reported_length(tvb) - 2);
124 /* dissecting a Tomcat 6 packet
126 if (tribes_version_mark == 11589) { /* "-E" */
128 /* BEGIN
130 proto_tree_add_item(ath_tree, hf_ath_begin, tvb, offset, 8, ENC_ASCII);
131 offset += 8;
133 /* LENGTH
135 proto_tree_add_item(ath_tree, hf_ath_length, tvb, offset, 4, ENC_BIG_ENDIAN);
136 offset += 4;
138 /* ALIVE TIME
140 proto_tree_add_item(ath_tree, hf_ath_alive, tvb, offset, 8, ENC_BIG_ENDIAN);
141 offset += 8;
143 /* PORT
145 proto_tree_add_item(ath_tree, hf_ath_port, tvb, offset, 4, ENC_BIG_ENDIAN);
146 offset += 4;
148 /* SECURE PORT
150 proto_tree_add_item(ath_tree, hf_ath_sport, tvb, offset, 4, ENC_BIG_ENDIAN);
151 offset += 4;
153 /* HOST LENGTH
155 hlen_item = proto_tree_add_item(ath_tree, hf_ath_hlen, tvb, offset, 1, ENC_BIG_ENDIAN);
156 hlen = tvb_get_uint8(tvb, offset);
157 offset += 1;
159 /* HOST
161 if (hlen == 4) {
162 proto_tree_add_item(ath_tree, hf_ath_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
163 info_srcaddr = tvb_ip_to_str(pinfo->pool, tvb, offset);
164 } else if (hlen == 6) {
165 proto_tree_add_item(ath_tree, hf_ath_ipv6, tvb, offset, 6, ENC_NA);
166 info_srcaddr = tvb_ip6_to_str(pinfo->pool, tvb, offset);
167 } else {
168 expert_add_info(pinfo, hlen_item, &ei_ath_hlen_invalid);
170 offset += hlen;
172 /* COMMAND LENGTH
174 proto_tree_add_item_ret_int(ath_tree, hf_ath_clen, tvb, offset, 4, ENC_BIG_ENDIAN, &clen);
175 offset += 4;
177 /* COMMAND
179 proto_tree_add_item(ath_tree, hf_ath_comm, tvb, offset, clen, ENC_ASCII);
180 if (clen != -1)
181 info_command = tvb_get_string_enc(pinfo->pool, tvb, offset, clen, ENC_ASCII);
182 offset += clen;
184 /* DOMAIN LENGTH
186 proto_tree_add_item_ret_int(ath_tree, hf_ath_dlen, tvb, offset, 4, ENC_BIG_ENDIAN, &dlen);
187 offset += 4;
189 /* DOMAIN
191 proto_tree_add_item(ath_tree, hf_ath_domain, tvb, offset, dlen, ENC_ASCII);
192 if (dlen != 0)
193 info_domain = tvb_get_string_enc(pinfo->pool, tvb, offset, dlen, ENC_ASCII);
194 offset += dlen;
196 /* UNIQUEID
198 proto_tree_add_item(ath_tree, hf_ath_unique, tvb, offset, 16, ENC_NA);
199 offset += 16;
201 /* PAYLOAD LENGTH
203 proto_tree_add_item_ret_int(ath_tree, hf_ath_plen, tvb, offset, 4, ENC_BIG_ENDIAN, &plen);
204 offset += 4;
206 /* PAYLOAD
208 proto_tree_add_item(ath_tree, hf_ath_payload, tvb, offset, plen, ENC_ASCII);
209 offset += plen;
211 /* END
213 proto_tree_add_item(ath_tree, hf_ath_end, tvb, offset, 8, ENC_ASCII);
216 /* dissecting a Tomcat 7/8 packet
218 else if (tribes_version_mark == 256) {
220 /* BEGIN
222 proto_tree_add_item(ath_tree, hf_ath_begin, tvb, offset, 8, ENC_ASCII);
223 offset += 8;
225 proto_tree_add_item(ath_tree, hf_ath_padding, tvb, offset, 2, ENC_ASCII|ENC_NA);
226 offset += 2;
228 /* LENGTH
230 proto_tree_add_item(ath_tree, hf_ath_length, tvb, offset, 4, ENC_BIG_ENDIAN);
231 offset += 4;
233 /* ALIVE TIME
235 proto_tree_add_item(ath_tree, hf_ath_alive, tvb, offset, 8, ENC_BIG_ENDIAN);
236 offset += 8;
238 /* PORT
240 proto_tree_add_item(ath_tree, hf_ath_port, tvb, offset, 4, ENC_BIG_ENDIAN);
241 offset += 4;
243 /* SECURE PORT
245 proto_tree_add_item(ath_tree, hf_ath_sport, tvb, offset, 4, ENC_BIG_ENDIAN);
246 offset += 4;
248 /* UDP PORT, only in Tomcat 7/8
250 proto_tree_add_item(ath_tree, hf_ath_uport, tvb, offset, 4, ENC_BIG_ENDIAN);
251 offset += 4;
253 /* HOST LENGTH
255 hlen_item = proto_tree_add_item(ath_tree, hf_ath_hlen, tvb, offset, 1, ENC_BIG_ENDIAN);
256 hlen = tvb_get_uint8(tvb, offset);
257 offset += 1;
259 /* HOST
261 if (hlen == 4) {
262 proto_tree_add_item(ath_tree, hf_ath_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
263 info_srcaddr = tvb_ip_to_str(pinfo->pool, tvb, offset);
264 } else if (hlen == 6) {
265 proto_tree_add_item(ath_tree, hf_ath_ipv6, tvb, offset, 6, ENC_NA);
266 info_srcaddr = tvb_ip6_to_str(pinfo->pool, tvb, offset);
267 } else {
268 expert_add_info(pinfo, hlen_item, &ei_ath_hlen_invalid);
270 offset += hlen;
272 /* COMMAND LENGTH
274 proto_tree_add_item_ret_int(ath_tree, hf_ath_clen, tvb, offset, 4, ENC_BIG_ENDIAN, &clen);
275 offset += 4;
277 /* COMMAND
279 proto_tree_add_item(ath_tree, hf_ath_comm, tvb, offset, clen, ENC_ASCII);
280 if (clen != -1)
281 info_command = tvb_get_string_enc(pinfo->pool, tvb, offset, clen, ENC_ASCII);
282 offset += clen;
284 /* DOMAIN LENGTH
286 proto_tree_add_item_ret_int(ath_tree, hf_ath_dlen, tvb, offset, 4, ENC_BIG_ENDIAN, &dlen);
287 offset += 4;
289 /* DOMAIN
291 proto_tree_add_item(ath_tree, hf_ath_domain, tvb, offset, dlen, ENC_ASCII);
292 if (dlen != 0)
293 info_domain = tvb_get_string_enc(pinfo->pool, tvb, offset, dlen, ENC_ASCII);
294 offset += dlen;
296 /* UNIQUEID
298 proto_tree_add_item(ath_tree, hf_ath_unique, tvb, offset, 16, ENC_NA);
299 offset += 16;
301 /* PAYLOAD LENGTH
303 proto_tree_add_item_ret_int(ath_tree, hf_ath_plen, tvb, offset, 4, ENC_BIG_ENDIAN, &plen);
304 offset += 4;
306 /* PAYLOAD
308 proto_tree_add_item(ath_tree, hf_ath_payload, tvb, offset, plen, ENC_ASCII);
309 offset += plen;
311 /* END
313 proto_tree_add_item(ath_tree, hf_ath_end, tvb, offset, 8, ENC_ASCII);
315 } else {
316 proto_tree_add_expert(tree, pinfo, &ei_ath_hmark_invalid, tvb, offset, -1);
317 return tvb_captured_length(tvb);
320 /* set the INFO column, and we're done !
322 if (strcmp(info_command, "") != 0) {
323 if (strcmp(info_command, "BABY-ALEX") == 0) {
324 if (strcmp(info_domain, "") != 0) {
325 col_append_fstr(pinfo->cinfo, COL_INFO, "%s is leaving domain %s", info_srcaddr, info_domain);
326 } else {
327 col_append_fstr(pinfo->cinfo, COL_INFO, "%s is leaving default domain", info_srcaddr);
329 } else {
330 if (strcmp(info_domain, "") != 0) {
331 col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to domain %s", info_srcaddr, info_domain);
332 } else {
333 col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to default domain", info_srcaddr);
336 } else {
337 if (strcmp(info_domain, "") != 0) {
338 col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to domain %s", info_srcaddr, info_domain);
339 } else {
340 col_append_fstr(pinfo->cinfo, COL_INFO, "Heartbeat from %s to default domain", info_srcaddr);
344 return tvb_captured_length(tvb);
347 void
348 proto_register_ath(void)
351 expert_module_t* expert_ath;
353 static hf_register_info hf[] = {
354 { &hf_ath_begin,
355 { "Begin", "ath.begin", FT_STRING, BASE_NONE, NULL, 0x0, "Begin mark",
356 HFILL }
358 { &hf_ath_padding,
359 { "Padding", "ath.padding", FT_UINT16, BASE_HEX, NULL, 0x0, NULL,
360 HFILL }
362 { &hf_ath_length,
363 { "Length", "ath.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Data Length",
364 HFILL }
366 { &hf_ath_alive,
367 { "Alive Time", "ath.alive", FT_UINT64, BASE_DEC, NULL, 0x0, "Alive Time counter",
368 HFILL }
370 { &hf_ath_port,
371 { "Port", "ath.port", FT_UINT32, BASE_DEC, NULL, 0x0, "RMI Port",
372 HFILL }
374 { &hf_ath_sport,
375 { "Secure Port", "ath.sport", FT_INT32, BASE_DEC, NULL, 0x0, "RMI Secure Port",
376 HFILL }
378 { &hf_ath_uport,
379 { "UDP Port", "ath.uport", FT_INT32, BASE_DEC, NULL, 0x0, "RMI UDP Port",
380 HFILL }
382 { &hf_ath_hlen,
383 { "Host Length", "ath.hlen", FT_INT8, BASE_DEC, NULL, 0x0, "Host IP Length",
384 HFILL }
386 { &hf_ath_ipv4,
387 { "Host", "ath.ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv4 Host",
388 HFILL }
390 { &hf_ath_ipv6,
391 { "Host", "ath.ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, "IPv6 Host",
392 HFILL }
394 { &hf_ath_clen,
395 { "Command Length", "ath.clen", FT_INT32, BASE_DEC, NULL, 0x0, "Command Length for members",
396 HFILL }
398 { &hf_ath_comm,
399 { "Command", "ath.comm", FT_STRING, BASE_NONE, NULL, 0x0, "Command for members",
400 HFILL }
402 { &hf_ath_dlen,
403 { "Domain Length", "ath.dlen", FT_INT32, BASE_DEC, NULL, 0x0, "Cluster Domain Length",
404 HFILL }
406 { &hf_ath_domain,
407 { "Domain", "ath.domain", FT_STRING, BASE_NONE, NULL, 0x0, "Cluster Domain",
408 HFILL }
410 { &hf_ath_unique,
411 { "uniqueId", "ath.unique", FT_BYTES, BASE_NONE, NULL, 0x0, "UniqueID identifier",
412 HFILL }
414 { &hf_ath_plen,
415 { "Payload Length", "ath.plen", FT_INT32, BASE_DEC, NULL, 0x0, "Packet Payload Length",
416 HFILL }
418 { &hf_ath_payload,
419 { "Payload", "ath.payload", FT_STRING, BASE_NONE, NULL, 0x0, "Packet Payload",
420 HFILL }
422 { &hf_ath_end,
423 { "End", "ath.end", FT_STRING, BASE_NONE, NULL, 0x0, "End mark",
424 HFILL }
428 static ei_register_info ei[] = {
429 { &ei_ath_hlen_invalid, { "ath.hlen.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid IP length", EXPFILL }},
430 { &ei_ath_hmark_invalid, { "ath.hmark.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: not an ATH packet", EXPFILL }},
433 static int *ett[] = {
434 &ett_ath,
437 proto_ath = proto_register_protocol("Apache Tribes Heartbeat Protocol", "ATH", "ath");
438 proto_register_field_array(proto_ath, hf, array_length(hf));
439 proto_register_subtree_array(ett, array_length(ett));
440 expert_ath = expert_register_protocol(proto_ath);
441 expert_register_field_array(expert_ath, ei, array_length(ei));
443 ath_handle = register_dissector("ath", dissect_ath, proto_ath);
446 void
447 proto_reg_handoff_ath(void)
449 dissector_add_uint_with_preference("udp.port", ATH_PORT, ath_handle);
453 * Editor modelines - https://www.wireshark.org/tools/modelines.html
455 * Local variables:
456 * c-basic-offset: 2
457 * tab-width: 8
458 * indent-tabs-mode: nil
459 * End:
461 * vi: set shiftwidth=2 tabstop=8 expandtab:
462 * :indentSize=2:tabSize=8:noTabs=true: