Bug Summary

File:builds/wireshark/wireshark/ui/cli/tap-follow.c
Warning:line 620, column 12
Potential leak of memory pointed to by 'follow_info'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tap-follow.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-05-18-100347-3659-1 -x c /builds/wireshark/wireshark/ui/cli/tap-follow.c
1/* tap-follow.c
2 *
3 * Copyright 2011-2013, QA Cafe <[email protected]>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <[email protected]>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12/* This module provides udp and tcp follow stream capabilities to tshark.
13 * It is only used by tshark and not wireshark.
14 */
15
16#include "config.h"
17
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <glib.h>
22#include <epan/addr_resolv.h>
23#include <wsutil/str_util.h>
24#include <wsutil/unicode-utils.h>
25#include <epan/follow.h>
26#include <epan/stat_tap_ui.h>
27#include <epan/tap.h>
28#include <wsutil/ws_assert.h>
29#include <wsutil/cmdarg_err.h>
30
31void register_tap_listener_follow(void);
32
33/* Show Type */
34typedef enum {
35 SHOW_ASCII,
36 SHOW_CARRAY,
37 SHOW_EBCDIC,
38 SHOW_HEXDUMP,
39 SHOW_RAW,
40 SHOW_CODEC, // Ordered to match UTF-8 combobox index
41 SHOW_YAML
42} show_type_t;
43
44typedef struct _cli_follow_info {
45 show_type_t show_type;
46 register_follow_t* follower;
47
48 /* range */
49 uint32_t chunkMin;
50 uint32_t chunkMax;
51
52 /* filter */
53 int stream_index;
54 int sub_stream_index;
55 int port[2];
56 address addr[2];
57 union {
58 uint32_t addrBuf_v4;
59 ws_in6_addr addrBuf_v6;
60 } addrBuf[2];
61} cli_follow_info_t;
62
63
64#define STR_FOLLOW"follow," "follow,"
65
66#define STR_HEX",hex" ",hex"
67#define STR_ASCII",ascii" ",ascii"
68#define STR_CARRAY",carray" ",carray"
69#define STR_EBCDIC",ebcdic" ",ebcdic"
70#define STR_RAW",raw" ",raw"
71#define STR_CODEC",utf-8" ",utf-8"
72#define STR_YAML",yaml" ",yaml"
73
74static const char * follow_str_type(cli_follow_info_t* cli_follow_info)
75{
76 switch (cli_follow_info->show_type)
77 {
78 case SHOW_HEXDUMP: return "hex";
79 case SHOW_ASCII: return "ascii";
80 case SHOW_CARRAY: return "carray";
81 case SHOW_EBCDIC: return "ebcdic";
82 case SHOW_RAW: return "raw";
83 case SHOW_CODEC: return "utf-8";
84 case SHOW_YAML: return "yaml";
85 default:
86 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-follow.c",
86, __func__, "assertion \"not reached\" failed")
;
87 break;
88 }
89
90 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-follow.c",
90, __func__, "assertion \"not reached\" failed")
;
91
92 return "<unknown-mode>";
93}
94
95static void
96follow_free(follow_info_t *follow_info)
97{
98 cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
99
100 g_free(cli_follow_info);
101 follow_info_free(follow_info);
102}
103
104#define BYTES_PER_LINE16 16
105#define OFFSET_LEN8 8
106#define OFFSET_SPACE2 2
107#define HEX_START(8 + 2) (OFFSET_LEN8 + OFFSET_SPACE2)
108#define HEX_LEN(16 * 3) (BYTES_PER_LINE16 * 3) /* extra space at column 8 */
109#define HEX_SPACE2 2
110#define ASCII_START((8 + 2) + (16 * 3) + 2) (HEX_START(8 + 2) + HEX_LEN(16 * 3) + HEX_SPACE2)
111#define ASCII_LEN(16 + 1) (BYTES_PER_LINE16 + 1) /* extra space at column 8 */
112#define LINE_LEN(((8 + 2) + (16 * 3) + 2) + (16 + 1)) (ASCII_START((8 + 2) + (16 * 3) + 2) + ASCII_LEN(16 + 1))
113
114static const char bin2hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
115 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
116
117static void follow_print_hex(const char *prefixp, uint32_t offset, void *datap, int len)
118{
119 int ii;
120 int jj;
121 int kk;
122 uint8_t val;
123 char line[LINE_LEN(((8 + 2) + (16 * 3) + 2) + (16 + 1)) + 1];
124
125 for (ii = 0, jj = 0, kk = 0; ii < len; )
126 {
127 if ((ii % BYTES_PER_LINE16) == 0)
128 {
129 /* new line */
130 snprintf(line, LINE_LEN(((8 + 2) + (16 * 3) + 2) + (16 + 1)) + 1, "%0*X", OFFSET_LEN8, offset);
131 memset(line + HEX_START(8 + 2) - OFFSET_SPACE2, ' ',
132 HEX_LEN(16 * 3) + OFFSET_SPACE2 + HEX_SPACE2);
133
134 /* offset of hex */
135 jj = HEX_START(8 + 2);
136
137 /* offset of ascii */
138 kk = ASCII_START((8 + 2) + (16 * 3) + 2);
139 }
140
141 val = ((uint8_t *)datap)[ii];
142
143 line[jj++] = bin2hex[val >> 4];
144 line[jj++] = bin2hex[val & 0xf];
145 jj++;
146
147 line[kk++] = val >= ' ' && val < 0x7f ? val : '.';
148
149 /* extra space at column 8 */
150 if (++ii % BYTES_PER_LINE16 == BYTES_PER_LINE16/2)
151 {
152 line[jj++] = ' ';
153 line[kk++] = ' ';
154 }
155
156 if ((ii % BYTES_PER_LINE16) == 0 || ii == len)
157 {
158 /* end of line or buffer */
159 if (line[kk - 1] == ' ')
160 {
161 kk--;
162 }
163 line[kk] = 0;
164 printf("%s%s\n", prefixp, line);
165 offset += BYTES_PER_LINE16;
166 }
167 }
168}
169
170static void follow_draw(void *contextp)
171{
172 static const char separator[] =
173 "===================================================================\n";
174
175 follow_info_t *follow_info = (follow_info_t*)contextp;
176 cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
177 char buf[WS_INET6_ADDRSTRLEN46];
178 uint32_t global_client_pos = 0, global_server_pos = 0;
179 uint32_t *global_pos;
180 uint32_t ii, jj;
181 char *buffer;
182 wmem_strbuf_t *strbuf;
183 GList *cur;
184 follow_record_t *follow_record;
185 unsigned chunk;
186 char *b64encoded;
187 const uint32_t base64_raw_len = 57; /* Encodes to 76 bytes, common in RFCs */
188 unsigned server_buffer_count = 0, client_buffer_count = 0;
189
190 /* Print header */
191 switch (cli_follow_info->show_type)
192 {
193 case SHOW_YAML:
194 printf("peers:\n");
195 printf(" - peer: 0\n");
196 address_to_str_buf(&follow_info->client_ip, buf, sizeof buf);
197 printf(" host: %s\n", buf);
198 printf(" port: %d\n", follow_info->client_port);
199 printf(" - peer: 1\n");
200 address_to_str_buf(&follow_info->server_ip, buf, sizeof buf);
201 printf(" host: %s\n", buf);
202 printf(" port: %d\n", follow_info->server_port);
203 printf("packets:\n");
204 break;
205
206 default:
207 printf("\n%s", separator);
208 printf("Follow: %s,%s\n", proto_get_protocol_filter_name(get_follow_proto_id(cli_follow_info->follower)), follow_str_type(cli_follow_info));
209 printf("Filter: %s\n", follow_info->filter_out_filter);
210
211 address_to_str_buf(&follow_info->client_ip, buf, sizeof buf);
212 if (follow_info->client_ip.type == AT_IPv6)
213 printf("Node 0: [%s]:%u\n", buf, follow_info->client_port);
214 else
215 printf("Node 0: %s:%u\n", buf, follow_info->client_port);
216
217 address_to_str_buf(&follow_info->server_ip, buf, sizeof buf);
218 if (follow_info->server_ip.type == AT_IPv6)
219 printf("Node 1: [%s]:%u\n", buf, follow_info->server_port);
220 else
221 printf("Node 1: %s:%u\n", buf, follow_info->server_port);
222 break;
223 }
224
225 for (cur = g_list_last(follow_info->payload), chunk = 1;
226 cur != NULL((void*)0);
227 cur = g_list_previous(cur)((cur) ? (((GList *)(cur))->prev) : ((void*)0)), chunk++)
228 {
229 follow_record = (follow_record_t *)cur->data;
230 if (!follow_record->is_server) {
231 global_pos = &global_client_pos;
232 } else {
233 global_pos = &global_server_pos;
234 }
235
236 /* ignore chunks not in range */
237 if ((chunk < cli_follow_info->chunkMin) || (chunk > cli_follow_info->chunkMax)) {
238 (*global_pos) += follow_record->data->len;
239 continue;
240 }
241
242 /* Print start of line */
243 switch (cli_follow_info->show_type)
244 {
245 case SHOW_HEXDUMP:
246 case SHOW_CODEC: /* The transformation to UTF-8 can change the length */
247 break;
248
249 case SHOW_ASCII:
250 case SHOW_EBCDIC:
251 printf("%s%u\n", follow_record->is_server ? "\t" : "", follow_record->data->len);
252 break;
253
254 case SHOW_RAW:
255 if (follow_record->is_server)
256 {
257 putchar('\t');
258 }
259 break;
260
261 case SHOW_CARRAY:
262 printf("char peer%d_%d[] = { /* Packet %u */\n",
263 follow_record->is_server ? 1 : 0,
264 follow_record->is_server ? server_buffer_count++ : client_buffer_count++,
265 follow_record->packet_num);
266 break;
267
268 case SHOW_YAML:
269 printf(" - packet: %d\n", follow_record->packet_num);
270 printf(" peer: %d\n", follow_record->is_server ? 1 : 0);
271 printf(" index: %d\n", follow_record->is_server ? server_buffer_count++ : client_buffer_count++);
272 printf(" timestamp: %.9f\n", nstime_to_sec(&follow_record->abs_ts));
273 printf(" data: !!binary |\n");
274 break;
275
276 default:
277 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-follow.c",
277, __func__, "assertion \"not reached\" failed")
;
278 }
279
280 /* Print data */
281 switch (cli_follow_info->show_type)
282 {
283 case SHOW_HEXDUMP:
284 follow_print_hex(follow_record->is_server ? "\t" : "", *global_pos, follow_record->data->data, follow_record->data->len);
285 (*global_pos) += follow_record->data->len;
286 break;
287
288 case SHOW_ASCII:
289 case SHOW_EBCDIC:
290 buffer = (char *)g_malloc(follow_record->data->len+2);
291
292 for (ii = 0; ii < follow_record->data->len; ii++)
293 {
294 switch (follow_record->data->data[ii])
295 {
296 // XXX: qt/follow_stream_dialog.c sanitize_buffer() also passes
297 // tabs ('\t') through. Should we do that here too?
298 // The Qt code has automatic universal new line handling for reading
299 // so, e.g., \r\n in HTML becomes just \n, but we don't do that here.
300 // (The Qt version doesn't write the file as Text, so all files use
301 // Unix line endings, including on Windows.)
302 case '\r':
303 case '\n':
304 buffer[ii] = follow_record->data->data[ii];
305 break;
306 default:
307 buffer[ii] = g_ascii_isprint(follow_record->data->data[ii])((g_ascii_table[(guchar) (follow_record->data->data[ii]
)] & G_ASCII_PRINT) != 0)
? follow_record->data->data[ii] : '.';
308 break;
309 }
310 }
311
312 buffer[ii++] = '\n';
313 buffer[ii] = 0;
314 if (cli_follow_info->show_type == SHOW_EBCDIC) {
315 EBCDIC_to_ASCII((uint8_t*)buffer, ii);
316 }
317 printf("%s", buffer);
318 g_free(buffer);
319 break;
320
321 case SHOW_CODEC:
322 // This does the same as the Show As UTF-8 code in the Qt version
323 // (passing through all legal UTF-8, including control codes and
324 // internal NULs, substituting illegal UTF-8 sequences with
325 // REPLACEMENT CHARACTER, and not handling valid UTF-8 sequences
326 // which are split between unreassembled frames), except for the
327 // end of line terminator issue as above.
328 strbuf = ws_utf8_make_valid_strbuf(NULL((void*)0), follow_record->data->data, follow_record->data->len);
329 printf("%s%zu\n", follow_record->is_server ? "\t" : "", wmem_strbuf_get_len(strbuf));
330 fwrite(wmem_strbuf_get_str(strbuf), 1, wmem_strbuf_get_len(strbuf), stdoutstdout);
331 wmem_strbuf_destroy(strbuf);
332 putchar('\n');
333 break;
334
335 case SHOW_RAW:
336 buffer = (char *)g_malloc((follow_record->data->len*2)+2);
337
338 for (ii = 0, jj = 0; ii < follow_record->data->len; ii++)
339 {
340 buffer[jj++] = bin2hex[follow_record->data->data[ii] >> 4];
341 buffer[jj++] = bin2hex[follow_record->data->data[ii] & 0xf];
342 }
343
344 buffer[jj++] = '\n';
345 buffer[jj] = 0;
346 printf("%s", buffer);
347 g_free(buffer);
348 break;
349
350 case SHOW_YAML:
351 ii = 0;
352 while (ii < follow_record->data->len) {
353 uint32_t len = ii + base64_raw_len < follow_record->data->len
354 ? base64_raw_len
355 : follow_record->data->len - ii;
356 b64encoded = g_base64_encode(&follow_record->data->data[ii], len);
357 printf(" %s\n", b64encoded);
358 g_free(b64encoded);
359 ii += len;
360 }
361 break;
362
363 case SHOW_CARRAY:
364 strbuf = wmem_strbuf_new_sized(NULL((void*)0), 2 + 6 * follow_record->data->len);
365 for (ii = 0; ii < follow_record->data->len; ii++)
366 {
367 wmem_strbuf_append_printf(strbuf, "0x%02x,", follow_record->data->data[ii]);
368 if ((ii % 8 == 7) && (ii + 1 < follow_record->data->len)) {
369 wmem_strbuf_append_c(strbuf, '\n');
370 } else {
371 wmem_strbuf_append_c(strbuf, ' ');
372 }
373 }
374 wmem_strbuf_append(strbuf, "};");
375 puts(wmem_strbuf_get_str(strbuf));
376 wmem_strbuf_destroy(strbuf);
377 break;
378
379 default:
380 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-follow.c",
380, __func__, "assertion \"not reached\" failed")
;
381 }
382 }
383
384 /* Print footer */
385 switch (cli_follow_info->show_type)
386 {
387 case SHOW_YAML:
388 break;
389
390 default:
391 printf("%s", separator);
392 break;
393 }
394}
395
396static bool_Bool follow_arg_strncmp(const char **opt_argp, const char *strp)
397{
398 size_t len = strlen(strp);
399
400 if (strncmp(*opt_argp, strp, len) == 0)
401 {
402 *opt_argp += len;
403 return true1;
404 }
405 return false0;
406}
407
408static bool_Bool
409follow_arg_mode(const char **opt_argp, follow_info_t *follow_info)
410{
411 cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
412
413 if (follow_arg_strncmp(opt_argp, STR_HEX",hex"))
414 {
415 cli_follow_info->show_type = SHOW_HEXDUMP;
416 }
417 else if (follow_arg_strncmp(opt_argp, STR_ASCII",ascii"))
418 {
419 cli_follow_info->show_type = SHOW_ASCII;
420 }
421 else if (follow_arg_strncmp(opt_argp, STR_EBCDIC",ebcdic"))
422 {
423 cli_follow_info->show_type = SHOW_EBCDIC;
424 }
425 else if (follow_arg_strncmp(opt_argp, STR_RAW",raw"))
426 {
427 cli_follow_info->show_type = SHOW_RAW;
428 }
429 else if (follow_arg_strncmp(opt_argp, STR_CODEC",utf-8"))
430 {
431 cli_follow_info->show_type = SHOW_CODEC;
432 }
433 else if (follow_arg_strncmp(opt_argp, STR_YAML",yaml"))
434 {
435 cli_follow_info->show_type = SHOW_YAML;
436 }
437 else if (follow_arg_strncmp(opt_argp, STR_CARRAY",carray"))
438 {
439 cli_follow_info->show_type = SHOW_CARRAY;
440 }
441 else
442 {
443 cmdarg_err("Invalid display mode.");
444 return false0;
445 }
446
447 return true1;
448}
449
450#define _STRING(s)"s" # s
451#define STRING(s)"s" _STRING(s)"s"
452
453#define ADDR_CHARS80 80
454#define ADDR_LEN(80 + 1) (ADDR_CHARS80 + 1)
455#define ADDRv6_FMT",[%" "80" "[^]]]:%d%n" ",[%" STRING(ADDR_CHARS)"80" "[^]]]:%d%n"
456#define ADDRv4_FMT",%" "80" "[^:]:%d%n" ",%" STRING(ADDR_CHARS)"80" "[^:]:%d%n"
457
458static bool_Bool
459follow_arg_filter(const char **opt_argp, follow_info_t *follow_info)
460{
461 int len;
462 unsigned int ii;
463 char addr[ADDR_LEN(80 + 1)];
464 cli_follow_info_t* cli_follow_info = (cli_follow_info_t*)follow_info->gui_data;
465 bool_Bool is_ipv6;
466
467 if (sscanf(*opt_argp, ",%d%n", &cli_follow_info->stream_index, &len) == 1 &&
468 ((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
469 {
470 *opt_argp += len;
471 follow_info->stream_id = cli_follow_info->stream_index;
472
473 /* if it's HTTP2 or QUIC protocol we should read substream id otherwise it's a range parameter from follow_arg_range */
474 if (cli_follow_info->sub_stream_index == -1 && sscanf(*opt_argp, ",%d%n", &cli_follow_info->sub_stream_index, &len) == 1 &&
475 ((*opt_argp)[len] == 0 || (*opt_argp)[len] == ','))
476 {
477 *opt_argp += len;
478 follow_info->substream_id = cli_follow_info->sub_stream_index;
479 }
480 }
481 else
482 {
483 for (ii = 0; ii < array_length(cli_follow_info->addr)(sizeof (cli_follow_info->addr) / sizeof (cli_follow_info->
addr)[0])
; ii++)
484 {
485 if (sscanf(*opt_argp, ADDRv6_FMT",[%" "80" "[^]]]:%d%n", addr, &cli_follow_info->port[ii], &len) == 2)
486 {
487 is_ipv6 = true1;
488 }
489 else if (sscanf(*opt_argp, ADDRv4_FMT",%" "80" "[^:]:%d%n", addr, &cli_follow_info->port[ii], &len) == 2)
490 {
491 is_ipv6 = false0;
492 }
493 else
494 {
495 cmdarg_err("Invalid address.");
496 return false0;
497 }
498
499 if (cli_follow_info->port[ii] <= 0 || cli_follow_info->port[ii] > UINT16_MAX(65535))
500 {
501 cmdarg_err("Invalid port.");
502 return false0;
503 }
504
505 if (is_ipv6)
506 {
507 if (!get_host_ipaddr6(addr, &cli_follow_info->addrBuf[ii].addrBuf_v6))
508 {
509 cmdarg_err("Can't get IPv6 address");
510 return false0;
511 }
512 set_address(&cli_follow_info->addr[ii], AT_IPv6, 16, (void *)&cli_follow_info->addrBuf[ii].addrBuf_v6);
513 }
514 else
515 {
516 if (!get_host_ipaddr(addr, &cli_follow_info->addrBuf[ii].addrBuf_v4))
517 {
518 cmdarg_err("Can't get IPv4 address");
519 return false0;
520 }
521 set_address(&cli_follow_info->addr[ii], AT_IPv4, 4, (void *)&cli_follow_info->addrBuf[ii].addrBuf_v4);
522 }
523
524 *opt_argp += len;
525 }
526
527 if (cli_follow_info->addr[0].type != cli_follow_info->addr[1].type)
528 {
529 cmdarg_err("Mismatched IP address types.");
530 return false0;
531 }
532 cli_follow_info->stream_index = -1;
533 }
534
535 return true1;
536}
537
538static bool_Bool follow_arg_range(const char **opt_argp, cli_follow_info_t* cli_follow_info)
539{
540 int len;
541
542 if (**opt_argp == 0)
543 {
544 cli_follow_info->chunkMin = 1;
545 cli_follow_info->chunkMax = UINT32_MAX(4294967295U);
546 }
547 else
548 {
549 if (sscanf(*opt_argp, ",%u-%u%n", &cli_follow_info->chunkMin, &cli_follow_info->chunkMax, &len) == 2)
550 {
551 *opt_argp += len;
552 }
553 else if (sscanf(*opt_argp, ",%u%n", &cli_follow_info->chunkMin, &len) == 1)
554 {
555 cli_follow_info->chunkMax = cli_follow_info->chunkMin;
556 *opt_argp += len;
557 }
558 else
559 {
560 cmdarg_err("Invalid range.");
561 return false0;
562 }
563
564 if (cli_follow_info->chunkMin < 1 || cli_follow_info->chunkMin > cli_follow_info->chunkMax)
565 {
566 cmdarg_err("Invalid range value.");
567 return false0;
568 }
569 }
570
571 return true1;
572}
573
574static bool_Bool
575follow_arg_done(const char *opt_argp)
576{
577 if (*opt_argp != 0)
578 {
579 cmdarg_err("Invalid parameter.");
580 return false0;
581 }
582
583 return true1;
584}
585
586static bool_Bool follow_stream(const char *opt_argp, void *userdata)
587{
588 follow_info_t *follow_info;
589 cli_follow_info_t* cli_follow_info;
590 GString *errp;
591 register_follow_t* follower = (register_follow_t*)userdata;
592 follow_index_filter_func index_filter;
593 follow_address_filter_func address_filter;
594 int proto_id = get_follow_proto_id(follower);
595 const char* proto_filter_name = proto_get_protocol_filter_name(proto_id);
596 bool_Bool arg_success = true1;
597
598 opt_argp += strlen(STR_FOLLOW"follow,");
599 opt_argp += strlen(proto_filter_name);
600
601 cli_follow_info = g_new0(cli_follow_info_t, 1)((cli_follow_info_t *) g_malloc0_n ((1), sizeof (cli_follow_info_t
)))
;
602 cli_follow_info->stream_index = -1;
603 /* use second parameter only for followers that have sub streams
604 * (currently HTTP2 or QUIC) */
605 if (get_follow_sub_stream_id_func(follower)) {
1
Assuming the condition is false
2
Taking false branch
606 cli_follow_info->sub_stream_index = -1;
607 } else {
608 cli_follow_info->sub_stream_index = 0;
609 }
610 follow_info = g_new0(follow_info_t, 1)((follow_info_t *) g_malloc0_n ((1), sizeof (follow_info_t)));
3
Memory is allocated
611 follow_info->gui_data = cli_follow_info;
612 follow_info->substream_id = SUBSTREAM_UNUSED0xFFFFFFFFFFFFFFFFUL;
613 cli_follow_info->follower = follower;
614
615 arg_success &= follow_arg_mode(&opt_argp, follow_info);
616 arg_success &= follow_arg_filter(&opt_argp, follow_info);
617 arg_success &= follow_arg_range(&opt_argp, cli_follow_info);
618 arg_success &= follow_arg_done(opt_argp);
619 if (!arg_success
3.1
'arg_success' is false
)
4
Taking true branch
620 return false0;
5
Potential leak of memory pointed to by 'follow_info'
621
622 if (cli_follow_info->stream_index >= 0)
623 {
624 index_filter = get_follow_index_func(follower);
625 follow_info->filter_out_filter = index_filter(cli_follow_info->stream_index, cli_follow_info->sub_stream_index);
626 if (follow_info->filter_out_filter == NULL((void*)0) || cli_follow_info->sub_stream_index < 0)
627 {
628 cmdarg_err("Error creating filter for this stream.");
629 return false0;
630 }
631 }
632 else
633 {
634 address_filter = get_follow_address_func(follower);
635 follow_info->filter_out_filter = address_filter(&cli_follow_info->addr[0], &cli_follow_info->addr[1], cli_follow_info->port[0], cli_follow_info->port[1]);
636 if (follow_info->filter_out_filter == NULL((void*)0))
637 {
638 cmdarg_err("Error creating filter for this address/port pair.\n");
639 return false0;
640 }
641 }
642
643 errp = register_tap_listener(get_follow_tap_string(follower), follow_info, follow_info->filter_out_filter, 0,
644 NULL((void*)0), get_follow_tap_handler(follower), follow_draw, (tap_finish_cb)follow_free);
645
646 if (errp != NULL((void*)0))
647 {
648 follow_free(follow_info);
649 g_string_free(errp, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(errp), ((!(0)))) : g_string_free_and_steal (errp)) : (g_string_free
) ((errp), ((!(0)))))
;
650 cmdarg_err("Error registering tap listener.");
651 return false0;
652 }
653 return true1;
654}
655
656static bool_Bool
657follow_register(const void *key _U___attribute__((unused)), void *value, void *userdata _U___attribute__((unused)))
658{
659 register_follow_t *follower = (register_follow_t*)value;
660 stat_tap_ui follow_ui;
661 char *cli_string;
662
663 cli_string = follow_get_stat_tap_string(follower);
664 follow_ui.group = REGISTER_STAT_GROUP_GENERIC;
665 follow_ui.title = NULL((void*)0); /* construct this from the protocol info? */
666 follow_ui.cli_string = cli_string;
667 follow_ui.tap_init_cb = follow_stream;
668 follow_ui.nparams = 0;
669 follow_ui.params = NULL((void*)0);
670 register_stat_tap_ui(&follow_ui, follower);
671 g_free(cli_string);
672 return false0;
673}
674
675void
676register_tap_listener_follow(void)
677{
678 follow_iterate_followers(follow_register, NULL((void*)0));
679}
680
681/*
682 * Editor modelines - https://www.wireshark.org/tools/modelines.html
683 *
684 * Local Variables:
685 * c-basic-offset: 2
686 * tab-width: 8
687 * indent-tabs-mode: nil
688 * End:
689 *
690 * ex: set shiftwidth=2 tabstop=8 expandtab:
691 * :indentSize=2:tabSize=8:noTabs=true:
692 */