blob: 581262f79ed37a63a468604b8161ea02a423a696 [file] [log] [blame]
Frédéric Lécaille6d889502017-11-15 14:50:19 +01001/* packet-happp.c
2 * Routines for HAProxy Peers Protocol (HAPPP) dissection
3 * Copyright 2016, Frédéric Lécaille <flecaille@haproxy.com>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#include <stdio.h>
Willy Tarreaua1bd1fa2019-03-29 17:26:33 +010025#include <inttypes.h>
Frédéric Lécaille6d889502017-11-15 14:50:19 +010026#include <inttypes.h>
27#include <arpa/inet.h>
28
29#include <config.h>
William Lallemand2be58f72020-04-25 22:03:29 +020030
Frédéric Lécaille6d889502017-11-15 14:50:19 +010031#include <epan/to_str.h>
32#include <epan/packet.h>
33#include <epan/prefs.h>
34#include <epan/conversation.h>
William Lallemand2be58f72020-04-25 22:03:29 +020035#include <epan/strutil.h>
36#include <epan/dissectors/packet-tcp.h>
37#include <epan/tvbuff.h>
38
Frédéric Lécailleaab6f7c2021-01-19 14:33:24 +010039#ifndef WITHOUT_WS_VERSION
William Lallemand2be58f72020-04-25 22:03:29 +020040#include <ws_version.h>
Frédéric Lécailleaab6f7c2021-01-19 14:33:24 +010041#endif
42
43#ifndef WIRESHARK_VERSION_MAJOR
44#define WIRESHARK_VERSION_MAJOR VERSION_MAJOR
45#endif
46#ifndef WIRESHARK_VERSION_MINOR
47#define WIRESHARK_VERSION_MINOR VERSION_MINOR
48#endif
49#ifndef WIRESHARK_VERSION_MICRO
50#define WIRESHARK_VERSION_MICRO VERSION_MICRO
51#endif
52
53#define HAPP_STR(str) #str
54#define HAPP_XSTR(str) HAPP_STR(str)
William Lallemand2be58f72020-04-25 22:03:29 +020055
56WS_DLL_PUBLIC_DEF const gchar plugin_version[] = "0.0.1";
Frédéric Lécailleaab6f7c2021-01-19 14:33:24 +010057WS_DLL_PUBLIC_DEF const gchar plugin_release[] = HAPP_XSTR(WIRESHARK_VERSION_MAJOR.WIRESHARK_VERSION_MINOR);
William Lallemand2be58f72020-04-25 22:03:29 +020058WS_DLL_PUBLIC_DEF const int plugin_want_major = WIRESHARK_VERSION_MAJOR;
59WS_DLL_PUBLIC_DEF const int plugin_want_minor = WIRESHARK_VERSION_MINOR;
60WS_DLL_PUBLIC void plugin_register(void);
61
Frédéric Lécaille6d889502017-11-15 14:50:19 +010062
63#define HAPPP_PROTOCOL "HAProxyS"
64#define HAPPP_MSG_MIN_LEN 2
65
66/* Status messages are the shortest ones (3 digits followed by a LF character) */
67#define STATUS_HANDSHAKE_SUCCEEDED "200"
68#define STATUS_TRY_AGAIN_LATER "300"
69#define STATUS_PROTOCOL_ERROR "501"
70#define STATUS_BAD_VERSION "502"
71#define STATUS_LOCAL_PEER_NAME_MISMATCH "503"
72#define STATUS_REMOTE_PEER_NAME_MISMATCH "504"
73
74#include <stdio.h>
75#include <ctype.h>
76#include <stdarg.h>
77
Frédéric Lécaille6d889502017-11-15 14:50:19 +010078
79#ifdef DEBUG
80static unsigned char dbg_buf[16 << 10];
81
82__attribute__((format (printf, 3, 4)))
83void hexdump(const unsigned char *buf, size_t buflen, const char *title_fmt, ...)
84{
85 size_t i;
86 va_list ap;
87 const unsigned char *p;
88 char str_buf[2 + 1 + 16 + 1 + 1];
89
90 va_start(ap, title_fmt);
91 vfprintf(stderr, title_fmt, ap);
92 va_end(ap);
93
94 p = buf;
95 str_buf[0] = str_buf[1] = ' ';
96 str_buf[2] = '|';
97
98 for (i = 0; i < buflen; i++) {
99 if (!(i & 0xf))
100 fprintf(stderr, "%08X: ", i);
101 fprintf(stderr, " %02x", *p);
102 if (isalnum(*p))
103 str_buf[(i & 0xf) + 3] = *p;
104 else
105 str_buf[(i & 0xf) + 3] = '.';
106 if ((i & 0xf) == 0xf || i == buflen -1) {
107 size_t k;
108
109 for (k = 0; k < (0x10 - (i & 0xf) - 1); k++)
110 fprintf(stderr, " ");
111 str_buf[(i & 0xf) + 4] = '|';
112 str_buf[(i & 0xf) + 5 ] = '\0';
113 fprintf(stderr, "%s\n", str_buf);
114 }
115 p++;
116 }
117}
118
119void hexdump_tvb(tvbuff_t *tvb, const gint offset, size_t len)
120{
121 len = len > sizeof dbg_buf ? sizeof dbg_buf : len;
122 if (tvb_memcpy(tvb, dbg_buf, offset, len)) {
123 hexdump(dbg_buf, len, "tvb buff (%zu bytes):\n", len);
124 } else
125 fprintf(stderr, "tvb buff COPY FAILED\n");
126}
127#endif
128
129/* HAPPP message classes */
130enum {
131 PEER_MSG_CLASS_CONTROL = 0,
132 PEER_MSG_CLASS_ERROR,
133 PEER_MSG_CLASS_STICKTABLE = 0x0a,
134 PEER_MSG_CLASS_RESERVED = 0xff,
135};
136
137enum {
138 CONTROL_CLASS_INDEX,
139 ERROR_CLASS_INDEX,
140 STICK_TABLE_CLASS_INDEX,
141 RESERVED_CLASS_INDEX,
142};
143
144/* Control messages */
145enum {
146 PEER_MSG_CTRL_RESYNCREQ = 0,
147 PEER_MSG_CTRL_RESYNCFINISHED,
148 PEER_MSG_CTRL_RESYNCPARTIAL,
149 PEER_MSG_CTRL_RESYNCCONFIRM,
Frédéric Lécaille200f8fc2021-01-21 16:23:29 +0100150 PEER_MSG_CTRL_HEARTBEAT,
Frédéric Lécaille6d889502017-11-15 14:50:19 +0100151};
152
153/* Error messages */
154enum {
155 PEER_MSG_ERR_PROTOCOL = 0,
156 PEER_MSG_ERR_SIZELIMIT,
157};
158
159/* Stick table messages */
160enum {
161 PEER_MSG_STKT_UPDATE = 0x80,
162 PEER_MSG_STKT_INCUPDATE,
163 PEER_MSG_STKT_DEFINE,
164 PEER_MSG_STKT_SWITCH,
165 PEER_MSG_STKT_ACK,
166 PEER_MSG_STKT_UPDATE_TIMED,
167 PEER_MSG_STKT_INCUPDATE_TIMED,
168};
169
170/* This is the different key types of the stick tables.
171 * Same definitions as in HAProxy sources.
172 */
173enum {
174 SMP_T_ANY, /* any type */
175 SMP_T_BOOL, /* boolean */
176 SMP_T_SINT, /* signed 64bits integer type */
177 SMP_T_ADDR, /* ipv4 or ipv6, only used for input type compatibility */
178 SMP_T_IPV4, /* ipv4 type */
179 SMP_T_IPV6, /* ipv6 type */
180 SMP_T_STR, /* char string type */
181 SMP_T_BIN, /* buffer type */
182 SMP_T_METH, /* contain method */
183 SMP_TYPES /* number of types, must always be last */
184};
185
186/* The types of data we can store in a stick table.
Ilya Shipitsince7b00f2020-03-23 22:28:40 +0500187 * Same definitions as in HAProxy sources.
Frédéric Lécaille6d889502017-11-15 14:50:19 +0100188 */
189enum {
190 STKT_DT_SERVER_ID, /* the server ID to use with this stream if > 0 */
191 STKT_DT_GPT0, /* General Purpose Flag 0. */
192 STKT_DT_GPC0, /* General Purpose Counter 0 (unsigned 32-bit integer) */
193 STKT_DT_GPC0_RATE, /* General Purpose Counter 0's event rate */
194 STKT_DT_CONN_CNT, /* cumulated number of connections */
195 STKT_DT_CONN_RATE, /* incoming connection rate */
196 STKT_DT_CONN_CUR, /* concurrent number of connections */
197 STKT_DT_SESS_CNT, /* cumulated number of sessions (accepted connections) */
198 STKT_DT_SESS_RATE, /* accepted sessions rate */
199 STKT_DT_HTTP_REQ_CNT, /* cumulated number of incoming HTTP requests */
200 STKT_DT_HTTP_REQ_RATE, /* incoming HTTP request rate */
201 STKT_DT_HTTP_ERR_CNT, /* cumulated number of HTTP requests errors (4xx) */
202 STKT_DT_HTTP_ERR_RATE, /* HTTP request error rate */
203 STKT_DT_BYTES_IN_CNT, /* cumulated bytes count from client to servers */
204 STKT_DT_BYTES_IN_RATE, /* bytes rate from client to servers */
205 STKT_DT_BYTES_OUT_CNT, /* cumulated bytes count from servers to client */
206 STKT_DT_BYTES_OUT_RATE, /* bytes rate from servers to client */
207 STKT_STATIC_DATA_TYPES, /* number of types above */
208};
209
210/* The types of data in stick stored in stick tables.
211 * Same definitions as in HAProxy sources.
212 */
213enum {
214 STD_T_SINT = 0, /* signed int */
215 STD_T_UINT, /* unsigned int */
216 STD_T_ULL, /* unsigned long long */
Willy Tarreaufa1258f2021-04-10 23:00:53 +0200217 STD_T_FRQP, /* freq_ctr structure made of three unsigned int */
Frédéric Lécaille6d889502017-11-15 14:50:19 +0100218};
219
220/* Prototypes */
221void proto_reg_handoff_happp(void);
222void proto_register_happp(void);
223
224/* Initialize the protocol and registered fields */
225static int proto_happp = -1;
226static int hf_happp_fake = -1;
227static int hf_happp_version = -1;
228static int hf_happp_remotepeerid = -1;
229static int hf_happp_localpeerid = -1;
230static int hf_happp_processpid = -1;
231static int hf_happp_relativepid = -1;
232static int hf_happp_status = -1;
233static int hf_happp_msg = -1;
234static int hf_happp_msg_class = -1;
235static int hf_happp_msg_type = -1;
236static int hf_happp_msg_len = -1;
237static int hf_happp_stkt_def_id = -1;
238static int hf_happp_stkt_def_name_len = -1;
239static int hf_happp_stkt_def_name_value = -1;
240static int hf_happp_stkt_def_key_type = -1;
241static int hf_happp_stkt_def_key_len = -1;
242static int hf_happp_stkt_def_data_types = -1;
243static int hf_happp_stkt_updt_update_id = -1;
244static int hf_happp_stkt_updt_expire = -1;
245static int hf_happp_stkt_updt_key_len = -1;
246static int hf_happp_stkt_updt_key_ipv4_value = -1;
247static int hf_happp_stkt_updt_key_str_value = -1;
248static int hf_happp_stkt_updt_key_int_value = -1;
249static int hf_happp_stkt_updt_key_bytes_value = -1;
250static int hf_happp_stkt_updt_data_server_id = -1;
251static int hf_happp_stkt_updt_data_gpt0 = -1;
252static int hf_happp_stkt_updt_data_gpc0 = -1;
253static int hf_happp_stkt_updt_data_gpc0_rate_curr_tick = -1;
254static int hf_happp_stkt_updt_data_gpc0_rate_curr_ctr = -1;
255static int hf_happp_stkt_updt_data_gpc0_rate_prev_ctr = -1;
256static int hf_happp_stkt_updt_data_conn_cnt = -1;
257static int hf_happp_stkt_updt_data_conn_rate_curr_tick = -1;
258static int hf_happp_stkt_updt_data_conn_rate_curr_ctr = -1;
259static int hf_happp_stkt_updt_data_conn_rate_prev_ctr = -1;
260static int hf_happp_stkt_updt_data_conn_cur = -1;
261static int hf_happp_stkt_updt_data_sess_cnt = -1;
262static int hf_happp_stkt_updt_data_sess_rate_curr_tick = -1;
263static int hf_happp_stkt_updt_data_sess_rate_curr_ctr = -1;
264static int hf_happp_stkt_updt_data_sess_rate_prev_ctr = -1;
265static int hf_happp_stkt_updt_data_http_req_cnt = -1;
266static int hf_happp_stkt_updt_data_http_req_rate_curr_tick = -1;
267static int hf_happp_stkt_updt_data_http_req_rate_curr_ctr = -1;
268static int hf_happp_stkt_updt_data_http_req_rate_prev_ctr= -1;
269static int hf_happp_stkt_updt_data_http_err_cnt = -1;
270static int hf_happp_stkt_updt_data_http_err_rate_curr_tick = -1;
271static int hf_happp_stkt_updt_data_http_err_rate_curr_ctr = -1;
272static int hf_happp_stkt_updt_data_http_err_rate_prev_ctr = -1;
273static int hf_happp_stkt_updt_data_bytes_in_cnt = -1;
274static int hf_happp_stkt_updt_data_bytes_in_rate_curr_tick = -1;
275static int hf_happp_stkt_updt_data_bytes_in_rate_curr_ctr = -1;
276static int hf_happp_stkt_updt_data_bytes_in_rate_prev_ctr = -1;
277static int hf_happp_stkt_updt_data_bytes_out_cnt = -1;
278static int hf_happp_stkt_updt_data_bytes_out_rate_curr_tick = -1;
279static int hf_happp_stkt_updt_data_bytes_out_rate_curr_ctr = -1;
280static int hf_happp_stkt_updt_data_bytes_out_rate_prev_ctr = -1;
281static int hf_happp_stkt_updt_ack_table_id = -1;
282static int hf_happp_stkt_updt_ack_update_id = -1;
283
284struct happp_cv_data_t {
285 /* Same thing for the type of the the stick table keys */
286 uint64_t stkt_key_type;
287
288 /* Same thing for the length of the stick table keys.
289 * Note that this is true only for key types different of SMT_T_STR (strings)
290 * and SMT_T_SINT (signed ints).
291 */
292 uint64_t stkt_key_len;
293
294 /* Same thing for the types of the stick table data */
295 uint64_t stkt_data_types;
296 void *data;
297};
298
299struct hf_stkt_data_type {
300 const char *name;
301 unsigned int type;
302 int *hf_ids[3];
303 size_t hf_ids_len;
304};
305
306struct hf_stkt_data_type hf_stkt_data_types[] = {
307 [STKT_DT_SERVER_ID] = {
308 .name = "server_id",
309 .type = STD_T_SINT,
310 .hf_ids = {
311 &hf_happp_stkt_updt_data_server_id,
312 },
313 .hf_ids_len = 1,
314 },
315 [STKT_DT_GPT0] = {
316 .name = "gpt0",
317 .type = STD_T_UINT,
318 .hf_ids = {
319 &hf_happp_stkt_updt_data_gpt0,
320 },
321 .hf_ids_len = 1,
322 },
323 [STKT_DT_GPC0] = {
324 .name = "gpc0",
325 .type = STD_T_UINT,
326 .hf_ids = {
327 &hf_happp_stkt_updt_data_gpc0,
328 },
329 .hf_ids_len = 1,
330 },
331 [STKT_DT_GPC0_RATE] = {
332 .name = "gpc0_rate",
333 .type = STD_T_FRQP,
334 .hf_ids = {
335 &hf_happp_stkt_updt_data_gpc0_rate_curr_tick,
336 &hf_happp_stkt_updt_data_gpc0_rate_curr_ctr,
337 &hf_happp_stkt_updt_data_gpc0_rate_prev_ctr,
338 },
339 .hf_ids_len = 3,
340 },
341 [STKT_DT_CONN_CNT] = {
342 .name = "conn_cnt",
343 .type = STD_T_UINT,
344 .hf_ids = {
345 &hf_happp_stkt_updt_data_conn_cnt,
346 },
347 .hf_ids_len = 1,
348 },
349 [STKT_DT_CONN_RATE] = {
350 .name = "conn_rate",
351 .type = STD_T_FRQP,
352 .hf_ids = {
353 &hf_happp_stkt_updt_data_conn_rate_curr_tick,
354 &hf_happp_stkt_updt_data_conn_rate_curr_ctr,
355 &hf_happp_stkt_updt_data_conn_rate_prev_ctr,
356 },
357 .hf_ids_len = 3,
358 },
359 [STKT_DT_CONN_CUR] = {
360 .name = "conn_cur",
361 .type = STD_T_UINT,
362 .hf_ids = {
363 &hf_happp_stkt_updt_data_conn_cur,
364 },
365 .hf_ids_len = 1,
366 },
367 [STKT_DT_SESS_CNT] = {
368 .name = "sess_cnt",
369 .type = STD_T_UINT,
370 .hf_ids = {
371 &hf_happp_stkt_updt_data_sess_cnt,
372 },
373 .hf_ids_len = 1,
374 },
375 [STKT_DT_SESS_RATE] = {
376 .name = "sess_rate",
377 .type = STD_T_FRQP,
378 .hf_ids = {
379 &hf_happp_stkt_updt_data_sess_rate_curr_tick,
380 &hf_happp_stkt_updt_data_sess_rate_curr_ctr,
381 &hf_happp_stkt_updt_data_sess_rate_prev_ctr,
382 },
383 .hf_ids_len = 3,
384 },
385 [STKT_DT_HTTP_REQ_CNT] = {
386 .name = "http_req_cnt",
387 .type = STD_T_UINT,
388 .hf_ids = {
389 &hf_happp_stkt_updt_data_http_req_cnt,
390 },
391 .hf_ids_len = 1,
392 },
393 [STKT_DT_HTTP_REQ_RATE] = {
394 .name = "http_req_rate",
395 .type = STD_T_FRQP,
396 .hf_ids = {
397 &hf_happp_stkt_updt_data_http_req_rate_curr_tick,
398 &hf_happp_stkt_updt_data_http_req_rate_curr_ctr,
399 &hf_happp_stkt_updt_data_http_req_rate_prev_ctr,
400 },
401 .hf_ids_len = 3,
402 },
403 [STKT_DT_HTTP_ERR_CNT] = {
404 .name = "http_err_cnt",
405 .type = STD_T_UINT,
406 .hf_ids = {
407 &hf_happp_stkt_updt_data_http_err_cnt,
408 },
409 .hf_ids_len = 1,
410 },
411 [STKT_DT_HTTP_ERR_RATE] = {
412 .name = "http_err_rate",
413 .type = STD_T_FRQP,
414 .hf_ids = {
415 &hf_happp_stkt_updt_data_http_err_rate_curr_tick,
416 &hf_happp_stkt_updt_data_http_err_rate_curr_ctr,
417 &hf_happp_stkt_updt_data_http_err_rate_prev_ctr,
418 },
419 .hf_ids_len = 3,
420 },
421 [STKT_DT_BYTES_IN_CNT] = {
422 .name = "bytes_in_cnt",
423 .type = STD_T_ULL,
424 .hf_ids = {
425 &hf_happp_stkt_updt_data_bytes_in_cnt,
426 },
427 .hf_ids_len = 1,
428 },
429 [STKT_DT_BYTES_IN_RATE] = {
430 .name = "bytes_in_rate",
431 .type = STD_T_FRQP,
432 .hf_ids = {
433 &hf_happp_stkt_updt_data_bytes_in_rate_curr_tick,
434 &hf_happp_stkt_updt_data_bytes_in_rate_curr_ctr,
435 &hf_happp_stkt_updt_data_bytes_in_rate_prev_ctr,
436 },
437 .hf_ids_len = 3,
438 },
439 [STKT_DT_BYTES_OUT_CNT] = {
440 .name = "bytes_out_cnt",
441 .type = STD_T_ULL,
442 .hf_ids = {
443 &hf_happp_stkt_updt_data_bytes_out_cnt,
444 },
445 .hf_ids_len = 1,
446 },
447 [STKT_DT_BYTES_OUT_RATE] = {
448 .name = "bytes_out_rate",
449 .type = STD_T_FRQP,
450 .hf_ids = {
451 &hf_happp_stkt_updt_data_bytes_out_rate_curr_tick,
452 &hf_happp_stkt_updt_data_bytes_out_rate_curr_ctr,
453 &hf_happp_stkt_updt_data_bytes_out_rate_prev_ctr,
454 },
455 .hf_ids_len = 3,
456 },
457};
458
459
460/* Initialize the subtree pointers */
461static gint ett_happp = -1;
462static gint ett_happp_msg = -1;
463
464static dissector_handle_t happp_tcp_handle;
465
466static const char *control_msg_type_str_from_byte(guint8 c);
467static const char *error_msg_type_str_from_byte(guint8 c);
468static const char *stkt_msg_type_str_from_byte(guint8 c);
469
470struct class_def_t {
471 const char *class_str;
472 const char *col_info_str;
473 const char *(*msg_type_str_func)(guint8 c);
474 unsigned int count;
475};
476
477static struct class_def_t class_def_tab[] = {
478 [CONTROL_CLASS_INDEX] = {
479 .class_str = "Control Class Message",
480 .col_info_str = "Ctl",
481 .msg_type_str_func = control_msg_type_str_from_byte,
482 },
483 [ERROR_CLASS_INDEX] = {
484 .class_str = "Error Class Message",
485 .col_info_str = "Err",
486 .msg_type_str_func = error_msg_type_str_from_byte,
487 },
488 [STICK_TABLE_CLASS_INDEX] = {
489 .class_str = "Stick Table Class Message",
490 .col_info_str = "Stkt",
491 .msg_type_str_func = stkt_msg_type_str_from_byte,
492 },
493 [RESERVED_CLASS_INDEX] = {
494 .class_str = "Reserved Class Message",
495 .col_info_str = "Res",
496 }
497};
498
499static int control_class_index_from_byte(guint8 c)
500{
501 switch (c) {
502 case PEER_MSG_CLASS_CONTROL:
503 return CONTROL_CLASS_INDEX;
504 case PEER_MSG_CLASS_ERROR:
505 return ERROR_CLASS_INDEX;
506 case PEER_MSG_CLASS_STICKTABLE:
507 return STICK_TABLE_CLASS_INDEX;
508 case PEER_MSG_CLASS_RESERVED:
509 return RESERVED_CLASS_INDEX;
510 default:
511 return -1;
512 };
513}
514
515static const char *class_str_from_byte(guint8 c)
516{
517 int class_idx;
518
519 class_idx = control_class_index_from_byte(c);
520 if (class_idx == -1)
521 return "N/A";
522
523 return class_def_tab[class_idx].class_str;
524}
525
526static const char *control_msg_type_str_from_byte(guint8 c)
527{
528 switch (c) {
529 case PEER_MSG_CTRL_RESYNCREQ:
530 return "resync. request";
531 case PEER_MSG_CTRL_RESYNCFINISHED:
532 return "resync. finished";
533 case PEER_MSG_CTRL_RESYNCPARTIAL:
534 return "resync. partial";
535 case PEER_MSG_CTRL_RESYNCCONFIRM:
536 return "resync. confirm";
Frédéric Lécaille200f8fc2021-01-21 16:23:29 +0100537 case PEER_MSG_CTRL_HEARTBEAT:
538 return "heartbeat";
Frédéric Lécaille6d889502017-11-15 14:50:19 +0100539 default:
540 return "Unknown";
541 }
542}
543
544static const char *stkt_msg_type_str_from_byte(guint8 c)
545{
546 switch (c) {
547 case PEER_MSG_STKT_UPDATE:
548 return "update";
549 case PEER_MSG_STKT_INCUPDATE:
550 return "inc. update";
551 case PEER_MSG_STKT_DEFINE:
552 return "definition";
553 case PEER_MSG_STKT_SWITCH:
554 return "switch";
555 case PEER_MSG_STKT_ACK:
556 return "ack";
557 case PEER_MSG_STKT_UPDATE_TIMED:
558 return "update (with expiration)";
559 case PEER_MSG_STKT_INCUPDATE_TIMED:
560 return "inc. update (with expiration)";
561 default:
562 return "Unknown";
563 }
564}
565
566static const char *error_msg_type_str_from_byte(guint8 c)
567{
568 switch (c) {
569 case PEER_MSG_ERR_PROTOCOL:
570 return "protocol error";
571 case PEER_MSG_ERR_SIZELIMIT:
572 return "limit size error";
573 default:
574 return "Unknown";
575 }
576}
577
578#define MAX_ENC_LEN 10
579static uint64_t intdecode(unsigned char **str, size_t len) {
580 int i = 0;
581 uint64_t ret;
582
583 if (len < 1 || len > MAX_ENC_LEN) {
584 *str = NULL;
585 return 0;
586 }
587
588 ret = *(*str)++;
589 len--;
590 if ((ret & 0xf0) != 0xf0 || !len)
591 return ret;
592
593 do {
594 /* As shifting value may be greater than 8 (size of **str in bits),
595 * uint64_t cast is required.
596 */
597 ret += (uint64_t)**str << (4 + 7 * i++);
598 } while (len-- && (*(*str)++ & 0x80) == 0x80);
599
600 return ret;
601}
602
603static int dissect_happp_handshake_pdu(tvbuff_t *tvb, packet_info *pinfo,
604 proto_tree *happp_tree)
605{
606 int line_len, token_len;
607 gint offset = 0, next_offset;
608 const guchar *line, *line_end, *next_token;
609 size_t protocol_strlen;
610
611 line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
612 /* XXX TO DO */
613 if (line_len == -1)
614 return -1;
615
616 protocol_strlen = strlen(HAPPP_PROTOCOL);
617
618 line = tvb_get_ptr(tvb, offset, line_len);
619 line_end = line + (next_offset - offset);
620 /* The line must contain at least HAPPP_PROTOCOL string followed by a space,
621 * then version string (at least one character) and a '\n' character.
622 */
623 if (line_len >= (int)protocol_strlen + 3 &&
624 !tvb_strncaseeql(tvb, 0, HAPPP_PROTOCOL, protocol_strlen)) {
625 /* This is an Hello message */
626 col_set_str(pinfo->cinfo, COL_INFO, "Hello message");
627
628 token_len = get_token_len(line + protocol_strlen + 1, line_end, &next_token);
629 proto_tree_add_item(happp_tree, hf_happp_version, tvb,
630 offset + protocol_strlen + 1, token_len,
631 ENC_ASCII | ENC_NA);
632
633 offset = next_offset;
634 line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
635 /* XXX TO DO */
636 if (line_len == -1)
637 return -1;
638
639 line = tvb_get_ptr(tvb, offset, line_len);
640 line_end = line + (next_offset - offset);
641 /* Get next token: remotepeerid */
642 token_len = get_token_len(line, line_end, &next_token);
643 if (!token_len)
644 return -1;
645
646 proto_tree_add_item(happp_tree, hf_happp_remotepeerid, tvb, offset,
647 token_len, ENC_ASCII | ENC_NA);
648
649 /* Retrieve next line */
650 offset = next_offset;
651 line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
652 /* XXX TO DO */
653 if (line_len == -1)
654 return -1;
655
656 line = tvb_get_ptr(tvb, offset, line_len);
657 line_end = line + (next_offset - offset);
658 /* Get next token: localpeerid */
659 token_len = get_token_len(line, line_end, &next_token);
660 if (!token_len)
661 return -1;
662
663 proto_tree_add_item(happp_tree, hf_happp_localpeerid, tvb, offset,
664 token_len, ENC_ASCII | ENC_NA);
665 offset += next_token - line;
666 line = next_token;
667
668 /* Get next token: processpid */
669 token_len = get_token_len(line, line_end, &next_token);
670 if (!token_len)
671 return -1;
672
673 proto_tree_add_item(happp_tree, hf_happp_processpid, tvb, offset,
674 token_len, ENC_ASCII | ENC_NA);
675 offset += next_token - line;
676 line = next_token;
677
678 /* Get next token: relativepid */
679 token_len = get_token_len(line, line_end, &next_token);
680 if (!token_len)
681 return -1;
682
683 proto_tree_add_item(happp_tree, hf_happp_relativepid, tvb, offset,
684 token_len, ENC_ASCII | ENC_NA);
685 offset += next_token - line;
686 line = next_token;
687
688 }
689 else if (line_len == 3) {
690 col_set_str(pinfo->cinfo, COL_INFO, "Status message");
691 token_len = get_token_len(line, line_end, &next_token);
692 if (!token_len)
693 return -1;
694
695 proto_tree_add_item(happp_tree, hf_happp_status, tvb, offset,
696 token_len, ENC_ASCII | ENC_NA);
697 }
698
699 return tvb_captured_length(tvb);
700}
701
702/* Reset to zero all statistics counters of class_def_array */
703static void init_class_def_tab(struct class_def_t *class_def_array, size_t size)
704{
705 size_t i;
706
707 for (i = 0; i < size; i++)
708 class_def_array[i].count = 0;
709}
710
711/* Add statistics counting information about HAPPP message classes to
712 * info column (numbers of messages found in an HAPPP PDU by class).
713 */
714static inline void col_info_append_class(packet_info *pinfo, int class_index,
715 int *first_class)
716{
717 if (!class_def_tab[class_index].count)
718 return;
719
720 col_append_fstr(pinfo->cinfo, COL_INFO, "%s%s=%u",
721 *first_class ? "" : " ",
722 class_def_tab[class_index].col_info_str,
723 class_def_tab[class_index].count);
724 class_def_tab[class_index].count = 0;
725 *first_class = 0;
726}
727
728
729static int intdecode_from_tvbuff(tvbuff_t *tvb, uint64_t *dec_val,
730 guint *offset, guint total)
731{
732 unsigned char *p, enc_buf[MAX_ENC_LEN];
733 size_t max_enc_buf_len, left;
734
735 left = total - *offset;
736 max_enc_buf_len = left < sizeof enc_buf ? left : sizeof enc_buf;
737 if (!tvb_memcpy(tvb, enc_buf, *offset, max_enc_buf_len))
738 return -1;
739
740 p = enc_buf;
741 *dec_val = intdecode(&p, max_enc_buf_len);
742 if (!p)
743 return -1;
744
745 *offset += p - enc_buf;
746
747 return 0;
748}
749
750static int add_enc_field_to_happp_tree(int field_id, proto_tree *tree, tvbuff_t *tvb,
751 guint *offset, guint total, uint64_t *val)
752{
753 uint64_t dec_val;
754 size_t dec_val_len;
755 guint saved_offset;
756
757 saved_offset = *offset;
758 if (intdecode_from_tvbuff(tvb, &dec_val, offset, total) < 0)
759 return -1;
760
761 dec_val_len = *offset - saved_offset;
762 proto_tree_add_uint64_format_value(tree, field_id, tvb, saved_offset,
763 dec_val_len, dec_val, "%" PRIu64, dec_val);
764
765 if (val)
766 *val = dec_val;
767
768 return 0;
769}
770
771static int add_int_field_to_happp_tree(int field_id,
772 tvbuff_t *tvb, proto_tree *tree,
773 guint *offset, guint total _U_)
774{
775 uint32_t val;
776
777 if (!tvb_memcpy(tvb, &val, *offset, sizeof val))
778 return -1;
779
780 val = ntohl(val);
781 proto_tree_add_int_format_value(tree, field_id, tvb, *offset,
782 sizeof val, val, "%" PRId32, val);
783 *offset += sizeof val;
784
785 return 0;
786}
787
788static void dissect_happp_stkt_define_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
789 proto_tree *tree, guint offset, guint total)
790{
791 uint64_t dec_val;
792 uint64_t stkt_key_type;
793 uint64_t stkt_key_len;
794 uint64_t stkt_data_types;
795 struct happp_cv_data_t *happp_cv_data;
796 conversation_t *cv;
797
798 if (add_enc_field_to_happp_tree(hf_happp_stkt_def_id, tree,
799 tvb, &offset, total, NULL) < 0 ||
800 add_enc_field_to_happp_tree(hf_happp_stkt_def_name_len, tree,
801 tvb, &offset, total, &dec_val) < 0)
802 return;
803
804 /* Add the stick table name to HAPPP proto tree */
805 proto_tree_add_item(tree, hf_happp_stkt_def_name_value, tvb, offset, dec_val,
806 ENC_ASCII | ENC_NA);
807 offset += dec_val;
808
809 if (add_enc_field_to_happp_tree(hf_happp_stkt_def_key_type, tree,
810 tvb, &offset, total, &stkt_key_type) < 0 ||
811 add_enc_field_to_happp_tree(hf_happp_stkt_def_key_len, tree,
812 tvb, &offset, total, &stkt_key_len) < 0 ||
813 add_enc_field_to_happp_tree(hf_happp_stkt_def_data_types, tree,
814 tvb, &offset, total, &stkt_data_types) < 0)
815 return;
816
817 cv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
818 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
819 if (!cv)
820 return;
821
822 /*
Joseph Herlantbd0f83f2018-11-09 19:00:24 -0800823 * According to the documentation, it is not our responsibility
Frédéric Lécaille6d889502017-11-15 14:50:19 +0100824 * to free this allocated memory.
825 */
826 happp_cv_data = (struct happp_cv_data_t *)wmem_alloc(wmem_file_scope(),
827 sizeof *happp_cv_data);
828 if (!happp_cv_data)
829 return;
830
831 happp_cv_data->stkt_key_type = stkt_key_type;
832 happp_cv_data->stkt_key_len = stkt_key_len;
833 happp_cv_data->stkt_data_types = stkt_data_types;
834
835 conversation_add_proto_data(cv, proto_happp, happp_cv_data);
836}
837
838static void dissect_happp_stkt_update_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
839 proto_tree *tree, guint offset, guint total,
840 unsigned char msg_type_byte)
841{
842 unsigned int data_type;
843 uint64_t *stkt_key_type;
844 uint64_t *stkt_key_len;
845 struct happp_cv_data_t *happp_cv_data;
846 int has_update_id, has_exp;
847 conversation_t *cv;
848
849 cv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
850 pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
851 if (!cv)
852 return;
853
854 happp_cv_data = (struct happp_cv_data_t *)conversation_get_proto_data(cv, proto_happp);
855 if (!happp_cv_data)
856 return;
857
858 has_update_id = msg_type_byte == PEER_MSG_STKT_UPDATE ||
859 msg_type_byte == PEER_MSG_STKT_UPDATE_TIMED;
860 has_exp = msg_type_byte == PEER_MSG_STKT_UPDATE_TIMED ||
861 msg_type_byte == PEER_MSG_STKT_INCUPDATE_TIMED;
862 /* Add the stick table update ID to HAPPP tree */
863 if (has_update_id &&
864 add_int_field_to_happp_tree(hf_happp_stkt_updt_update_id, tvb, tree,
865 &offset, total) < 0)
866 return;
867
868 if (has_exp &&
869 add_int_field_to_happp_tree(hf_happp_stkt_updt_expire, tvb, tree,
870 &offset, total) < 0)
871 return;
872
873
874 stkt_key_type = &happp_cv_data->stkt_key_type;
875 stkt_key_len = &happp_cv_data->stkt_key_len;
876
877 switch(*stkt_key_type) {
878 case SMP_T_STR:
879 if (add_enc_field_to_happp_tree(hf_happp_stkt_updt_key_len, tree, tvb,
880 &offset, total, stkt_key_len) < 0)
881 return;
882
883 proto_tree_add_item(tree, hf_happp_stkt_updt_key_str_value, tvb,
884 offset, *stkt_key_len, ENC_ASCII | ENC_NA);
885 offset += *stkt_key_len;
886 break;
887 case SMP_T_SINT:
888 if (add_int_field_to_happp_tree(hf_happp_stkt_updt_key_int_value, tvb, tree,
889 &offset, total) < 0)
890 return;
891
892 break;
893 case SMP_T_IPV4:
894 proto_tree_add_ipv4(tree, hf_happp_stkt_updt_key_ipv4_value,
895 tvb, offset, 4, tvb_get_ipv4(tvb, offset));
896 offset += 4;
897 break;
898 default:
899 proto_tree_add_item(tree, hf_happp_stkt_updt_key_bytes_value,
900 tvb, offset, *stkt_key_len, ENC_NA);
901 offset += *stkt_key_len;
902 break;
903 }
904
905 /* Data dissection */
906 for (data_type = 0;
907 data_type < sizeof hf_stkt_data_types / sizeof *hf_stkt_data_types;
908 data_type++) {
909 struct hf_stkt_data_type *hf_stkt_dtype;
910 size_t i;
911
912 if (!(happp_cv_data->stkt_data_types & (1 << data_type)))
913 continue;
914
915 hf_stkt_dtype = &hf_stkt_data_types[data_type];
916
917 for (i = 0; i < hf_stkt_dtype->hf_ids_len; i++)
918 if (add_enc_field_to_happp_tree(*hf_stkt_dtype->hf_ids[i], tree, tvb,
919 &offset, total, NULL) < 0)
920 return;
921 }
922}
923
924static void dissect_happp_stkt_ack_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
925 proto_tree *tree, guint offset, guint total)
926{
927 if (add_enc_field_to_happp_tree(hf_happp_stkt_updt_ack_table_id, tree, tvb,
928 &offset, total, NULL) < 0)
929 return;
930
931 if (add_int_field_to_happp_tree(hf_happp_stkt_updt_ack_update_id, tvb, tree,
932 &offset, total) < 0)
933 return;
934}
935
936static void dissect_happp_stk_msg(tvbuff_t *tvb, packet_info *pinfo _U_,
937 proto_tree *tree, guint8 msg_type_byte,
938 guint offset, guint total)
939{
940 switch (msg_type_byte) {
941 case PEER_MSG_STKT_DEFINE:
942 dissect_happp_stkt_define_msg(tvb, pinfo, tree, offset, total);
943 break;
944 case PEER_MSG_STKT_UPDATE:
945 case PEER_MSG_STKT_INCUPDATE:
946 case PEER_MSG_STKT_UPDATE_TIMED:
947 case PEER_MSG_STKT_INCUPDATE_TIMED:
948 dissect_happp_stkt_update_msg(tvb, pinfo, tree, offset, total, msg_type_byte);
949 break;
950 case PEER_MSG_STKT_ACK:
951 dissect_happp_stkt_ack_msg(tvb, pinfo, tree, offset, total);
952 break;
953 };
954
955}
956
957static void
958dissect_happp_msg(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
959 guint8 msg_class_byte, guint8 msg_type_byte,
960 guint *offset, guint total)
961{
962 unsigned char *p, enc_buf[MAX_ENC_LEN];
963 uint64_t dec_msg_len;
964 size_t max_enc_buf_len, left, dec_val_len;
965
966 left = total - *offset;
967 max_enc_buf_len = left < sizeof enc_buf ? left : sizeof enc_buf;
968 if (!tvb_memcpy(tvb, enc_buf, *offset, max_enc_buf_len))
969 return;
970
971 p = enc_buf;
972 dec_msg_len = intdecode(&p, max_enc_buf_len);
973 if (!p)
974 return;
975
976 dec_val_len = p - enc_buf;
977 proto_tree_add_uint64_format_value(tree, hf_happp_msg_len,
978 tvb, *offset, dec_val_len, dec_msg_len,
979 "%" PRIu64, dec_msg_len);
980 *offset += dec_val_len;
981
982 switch (msg_class_byte) {
983 case PEER_MSG_CLASS_STICKTABLE:
984 dissect_happp_stk_msg(tvb, pinfo, tree, msg_type_byte, *offset, total);
985 break;
986 }
987
988 *offset += dec_msg_len;
989}
990
991/* Code to actually dissect the packets */
992static int
993dissect_happp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
994{
995 /* Set up structures needed to add the protocol subtree and manage it */
996 proto_item *item;
997 proto_tree *happp_tree;
998 /* Other misc. local variables. */
999 guint total, offset;
1000 int first_message, first_class, curr_class, prev_class;
1001 guint8 first_byte;
1002 size_t sizeof_class_def_tab;
1003
1004 offset = 0;
1005 first_message = first_class = 1;
1006 total = tvb_reported_length(tvb);
1007
1008 /* create display subtree for the protocol */
1009 item = proto_tree_add_item(tree, proto_happp, tvb, offset, -1, ENC_NA);
1010 happp_tree = proto_item_add_subtree(item, ett_happp);
1011
1012 /* Set the protocol column value */
1013 col_set_str(pinfo->cinfo, COL_PROTOCOL, "happp");
1014
1015 first_byte = (gchar)tvb_get_guint8(tvb, offset);
1016 if (first_byte != PEER_MSG_CLASS_CONTROL &&
1017 first_byte != PEER_MSG_CLASS_ERROR &&
1018 first_byte != PEER_MSG_CLASS_STICKTABLE &&
1019 first_byte != PEER_MSG_CLASS_RESERVED)
1020 return dissect_happp_handshake_pdu(tvb, pinfo, happp_tree);
1021
1022 /* Reset class_def_tab message class counters */
1023 sizeof_class_def_tab = sizeof class_def_tab / sizeof *class_def_tab;
1024 init_class_def_tab(class_def_tab, sizeof_class_def_tab);
1025
1026 prev_class = curr_class = -1;
1027 col_set_str(pinfo->cinfo, COL_INFO, "[");
1028 while (offset < total) {
1029 guint8 msg_class_byte, msg_type_byte;
1030 const char *(*msg_type_str_func)(guint8 c);
1031 struct class_def_t *class_def;
1032
1033 if (first_message) {
1034 msg_class_byte = first_byte;
1035 }
1036 else {
1037 msg_class_byte = tvb_get_guint8(tvb, offset);
1038 }
1039 curr_class = control_class_index_from_byte(msg_class_byte);
1040 if (curr_class == -1)
1041 return -1;
1042
1043 if (first_message) {
1044 prev_class = curr_class;
1045 first_message = 0;
1046 }
1047
1048 class_def = &class_def_tab[curr_class];
1049 class_def->count++;
1050 msg_type_str_func = class_def->msg_type_str_func;
1051
1052 /* Insert a line separator */
1053 proto_tree_add_item(happp_tree, hf_happp_fake, tvb,
1054 offset, 0,
1055 ENC_ASCII | ENC_NA);
1056 proto_tree_add_uint_format_value(happp_tree, hf_happp_msg_class,
1057 tvb, offset++, 1, msg_class_byte,
1058 "%u (%s)", msg_class_byte,
1059 class_str_from_byte(msg_class_byte));
1060 msg_type_byte = tvb_get_guint8(tvb, offset);
1061
1062 /* First byte: message class */
1063 switch (msg_class_byte) {
1064 case PEER_MSG_CLASS_CONTROL:
1065 case PEER_MSG_CLASS_ERROR:
1066 case PEER_MSG_CLASS_STICKTABLE:
1067 /* Second byte: message type in the class */
1068 proto_tree_add_uint_format_value(happp_tree, hf_happp_msg_type,
1069 tvb, offset++, 1, msg_type_byte,
1070 "%u (%s)", msg_type_byte,
1071 msg_type_str_func(msg_type_byte));
1072 break;
1073 case PEER_MSG_CLASS_RESERVED:
1074 col_append_str(pinfo->cinfo, COL_INFO, "NON IMPLEMENTED");
1075 break;
1076 }
1077 if (msg_class_byte >= PEER_MSG_CLASS_STICKTABLE)
1078 dissect_happp_msg(tvb, pinfo, happp_tree,
1079 msg_class_byte, msg_type_byte, &offset, total);
1080
1081 /* Sequentially add counting information to info column about
1082 * number of messages found by class in an HAPPP PDU.
1083 * For instance if an HAPPP PDU contains this sequence of messages:
1084 * 1 Control message - 2 Stick Table messages - 3 Control messages
1085 * column information displays: [Ctl=1 Stkt=2 Ctl=3].
1086 */
1087 if (curr_class != prev_class) {
1088 col_info_append_class(pinfo, prev_class, &first_class);
1089 col_info_append_class(pinfo, curr_class, &first_class);
1090 prev_class = curr_class;
1091 }
1092 else if (offset >= total) {
1093 /* Last message */
1094 col_info_append_class(pinfo, curr_class, &first_class);
1095 }
1096 }
1097 col_append_str(pinfo->cinfo, COL_INFO, "]");
1098
1099 return tvb_captured_length(tvb);
1100}
1101
1102static guint
1103get_happp_msg_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1104{
1105 guint ret, len, left;
1106 gint next_offset, line_len;
1107 guint8 first_byte;
1108 uint64_t dec_len;
1109 int saved_offset;
1110
1111 /* 0 means there is not enough data to get length. */
1112 ret = 0;
1113
1114 len = tvb_reported_length(tvb);
1115 left = len - offset;
1116 if (left < HAPPP_MSG_MIN_LEN)
1117 goto out;
1118
1119 saved_offset = offset;
1120 first_byte = (gchar)tvb_get_guint8(tvb, offset);
1121 if (first_byte == PEER_MSG_CLASS_CONTROL ||
1122 first_byte == PEER_MSG_CLASS_ERROR ||
1123 first_byte == PEER_MSG_CLASS_RESERVED) {
1124 ret = HAPPP_MSG_MIN_LEN;
1125 } else if (first_byte == PEER_MSG_CLASS_STICKTABLE) {
1126 int soff;
1127
1128 left -= HAPPP_MSG_MIN_LEN;
1129 offset += HAPPP_MSG_MIN_LEN;
1130 soff = offset;
1131 if (intdecode_from_tvbuff(tvb, &dec_len, &offset, len) < 0)
1132 goto out;
1133
1134 left -= offset - soff;
1135 if (left < dec_len)
1136 goto out;
1137
1138 ret = dec_len + offset - saved_offset;
1139 } else {
1140 /* hello message: add line lengths to compute this message length. */
1141 for (;;) {
1142 line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE);
1143 if (line_len == -1)
1144 break;
1145
1146 ret += line_len + 1;
1147 offset += line_len + 1;
1148 }
1149 }
1150
1151 out:
1152 return ret;
1153 }
1154
1155static int
1156dissect_happp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1157{
1158 tcp_dissect_pdus(tvb, pinfo, tree, TRUE,
1159 HAPPP_MSG_MIN_LEN, get_happp_msg_len, dissect_happp_pdu, data);
1160
1161 return tvb_captured_length(tvb);
1162}
1163
1164/* Register the protocol with Wireshark.
1165 *
1166 * This format is require because a script is used to build the C function that
1167 * calls all the protocol registration.
1168 */
1169void
1170proto_register_happp(void)
1171{
1172 /* Setup list of header fields See Section 1.5 of README.dissector for
1173 * details. */
1174 static hf_register_info hf[] = {
1175 {
1176 /* This one is used as separator between HAPPP messages */
1177 &hf_happp_fake,
1178 {
1179 ":-----------------------------------------------", "happp.fake",
1180 FT_STRING, STR_ASCII, NULL, 0, "FAKE", HFILL
1181 }
1182 },
1183 {
1184 &hf_happp_version,
1185 {
1186 "version", "happp.version",
1187 FT_STRING, STR_ASCII, NULL, 0, "version", HFILL
1188 }
1189 },
1190 {
1191 &hf_happp_remotepeerid,
1192 {
1193 "remotepeerid", "happp.remotepeerid",
1194 FT_STRING, STR_ASCII, NULL, 0, "remote peer id", HFILL
1195 }
1196 },
1197 {
1198 &hf_happp_localpeerid,
1199 {
1200 "localpeerid", "happp.localpeerid",
1201 FT_STRING, STR_ASCII, NULL, 0, "local peer id", HFILL
1202 }
1203 },
1204 {
1205 &hf_happp_processpid,
1206 {
1207 "processpid", "happp.processpid",
1208 FT_STRING, STR_ASCII, NULL, 0, "process pid", HFILL
1209 }
1210 },
1211 {
1212 &hf_happp_relativepid,
1213 {
1214 "relativepid", "happp.relativepid",
1215 FT_STRING, STR_ASCII, NULL, 0, "relative pid", HFILL
1216 }
1217 },
1218 {
1219 &hf_happp_status,
1220 {
1221 "status", "happp.status",
1222 FT_STRING, STR_ASCII, NULL, 0, "status message", HFILL
1223 }
1224 },
1225 {
1226 &hf_happp_msg,
1227 {
1228 "message", "happp.msg",
1229 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL
1230 }
1231 },
1232 {
1233 &hf_happp_msg_class,
1234 {
1235 "message class", "happp.msg.class",
1236 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL
1237 }
1238 },
1239 {
1240 &hf_happp_msg_type,
1241 {
1242 "message type", "happp.msg.type",
1243 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL
1244 }
1245 },
1246 {
1247 &hf_happp_msg_len,
1248 {
1249 "message length", "happp.msg.len",
1250 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1251 }
1252 },
1253 {
1254 &hf_happp_stkt_def_id,
1255 {
1256 " ID", "happp.msg.stkt.def.id",
1257 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1258 }
1259 },
1260 {
1261 &hf_happp_stkt_def_name_len,
1262 {
1263 " name length", "happp.msg.stkt.def.name.length",
1264 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1265 }
1266 },
1267 {
1268 &hf_happp_stkt_def_name_value,
1269 {
1270 " name", "happp.msg.stkt.def.name.value",
1271 FT_STRING, STR_ASCII, NULL, 0, NULL, HFILL
1272 }
1273 },
1274 {
1275 &hf_happp_stkt_def_key_type,
1276 {
1277 " key type", "happp.msg.stkt.def.key.type",
1278 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1279 }
1280 },
1281 {
1282 &hf_happp_stkt_def_key_len,
1283 {
1284 " key length", "happp.msg.stkt.def.key.len",
1285 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1286 }
1287 },
1288 {
1289 &hf_happp_stkt_def_data_types,
1290 {
1291 " data types", "happp.msg.stkt.def.data_types",
1292 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1293 }
1294 },
1295 {
1296 &hf_happp_stkt_updt_update_id,
1297 {
1298 " update ID", "happp.msg.stkt.updt.update_id",
1299 FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL
1300 }
1301 },
1302 {
1303 &hf_happp_stkt_updt_expire,
1304 {
1305 " expiration", "happp.msg.stkt.updt.expiration",
1306 FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL
1307 }
1308 },
1309 {
1310 &hf_happp_stkt_updt_key_len,
1311 {
1312 " key length", "happp.msg.stkt.updt.key.len",
1313 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1314 }
1315 },
1316 {
1317 &hf_happp_stkt_updt_key_str_value,
1318 {
1319 " key value", "happp.msg.stkt.updt.key.str.value",
1320 FT_STRING, STR_ASCII, NULL, 0, NULL, HFILL
1321 }
1322 },
1323 {
1324 &hf_happp_stkt_updt_key_int_value,
1325 {
1326 " key value", "happp.msg.stkt.updt.key.int.value",
1327 FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL
1328 }
1329 },
1330 {
1331 &hf_happp_stkt_updt_key_ipv4_value,
1332 {
1333 " key IPv4 value", "happp.msg.stkt.updt.key.ipv4.value",
1334 FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL
1335 }
1336 },
1337 {
1338 &hf_happp_stkt_updt_key_bytes_value,
1339 {
1340 " key value", "happp.msg.stkt.updt.key.bytes.value",
1341 FT_BYTES, 0, NULL, 0, NULL, HFILL
1342 }
1343 },
1344 {
1345 &hf_happp_stkt_updt_data_server_id,
1346 {
1347 " server_id", "happp.msg.stkt.updt.data.server_id",
1348 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1349 }
1350 },
1351 {
1352 &hf_happp_stkt_updt_data_gpt0,
1353 {
1354 " gpt0", "happp.msg.stkt.updt.data.gpt0",
1355 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1356 }
1357 },
1358 {
1359 &hf_happp_stkt_updt_data_gpc0,
1360 {
1361 " gpc0", "happp.msg.stkt.updt.data.gpc0",
1362 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1363 }
1364 },
1365 {
1366 &hf_happp_stkt_updt_data_gpc0_rate_curr_tick,
1367 {
1368 " gpc0 curr. tick",
1369 "happp.msg.stkt.updt.data.gpc0_rate.curr_tick",
1370 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1371 }
1372 },
1373 {
1374 &hf_happp_stkt_updt_data_gpc0_rate_curr_ctr,
1375 {
1376 " gpc0 curr. ctr.",
1377 "happp.msg.stkt.updt.data.gpc0_rate.curr_ctr",
1378 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1379 }
1380 },
1381 {
1382 &hf_happp_stkt_updt_data_gpc0_rate_prev_ctr,
1383 {
1384 " gpc0 prev. ctr.",
1385 "happp.msg.stkt.updt.data.gpc0_rate.prev_ctr",
1386 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1387 }
1388 },
1389 {
1390 &hf_happp_stkt_updt_data_conn_cnt,
1391 {
1392 " conn_cnt",
1393 "happp.msg.stkt.updt.data.conn_cnt",
1394 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1395 }
1396 },
1397 {
1398 &hf_happp_stkt_updt_data_conn_rate_curr_tick,
1399 {
1400 " conn_rate curr. tick",
1401 "happp.msg.stkt.updt.data.conn_rate.curr_tick",
1402 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1403 }
1404 },
1405 {
1406 &hf_happp_stkt_updt_data_conn_rate_curr_ctr,
1407 {
1408 " conn_rate curr. ctr.",
1409 "happp.msg.stkt.updt.data.conn_rate.curr_ctr",
1410 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1411 }
1412 },
1413 {
1414 &hf_happp_stkt_updt_data_conn_rate_prev_ctr,
1415 {
1416 " conn_rate prev. ctr.",
1417 "happp.msg.stkt.updt.data.conn_rate.prev_ctr",
1418 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1419 }
1420 },
1421 {
1422 &hf_happp_stkt_updt_data_conn_cur,
1423 {
1424 " conn_curr curr. tick",
1425 "happp.msg.stkt.updt.data.conn_cur",
1426 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1427 }
1428 },
1429 {
1430 &hf_happp_stkt_updt_data_sess_cnt,
1431 {
1432 " sess_cnt", "happp.msg.stkt.updt.data.sess_cnt",
1433 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1434 }
1435 },
1436 {
1437 &hf_happp_stkt_updt_data_sess_rate_curr_tick,
1438 {
1439 " sess_rate curr. tick",
1440 "happp.msg.stkt.updt.data.sess_rate.curr_tick",
1441 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1442 }
1443 },
1444 {
1445 &hf_happp_stkt_updt_data_sess_rate_curr_ctr,
1446 {
1447 " sess_rate curr. ctr.",
1448 "happp.msg.stkt.updt.data.sess_rate.curr_ctr",
1449 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1450 }
1451 },
1452 {
1453 &hf_happp_stkt_updt_data_sess_rate_prev_ctr,
1454 {
1455 " sess_rate prev. ctr.",
1456 "happp.msg.stkt.updt.data.sess_rate.prev_ctr",
1457 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1458 }
1459 },
1460 {
1461 &hf_happp_stkt_updt_data_http_req_cnt,
1462 {
1463 " http_req_cnt",
1464 "happp.msg.stkt.updt.data.http_req_cnt",
1465 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1466 }
1467 },
1468 {
1469 &hf_happp_stkt_updt_data_http_req_rate_curr_tick,
1470 {
1471 " http_req_rate curr. tick",
1472 "happp.msg.stkt.updt.data.http_req_rate.curr_tick",
1473 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1474 }
1475 },
1476 {
1477 &hf_happp_stkt_updt_data_http_req_rate_curr_ctr,
1478 {
1479 " http_req_rate curr. ctr.",
1480 "happp.msg.stkt.updt.data.http_req_rate.curr_ctr",
1481 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1482 }
1483 },
1484 {
1485 &hf_happp_stkt_updt_data_http_req_rate_prev_ctr,
1486 {
1487 " http_req_rate prev. ctr.",
1488 "happp.msg.stkt.updt.data.http_req_rate.prev_ctr",
1489 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1490 }
1491 },
1492 {
1493 &hf_happp_stkt_updt_data_http_err_cnt,
1494 {
1495 " http_err_cnt",
1496 "happp.msg.stkt.updt.data.http_err_cnt",
1497 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1498 }
1499 },
1500 {
1501 &hf_happp_stkt_updt_data_http_err_rate_curr_tick,
1502 {
1503 " http_err_rate curr. tick",
1504 "happp.msg.stkt.updt.data.http_err_rate.curr_tick",
1505 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1506 }
1507 },
1508 {
1509 &hf_happp_stkt_updt_data_http_err_rate_curr_ctr,
1510 {
1511 " http_err_rate curr. ctr.",
1512 "happp.msg.stkt.updt.data.http_err_rate.curr_ctr",
1513 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1514 }
1515 },
1516 {
1517 &hf_happp_stkt_updt_data_http_err_rate_prev_ctr,
1518 {
1519 " http_err_rate prev. ctr.",
1520 "happp.msg.stkt.updt.data.http_err_rate.prev_ctr",
1521 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1522 }
1523 },
1524 {
1525 &hf_happp_stkt_updt_data_bytes_in_cnt,
1526 {
1527 " bytes_in_cnt",
1528 "happp.msg.stkt.updt.data.bytes_in_cnt",
1529 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1530 }
1531 },
1532 {
1533 &hf_happp_stkt_updt_data_bytes_in_rate_curr_tick,
1534 {
1535 " bytes_in_rate curr. tick",
1536 "happp.msg.stkt.updt.data.bytes_in_rate.curr_tick",
1537 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1538 }
1539 },
1540 {
1541 &hf_happp_stkt_updt_data_bytes_in_rate_curr_ctr,
1542 {
1543 " bytes_in_rate curr. ctr.",
1544 "happp.msg.stkt.updt.data.bytes_in_rate.curr_ctr",
1545 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1546 }
1547 },
1548 {
1549 &hf_happp_stkt_updt_data_bytes_in_rate_prev_ctr,
1550 {
1551 " bytes_in_rate prev. ctr.",
1552 "happp.msg.stkt.updt.data.bytes_in_rate.prev_ctr",
1553 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1554 }
1555 },
1556 {
1557 &hf_happp_stkt_updt_data_bytes_out_cnt,
1558 {
1559 " bytes_out_cnt",
1560 "happp.msg.stkt.updt.data.bytes_out_cnt",
1561 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1562 }
1563 },
1564 {
1565 &hf_happp_stkt_updt_data_bytes_out_rate_curr_tick,
1566 {
1567 " bytes_out_rate curr. tick",
1568 "happp.msg.stkt.updt.data.bytes_out_rate.curr_tick",
1569 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1570 }
1571 },
1572 {
1573 &hf_happp_stkt_updt_data_bytes_out_rate_curr_ctr,
1574 {
1575 " bytes_out_rate curr. ctr.",
1576 "happp.msg.stkt.updt.data.bytes_out_rate.curr_ctr",
1577 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1578 }
1579 },
1580 {
1581 &hf_happp_stkt_updt_data_bytes_out_rate_prev_ctr,
1582 {
1583 " bytes_out_rate prev. ctr.",
1584 "happp.msg.stkt.updt.data.bytes_out_rate.prev_ctr",
1585 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1586 }
1587 },
1588 {
1589 &hf_happp_stkt_updt_ack_table_id,
1590 {
1591 " remote table Id",
1592 "happp.msg.stkt.updt.ack.table_id",
1593 FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL
1594 }
1595 },
1596 {
1597 &hf_happp_stkt_updt_ack_update_id,
1598 {
1599 " update Id", "happp.msg.stkt.updt.ack.update_id",
1600 FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL
1601 }
1602 },
1603 };
1604
1605 /* Setup protocol subtree array */
1606 static gint *ett[] = {
1607 &ett_happp,
1608 &ett_happp_msg
1609 };
1610
1611 /* Register the protocol name and description */
1612 proto_happp = proto_register_protocol("HAProxy Peers Protocol", "HAPPP", "happp");
1613
1614 /* Required function calls to register the header fields and subtrees */
1615 proto_register_field_array(proto_happp, hf, array_length(hf));
1616 proto_register_subtree_array(ett, array_length(ett));
1617}
1618
1619static gboolean
1620dissect_happp_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1621{
1622 size_t proto_strlen;
1623 conversation_t *conversation;
1624
1625 proto_strlen = strlen(HAPPP_PROTOCOL);
1626
Frédéric Lécaille8d4f1dd2021-01-21 16:25:45 +01001627 if (tvb_captured_length(tvb) < 2)
1628 return FALSE;
1629
1630 if (tvb_get_guint8(tvb, 0) == PEER_MSG_CLASS_STICKTABLE &&
1631 tvb_get_guint8(tvb, 1) >= PEER_MSG_STKT_UPDATE &&
1632 tvb_get_guint8(tvb, 1) <= PEER_MSG_STKT_ACK)
1633 goto found;
1634
Frédéric Lécaille6d889502017-11-15 14:50:19 +01001635 if (tvb_captured_length(tvb) < proto_strlen + 1)
1636 return FALSE;
1637
Joseph Herlantbd0f83f2018-11-09 19:00:24 -08001638 /* Check that we received a line beginning with HAPPP_PROTOCOL
Frédéric Lécaille6d889502017-11-15 14:50:19 +01001639 * followed by a space character.
1640 */
1641 if (tvb_strneql(tvb, 0, HAPPP_PROTOCOL, proto_strlen) ||
1642 tvb_get_guint8(tvb, proto_strlen) != ' ')
1643 return FALSE;
1644
Frédéric Lécaille8d4f1dd2021-01-21 16:25:45 +01001645 found:
Frédéric Lécaille6d889502017-11-15 14:50:19 +01001646 conversation = find_or_create_conversation(pinfo);
1647 if (!conversation)
1648 return FALSE;
1649
1650 conversation_set_dissector(conversation, happp_tcp_handle);
1651 dissect_happp_tcp(tvb, pinfo, tree, data);
1652
1653 return TRUE;
1654}
1655
1656/* Simpler form of proto_reg_handoff_happp which can be used if there are
1657 * no prefs-dependent registration function calls. */
1658void
1659proto_reg_handoff_happp(void)
1660{
1661 /* Use create_dissector_handle() to indicate that dissect_happp_tcp()
1662 * returns the number of bytes it dissected (or 0 if it thinks the packet
1663 * does not belong to HAProxy Peers Protocol).
1664 */
1665 happp_tcp_handle = create_dissector_handle(dissect_happp_tcp, proto_happp);
1666 heur_dissector_add("tcp", dissect_happp_heur_tcp, "HAPPP over TCP", "happp_tcp",
1667 proto_happp, HEURISTIC_ENABLE);
1668}
1669
William Lallemand2be58f72020-04-25 22:03:29 +02001670
1671void
1672plugin_register(void)
1673{
1674 static proto_plugin plug;
1675
1676 plug.register_protoinfo = proto_register_happp;
1677 plug.register_handoff = proto_reg_handoff_happp;
1678 proto_register_plugin(&plug);
1679}