Bug Summary

File:builds/wireshark/wireshark/editcap.c
Warning:line 827, column 5
Value stored to 'caplen' is never read

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 editcap.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-18/lib/clang/18 -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-18/lib/clang/18/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-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -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 -dwarf-debug-flags /usr/lib/llvm-18/bin/clang -### --analyze -x c -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 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -fvisibility=hidden -fexcess-precision=fast -fstrict-flex-arrays=3 -fstack-clash-protection -fcf-protection=full -D _GLIBCXX_ASSERTIONS -fstack-protector-strong -fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -fexceptions -Wno-format-truncation -Wno-format-nonliteral -fdiagnostics-color=always -Wno-pointer-sign -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -std=gnu11 -fPIE /builds/wireshark/wireshark/editcap.c -o /builds/wireshark/wireshark/sbout/2025-01-03-100300-3868-1 -Xclang -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-01-03-100300-3868-1 -x c /builds/wireshark/wireshark/editcap.c
1/* editcap.c
2 * Edit capture files. We can delete packets, adjust timestamps, or
3 * simply convert from one format to another format.
4 *
5 * Originally written by Richard Sharpe.
6 * Improved by Guy Harris.
7 * Further improved by Richard Sharpe.
8 *
9 * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
10 *
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <[email protected]>
13 * Copyright 1998 Gerald Combs
14 *
15 * SPDX-License-Identifier: GPL-2.0-or-later
16 */
17
18#include <config.h>
19#define WS_LOG_DOMAIN"Main" LOG_DOMAIN_MAIN"Main"
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <math.h>
26#include <stddef.h>
27
28#include <time.h>
29#include <glib.h>
30#include <gcrypt.h>
31
32#ifdef HAVE_UNISTD_H1
33#include <unistd.h>
34#endif
35
36#include <ws_exit_codes.h>
37#include <wsutil/ws_getopt.h>
38
39#include <wiretap/secrets-types.h>
40#include <wiretap/wtap.h>
41
42#include "epan/etypes.h"
43#include "epan/dissectors/packet-ieee80211-radiotap-defs.h"
44
45#ifdef _WIN32
46#include <process.h> /* getpid */
47#include <winsock2.h>
48#endif
49
50#include <wsutil/clopts_common.h>
51#include <wsutil/cmdarg_err.h>
52#include <wsutil/filesystem.h>
53#include <wsutil/file_util.h>
54#include <wsutil/plugins.h>
55#include <wsutil/privileges.h>
56#include <wsutil/strnatcmp.h>
57#include <wsutil/str_util.h>
58#include <cli_main.h>
59#include <wsutil/version_info.h>
60#include <wsutil/pint.h>
61#include <wsutil/strtoi.h>
62#include <wsutil/ws_assert.h>
63#include <wsutil/wslog.h>
64#include <wiretap/wtap_opttypes.h>
65
66#include "ui/failure_message.h"
67
68#include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
69
70/* Additional exit codes */
71#define CANT_EXTRACT_PREFIX2 2
72#define WRITE_ERROR2 2
73#define DUMP_ERROR2 2
74
75#define NANOSECS_PER_SEC1000000000 1000000000
76
77/*
78 * Some globals so we can pass things to various routines
79 */
80
81struct select_item {
82 bool_Bool inclusive;
83 uint64_t first, second;
84};
85
86/*
87 * Duplicate frame detection
88 */
89typedef struct _fd_hash_t {
90 uint8_t digest[16];
91 uint32_t len;
92 nstime_t frame_time;
93} fd_hash_t;
94
95#define DEFAULT_DUP_DEPTH5 5 /* Used with -d */
96#define MAX_DUP_DEPTH1000000 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
97
98static fd_hash_t fd_hash[MAX_DUP_DEPTH1000000];
99static int dup_window = DEFAULT_DUP_DEPTH5;
100static int cur_dup_entry;
101
102static uint32_t ignored_bytes; /* Used with -I */
103
104#define ONE_BILLION1000000000 1000000000
105
106/* Weights of different errors we can introduce */
107/* We should probably make these command-line arguments */
108/* XXX - Should we add a bit-level error? */
109#define ERR_WT_BIT5 5 /* Flip a random bit */
110#define ERR_WT_BYTE5 5 /* Substitute a random byte */
111#define ERR_WT_ALNUM5 5 /* Substitute a random character in [A-Za-z0-9] */
112#define ERR_WT_FMT2 2 /* Substitute "%s" */
113#define ERR_WT_AA1 1 /* Fill the remainder of the buffer with 0xAA */
114#define ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1) (ERR_WT_BIT5 + ERR_WT_BYTE5 + ERR_WT_ALNUM5 + ERR_WT_FMT2 + ERR_WT_AA1)
115
116#define ALNUM_CHARS"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
117#define ALNUM_LEN(sizeof("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
) - 1)
(sizeof(ALNUM_CHARS"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") - 1)
118
119struct time_adjustment {
120 nstime_t tv;
121 int is_negative;
122};
123
124typedef struct _chop_t {
125 int len_begin;
126 int off_begin_pos;
127 int off_begin_neg;
128 int len_end;
129 int off_end_pos;
130 int off_end_neg;
131} chop_t;
132
133
134/* Table of user comments */
135GTree *frames_user_comments;
136GPtrArray *capture_comments;
137
138#define MAX_SELECTIONS512 512
139static struct select_item selectfrm[MAX_SELECTIONS512];
140static unsigned max_selected;
141static bool_Bool keep_em;
142static int out_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN-1;
143static int out_frame_type = -2; /* Leave frame type alone */
144static bool_Bool verbose; /* Not so verbose */
145static struct time_adjustment time_adj; /* no adjustment */
146static nstime_t relative_time_window; /* de-dup time window */
147static double err_prob = -1.0;
148static nstime_t starttime;
149static bool_Bool have_starttime;
150static nstime_t stoptime;
151static bool_Bool have_stoptime;
152static bool_Bool check_startstop;
153static bool_Bool rem_vlan;
154static bool_Bool dup_detect;
155static bool_Bool dup_detect_by_time;
156static bool_Bool skip_radiotap;
157static bool_Bool discard_all_secrets;
158static bool_Bool discard_cap_comments;
159static bool_Bool set_unused;
160static bool_Bool discard_pkt_comments;
161static bool_Bool do_extract_secrets;
162
163static int do_strict_time_adjustment;
164static struct time_adjustment strict_time_adj; /* strict time adjustment */
165static nstime_t previous_time; /* previous time */
166
167static const struct {
168 const char *str;
169 uint32_t id;
170} secrets_types[] = {
171 { "tls", SECRETS_TYPE_TLS0x544c534b },
172 { "ssh", SECRETS_TYPE_SSH0x5353484b },
173 { "wg", SECRETS_TYPE_WIREGUARD0x57474b4c },
174 { "opcua", SECRETS_TYPE_OPCUA0x55414b4c },
175};
176
177static unsigned find_dct2000_real_data(const uint8_t *buf);
178static void handle_chopping(chop_t chop, wtap_packet_header *phdr,
179 uint8_t **buf, bool_Bool adjlen);
180
181static char *
182abs_time_to_str_with_sec_resolution(const nstime_t *abs_time)
183{
184 struct tm *tmp;
185 char *buf = (char *)g_malloc(16);
186
187 tmp = localtime(&abs_time->secs);
188
189 if (tmp) {
190 snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
191 tmp->tm_year + 1900,
192 tmp->tm_mon+1,
193 tmp->tm_mday,
194 tmp->tm_hour,
195 tmp->tm_min,
196 tmp->tm_sec);
197 } else {
198 buf[0] = '\0';
199 }
200
201 return buf;
202}
203
204static char *
205fileset_get_filename_by_pattern(unsigned idx, const nstime_t *ts,
206 char *fprefix, char *fsuffix)
207{
208 char filenum[5+1];
209 char *timestr;
210 char *abs_str;
211
212 snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES100000);
213 if (ts) {
214 timestr = abs_time_to_str_with_sec_resolution(ts);
215 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL((void*)0));
216 g_free(timestr);
217 } else
218 abs_str = g_strconcat(fprefix, "_", filenum, fsuffix, NULL((void*)0));
219
220 return abs_str;
221}
222
223static bool_Bool
224fileset_extract_prefix_suffix(const char *fname, char **fprefix, char **fsuffix, wtap_compression_type *compression_typep)
225{
226 char *pfx, *last_pathsep;
227 char *save_file;
228 wtap_compression_type compression_type;
229
230 save_file = g_strdup(fname)g_strdup_inline (fname);
231 if (save_file == NULL((void*)0)) {
232 fprintf(stderrstderr, "editcap: Out of memory\n");
233 return false0;
234 }
235
236 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR'/');
237 if (last_pathsep == NULL((void*)0)) {
238 last_pathsep = save_file;
239 }
240 pfx = strrchr(last_pathsep, '.');
241 if (pfx != NULL((void*)0)) {
242 /* The pathname has a "." in it, and it's in the last component
243 * of the pathname (because there is either only one component,
244 * i.e. last_pathsep is null as there are no path separators,
245 * or the "." is after the path separator before the last
246 * component.
247
248 * Treat it as a separator between the rest of the file name and
249 * the file name suffix, and arrange that the names given to the
250 * ring buffer files have the specified suffix, i.e. put the
251 * changing part of the name *before* the suffix. */
252 pfx[0] = '\0';
253 compression_type = wtap_extension_to_compression_type(pfx + 1);
254 if (compression_type != WTAP_UNKNOWN_COMPRESSION) {
255 char *pfx2 = strrchr(last_pathsep, '.');
256 if (pfx2 != NULL((void*)0)) {
257 pfx[0] = '.';
258 pfx = pfx2;
259 pfx[0] = '\0';
260 }
261 if (compression_typep && *compression_typep == WTAP_UNKNOWN_COMPRESSION) {
262 *compression_typep = compression_type;
263 }
264 /* XXX - What if there's an extension matching a compression type
265 * and the passed in compression type is known but something else?
266 */
267 }
268 *fprefix = g_strdup(save_file)g_strdup_inline (save_file);
269 pfx[0] = '.'; /* restore capfile_name */
270 *fsuffix = g_strdup(pfx)g_strdup_inline (pfx);
271 } else {
272 /* Either there's no "." in the pathname, or it's in a directory
273 * component, so the last component has no suffix. */
274 *fprefix = g_strdup(save_file)g_strdup_inline (save_file);
275 *fsuffix = NULL((void*)0);
276 }
277 g_free(save_file);
278 return true1;
279}
280
281/* Add a selection item, a simple parser for now */
282static bool_Bool
283add_selection(char *sel, uint64_t* max_selection)
284{
285 char *locn;
286 char *next;
287
288 if (max_selected >= MAX_SELECTIONS512) {
289 /* Let the user know we stopped selecting */
290 fprintf(stderrstderr, "Out of room for packet selections.\n");
291 return false0;
292 }
293
294 if (verbose)
295 fprintf(stderrstderr, "Add_Selected: %s\n", sel);
296
297 if ((locn = strchr(sel, '-')) == NULL((void*)0)) { /* No dash, so a single number? */
298 if (verbose)
299 fprintf(stderrstderr, "Not inclusive ...");
300
301 selectfrm[max_selected].inclusive = false0;
302 selectfrm[max_selected].first = get_uint64(sel, "packet number");
303 if (selectfrm[max_selected].first > *max_selection)
304 *max_selection = selectfrm[max_selected].first;
305
306 if (verbose)
307 fprintf(stderrstderr, " %" PRIu64"l" "u" "\n", selectfrm[max_selected].first);
308 } else {
309 if (verbose)
310 fprintf(stderrstderr, "Inclusive ...");
311
312 *locn = '\0'; /* split the range */
313 next = locn + 1;
314 selectfrm[max_selected].inclusive = true1;
315 selectfrm[max_selected].first = get_uint64(sel, "beginning of packet range");
316 selectfrm[max_selected].second = get_uint64(next, "end of packet range");
317
318 if (selectfrm[max_selected].second == 0)
319 {
320 /* Not a valid number, presume all */
321 selectfrm[max_selected].second = *max_selection = UINT64_MAX(18446744073709551615UL);
322 }
323 else if (selectfrm[max_selected].second > *max_selection)
324 *max_selection = selectfrm[max_selected].second;
325
326 if (verbose)
327 fprintf(stderrstderr, " %" PRIu64"l" "u" ", %" PRIu64"l" "u" "\n", selectfrm[max_selected].first,
328 selectfrm[max_selected].second);
329 }
330
331 max_selected++;
332 return true1;
333}
334
335/* Was the packet selected? */
336
337static bool_Bool
338selected(uint64_t recno)
339{
340 unsigned i;
341
342 for (i = 0; i < max_selected; i++) {
343 if (selectfrm[i].inclusive) {
344 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
345 return true1;
346 } else {
347 if (recno == selectfrm[i].first)
348 return true1;
349 }
350 }
351
352 return false0;
353}
354
355static bool_Bool
356set_time_adjustment(char *optarg_str_p)
357{
358 char *frac, *end;
359 long val;
360 size_t frac_digits;
361
362 if (!optarg_str_p)
363 return true1;
364
365 /* skip leading whitespace */
366 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
367 optarg_str_p++;
368
369 /* check for a negative adjustment */
370 if (*optarg_str_p == '-') {
371 time_adj.is_negative = 1;
372 optarg_str_p++;
373 }
374
375 /* collect whole number of seconds, if any */
376 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
377 val = 0;
378 frac = optarg_str_p;
379 } else {
380 val = strtol(optarg_str_p, &frac, 10);
381 if (frac == NULL((void*)0) || frac == optarg_str_p
382 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
383 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
384 optarg_str_p);
385 return false0;
386 }
387 if (val < 0) { /* implies '--' since we caught '-' above */
388 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
389 optarg_str_p);
390 return false0;
391 }
392 }
393 time_adj.tv.secs = val;
394
395 /* now collect the partial seconds, if any */
396 if (*frac != '\0') { /* chars left, so get fractional part */
397 val = strtol(&(frac[1]), &end, 10);
398 /* if more than 9 fractional digits truncate to 9 */
399 if ((end - &(frac[1])) > 9) {
400 frac[10] = 't'; /* 't' for truncate */
401 val = strtol(&(frac[1]), &end, 10);
402 }
403 if (*frac != '.' || end == NULL((void*)0) || end == frac || val < 0
404 || val >= ONE_BILLION1000000000 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
405 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
406 optarg_str_p);
407 return false0;
408 }
409 } else {
410 return true1; /* no fractional digits */
411 }
412
413 /* adjust fractional portion from fractional to numerator
414 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
415 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
416 while(frac_digits < 9) { /* this is frac of 10^9 */
417 val *= 10;
418 frac_digits++;
419 }
420
421 time_adj.tv.nsecs = (int)val;
422 return true1;
423}
424
425static bool_Bool
426set_strict_time_adj(char *optarg_str_p)
427{
428 char *frac, *end;
429 long val;
430 size_t frac_digits;
431
432 if (!optarg_str_p)
433 return true1;
434
435 /* skip leading whitespace */
436 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
437 optarg_str_p++;
438
439 /*
440 * check for a negative adjustment
441 * A negative strict adjustment value is a flag
442 * to adjust all frames by the specified delta time.
443 */
444 if (*optarg_str_p == '-') {
445 strict_time_adj.is_negative = 1;
446 optarg_str_p++;
447 }
448
449 /* collect whole number of seconds, if any */
450 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
451 val = 0;
452 frac = optarg_str_p;
453 } else {
454 val = strtol(optarg_str_p, &frac, 10);
455 if (frac == NULL((void*)0) || frac == optarg_str_p
456 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
457 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
458 optarg_str_p);
459 return false0;
460 }
461 if (val < 0) { /* implies '--' since we caught '-' above */
462 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
463 optarg_str_p);
464 return false0;
465 }
466 }
467 strict_time_adj.tv.secs = val;
468
469 /* now collect the partial seconds, if any */
470 if (*frac != '\0') { /* chars left, so get fractional part */
471 val = strtol(&(frac[1]), &end, 10);
472 /* if more than 9 fractional digits truncate to 9 */
473 if ((end - &(frac[1])) > 9) {
474 frac[10] = 't'; /* 't' for truncate */
475 val = strtol(&(frac[1]), &end, 10);
476 }
477 if (*frac != '.' || end == NULL((void*)0) || end == frac || val < 0
478 || val >= ONE_BILLION1000000000 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
479 fprintf(stderrstderr, "editcap: \"%s\" isn't a valid time adjustment\n",
480 optarg_str_p);
481 return false0;
482 }
483 } else {
484 return true1; /* no fractional digits */
485 }
486
487 /* adjust fractional portion from fractional to numerator
488 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
489 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
490 while(frac_digits < 9) { /* this is frac of 10^9 */
491 val *= 10;
492 frac_digits++;
493 }
494
495 strict_time_adj.tv.nsecs = (int)val;
496 return true1;
497}
498
499static bool_Bool
500set_rel_time(char *optarg_str_p)
501{
502 char *frac, *end;
503 long val;
504 size_t frac_digits;
505
506 if (!optarg_str_p)
507 return true1;
508
509 /* skip leading whitespace */
510 while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
511 optarg_str_p++;
512
513 /* ignore negative adjustment */
514 if (*optarg_str_p == '-')
515 optarg_str_p++;
516
517 /* collect whole number of seconds, if any */
518 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
519 val = 0;
520 frac = optarg_str_p;
521 } else {
522 val = strtol(optarg_str_p, &frac, 10);
523 if (frac == NULL((void*)0) || frac == optarg_str_p
524 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
525 fprintf(stderrstderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
526 optarg_str_p);
527 return false0;
528 }
529 if (val < 0) { /* implies '--' since we caught '-' above */
530 fprintf(stderrstderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
531 optarg_str_p);
532 return false0;
533 }
534 }
535 relative_time_window.secs = val;
536
537 /* now collect the partial seconds, if any */
538 if (*frac != '\0') { /* chars left, so get fractional part */
539 val = strtol(&(frac[1]), &end, 10);
540 /* if more than 9 fractional digits truncate to 9 */
541 if ((end - &(frac[1])) > 9) {
542 frac[10] = 't'; /* 't' for truncate */
543 val = strtol(&(frac[1]), &end, 10);
544 }
545 if (*frac != '.' || end == NULL((void*)0) || end == frac || val < 0
546 || val >= ONE_BILLION1000000000 || val == LONG_MIN(-9223372036854775807L -1L) || val == LONG_MAX9223372036854775807L) {
547 fprintf(stderrstderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
548 optarg_str_p);
549 return false0;
550 }
551 } else {
552 return true1; /* no fractional digits */
553 }
554
555 /* adjust fractional portion from fractional to numerator
556 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
557 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
558 while(frac_digits < 9) { /* this is frac of 10^9 */
559 val *= 10;
560 frac_digits++;
561 }
562
563 relative_time_window.nsecs = (int)val;
564 return true1;
565}
566
567#define SLL_ADDRLEN8 8 /* length of address field */
568struct sll_header {
569 uint16_t sll_pkttype; /* packet type */
570 uint16_t sll_hatype; /* link-layer address type */
571 uint16_t sll_halen; /* link-layer address length */
572 uint8_t sll_addr[SLL_ADDRLEN8]; /* link-layer address */
573 uint16_t sll_protocol; /* protocol */
574};
575
576struct sll2_header {
577 uint16_t sll2_protocol; /* protocol */
578 uint16_t sll2_reserved_mbz; /* reserved - must be zero */
579 uint32_t sll2_if_index; /* 1-based interface index */
580 uint16_t sll2_hatype; /* link-layer address type */
581 uint8_t sll2_pkttype; /* packet type */
582 uint8_t sll2_halen; /* link-layer address length */
583 uint8_t sll2_addr[SLL_ADDRLEN8]; /* link-layer address */
584};
585
586#define VLAN_SIZE4 4
587static void
588sll_remove_vlan_info(uint8_t* fd, uint32_t* len) {
589 if (pntoh16(fd + offsetof(struct sll_header, sll_protocol)__builtin_offsetof(struct sll_header, sll_protocol)) == ETHERTYPE_VLAN0x8100) {
590 int rest_len;
591 /* point to start of vlan */
592 fd = fd + offsetof(struct sll_header, sll_protocol)__builtin_offsetof(struct sll_header, sll_protocol);
593 /* bytes to read after vlan info */
594 rest_len = *len - (offsetof(struct sll_header, sll_protocol)__builtin_offsetof(struct sll_header, sll_protocol) + VLAN_SIZE4);
595 /* remove vlan info from packet */
596 memmove(fd, fd + VLAN_SIZE4, rest_len);
597 *len -= 4;
598 }
599}
600
601
602
603static void
604sll_set_unused_info(uint8_t* fd) {
605 uint32_t ha_len;
606 ha_len = pntoh16(fd + offsetof(struct sll_header, sll_halen)__builtin_offsetof(struct sll_header, sll_halen));
607
608 if (ha_len < SLL_ADDRLEN8) {
609 int unused;
610 unused = SLL_ADDRLEN8 - ha_len;
611 /* point to end of sll_ddr */
612 fd = fd + offsetof(struct sll_header, sll_addr)__builtin_offsetof(struct sll_header, sll_addr) + ha_len;
613 /* set zeros in the unused data */
614 memset(fd, 0, unused);
615 }
616}
617
618static void
619sll2_set_unused_info(uint8_t* fd) {
620 uint32_t ha_len;
621 ha_len = *(fd + offsetof(struct sll2_header, sll2_halen)__builtin_offsetof(struct sll2_header, sll2_halen));
622
623 if (ha_len < SLL_ADDRLEN8) {
624 int unused;
625 unused = SLL_ADDRLEN8 - ha_len;
626 /* point to end of sll2_addr */
627 fd = fd + offsetof(struct sll2_header, sll2_addr)__builtin_offsetof(struct sll2_header, sll2_addr) + ha_len;
628 /* set zeros in the unused data */
629 memset(fd, 0, unused);
630 }
631}
632
633static void
634remove_vlan_info(wtap_packet_header *phdr, uint8_t* fd) {
635 switch (phdr->pkt_encap) {
636 case WTAP_ENCAP_SLL25:
637 sll_remove_vlan_info(fd, &phdr->caplen);
638 break;
639 default:
640 /* no support for current pkt_encap */
641 break;
642 }
643}
644
645static void
646set_unused_info(const wtap_packet_header *phdr, uint8_t* fd) {
647 switch (phdr->pkt_encap) {
648 case WTAP_ENCAP_SLL25:
649 sll_set_unused_info(fd);
650 break;
651 case WTAP_ENCAP_SLL2210:
652 sll2_set_unused_info(fd);
653 break;
654 default:
655 /* no support for current pkt_encap */
656 break;
657 }
658}
659
660static bool_Bool
661is_duplicate(uint8_t* fd, uint32_t len) {
662 int i;
663 const struct ieee80211_radiotap_header* tap_header;
664
665 /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
666 uint32_t offset = ignored_bytes;
667 uint32_t new_len;
668 uint8_t *new_fd;
669
670 if (len <= ignored_bytes) {
671 offset = 0;
672 }
673
674 /* Get the size of radiotap header and use that as offset (-p option) */
675 if (skip_radiotap == true1) {
676 tap_header = (const struct ieee80211_radiotap_header*)fd;
677 offset = pletoh16(&tap_header->it_len);
678 if (offset >= len)
679 offset = 0;
680 }
681
682 new_fd = &fd[offset];
683 new_len = len - (offset);
684
685 cur_dup_entry++;
686 if (cur_dup_entry >= dup_window)
687 cur_dup_entry = 0;
688
689 /* Calculate our digest */
690 gcry_md_hash_buffer(GCRY_MD_MD5, fd_hash[cur_dup_entry].digest, new_fd, new_len);
691
692 fd_hash[cur_dup_entry].len = len;
693
694 /* Look for duplicates */
695 for (i = 0; i < dup_window; i++) {
696 if (i == cur_dup_entry)
697 continue;
698
699 if (fd_hash[i].len == fd_hash[cur_dup_entry].len
700 && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
701 return true1;
702 }
703 }
704
705 return false0;
706}
707
708static bool_Bool
709is_duplicate_rel_time(uint8_t* fd, uint32_t len, const nstime_t *current) {
710 int i;
711
712 /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
713 uint32_t offset = ignored_bytes;
714 uint32_t new_len;
715 uint8_t *new_fd;
716
717 if (len <= ignored_bytes) {
718 offset = 0;
719 }
720
721 new_fd = &fd[offset];
722 new_len = len - (offset);
723
724 cur_dup_entry++;
725 if (cur_dup_entry >= dup_window)
726 cur_dup_entry = 0;
727
728 /* Calculate our digest */
729 gcry_md_hash_buffer(GCRY_MD_MD5, fd_hash[cur_dup_entry].digest, new_fd, new_len);
730
731 fd_hash[cur_dup_entry].len = len;
732 fd_hash[cur_dup_entry].frame_time.secs = current->secs;
733 fd_hash[cur_dup_entry].frame_time.nsecs = current->nsecs;
734
735 /*
736 * Look for relative time related duplicates.
737 * This is hopefully a reasonably efficient mechanism for
738 * finding duplicates by rel time in the fd_hash[] cache.
739 * We check starting from the most recently added hash
740 * entries and work backwards towards older packets.
741 * This approach allows the dup test to be terminated
742 * when the relative time of a cached entry is found to
743 * be beyond the dup time window.
744 *
745 * Of course this assumes that the input trace file is
746 * "well-formed" in the sense that the packet timestamps are
747 * in strict chronologically increasing order (which is NOT
748 * always the case!!).
749 *
750 * The fd_hash[] table was deliberately created large (1,000,000).
751 * Looking for time related duplicates in large trace files with
752 * non-fractional dup time window values can potentially take
753 * a long time to complete.
754 */
755
756 for (i = cur_dup_entry - 1;; i--) {
757 nstime_t delta;
758 int cmp;
759
760 if (i < 0)
761 i = dup_window - 1;
762
763 if (i == cur_dup_entry) {
764 /*
765 * We've decremented back to where we started.
766 * Check no more!
767 */
768 break;
769 }
770
771 if (nstime_is_unset(&(fd_hash[i].frame_time))) {
772 /*
773 * We've decremented to an unused fd_hash[] entry.
774 * Check no more!
775 */
776 break;
777 }
778
779 nstime_delta(&delta, current, &fd_hash[i].frame_time);
780
781 if (delta.secs < 0 || delta.nsecs < 0) {
782 /*
783 * A negative delta implies that the current packet
784 * has an absolute timestamp less than the cached packet
785 * that it is being compared to. This is NOT a normal
786 * situation since trace files usually have packets in
787 * chronological order (oldest to newest).
788 *
789 * There are several possible ways to deal with this:
790 * 1. 'continue' dup checking with the next cached frame.
791 * 2. 'break' from looking for a duplicate of the current frame.
792 * 3. Take the absolute value of the delta and see if that
793 * falls within the specified dup time window.
794 *
795 * Currently this code does option 1. But it would pretty
796 * easy to add yet-another-editcap-option to select one of
797 * the other behaviors for dealing with out-of-sequence
798 * packets.
799 */
800 continue;
801 }
802
803 cmp = nstime_cmp(&delta, &relative_time_window);
804
805 if (cmp > 0) {
806 /*
807 * The delta time indicates that we are now looking at
808 * cached packets beyond the specified dup time window.
809 * Check no more!
810 */
811 break;
812 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len
813 && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
814 return true1;
815 }
816 }
817
818 return false0;
819}
820
821static void
822mutate_packet_data(wtap_rec *rec, uint8_t *buf, uint32_t change_offset, uint64_t count)
823{
824 uint32_t caplen;
825 unsigned real_data_start = 0;
826
827 caplen = 0;
Value stored to 'caplen' is never read
828
829 switch (rec->rec_type) {
830
831 case REC_TYPE_PACKET0:
832 caplen = rec->rec_header.packet_header.caplen;
833
834 /*
835 * Protect some non-protocol data.
836 * XXX - any reason not to fuzz this part?
837 */
838 if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_CATAPULT_DCT200089)
839 real_data_start = find_dct2000_real_data(buf);
840 break;
841
842 case REC_TYPE_FT_SPECIFIC_EVENT1:
843 case REC_TYPE_FT_SPECIFIC_REPORT2:
844 caplen = rec->rec_header.ft_specific_header.record_len;
845 break;
846
847 case REC_TYPE_SYSCALL3:
848 caplen = rec->rec_header.syscall_header.event_filelen;
849 break;
850
851 case REC_TYPE_SYSTEMD_JOURNAL_EXPORT4:
852 caplen = rec->rec_header.systemd_journal_export_header.record_len;
853 break;
854
855 default:
856 /* We don't mutate anything else. */
857 return;
858 }
859
860 if (change_offset > caplen) {
861 fprintf(stderrstderr, "change offset %u is longer than caplen %u in packet %" PRIu64"l" "u" "\n",
862 change_offset, caplen, count);
863 return;
864 }
865
866 real_data_start += change_offset;
867
868 for (unsigned i = real_data_start; i < caplen; i++) {
869 if (rand() <= err_prob * RAND_MAX2147483647) {
870 int err_type = rand() / (RAND_MAX2147483647 / ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1) + 1);
871
872 if (err_type < ERR_WT_BIT5) {
873 buf[i] ^= 1 << (rand() / (RAND_MAX2147483647 / 8 + 1));
874 err_type = ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1);
875 } else {
876 err_type -= ERR_WT_BYTE5;
877 }
878
879 if (err_type < ERR_WT_BYTE5) {
880 buf[i] = rand() / (RAND_MAX2147483647 / 255 + 1);
881 err_type = ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1);
882 } else {
883 err_type -= ERR_WT_BYTE5;
884 }
885
886 if (err_type < ERR_WT_ALNUM5) {
887 buf[i] = ALNUM_CHARS"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[rand() / (RAND_MAX2147483647 / ALNUM_LEN(sizeof("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
) - 1)
+ 1)];
888 err_type = ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1);
889 } else {
890 err_type -= ERR_WT_ALNUM5;
891 }
892
893 if (err_type < ERR_WT_FMT2) {
894 if (i < caplen - 2)
895 (void) g_strlcpy((char*) &buf[i], "%s", 2);
896 err_type = ERR_WT_TOTAL(5 + 5 + 5 + 2 + 1);
897 } else {
898 err_type -= ERR_WT_FMT2;
899 }
900
901 if (err_type < ERR_WT_AA1) {
902 for (unsigned j = i; j < caplen; j++)
903 buf[j] = 0xAA;
904 i = caplen;
905 }
906 }
907 }
908}
909
910static void
911print_usage(FILE *output)
912{
913 fprintf(output, "\n");
914 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
915 fprintf(output, "\n");
916 fprintf(output, "<infile> and <outfile> must both be present; use '-' for stdin or stdout.\n");
917 fprintf(output, "A single packet or a range of packets can be selected.\n");
918 fprintf(output, "\n");
919 fprintf(output, "Packet selection:\n");
920 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
921 fprintf(output, " -A <start time> only read packets whose timestamp is after (or equal\n");
922 fprintf(output, " to) the given time.\n");
923 fprintf(output, " -B <stop time> only read packets whose timestamp is before the\n");
924 fprintf(output, " given time.\n");
925 fprintf(output, " Time format for -A/-B options is\n");
926 fprintf(output, " YYYY-MM-DDThh:mm:ss[.nnnnnnnnn][Z|+-hh:mm]\n");
927 fprintf(output, " Unix epoch timestamps are also supported.\n");
928 fprintf(output, "\n");
929 fprintf(output, "Duplicate packet removal:\n");
930 fprintf(output, " --novlan remove vlan info from packets before checking for duplicates.\n");
931 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH5);
932 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>.\n");
933 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH1000000);
934 fprintf(output, " NOTE: A <dup window> of 0 with -V (verbose option) is\n");
935 fprintf(output, " useful to print MD5 hashes.\n");
936 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
937 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
938 fprintf(output, " A <dup time window> is specified in relative seconds\n");
939 fprintf(output, " (e.g. 0.000001).\n");
940 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
941 fprintf(output, " other editcap options except -V may not always work as expected.\n");
942 fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n");
943 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
944 fprintf(output, " --skip-radiotap-header skip radiotap header when checking for packet duplicates.\n");
945 fprintf(output, " Useful when processing packets captured by multiple radios\n");
946 fprintf(output, " on the same channel in the vicinity of each other.\n");
947 fprintf(output, " --set-unused set unused byts to zero in sll link addr.\n");
948 fprintf(output, "\n");
949 fprintf(output, "Packet manipulation:\n");
950 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
951 fprintf(output, " -C [offset:]<choplen> chop each packet by <choplen> bytes. Positive values\n");
952 fprintf(output, " chop at the packet beginning, negative values at the\n");
953 fprintf(output, " packet end. If an optional offset precedes the length,\n");
954 fprintf(output, " then the bytes chopped will be offset from that value.\n");
955 fprintf(output, " Positive offsets are from the packet beginning,\n");
956 fprintf(output, " negative offsets are from the packet end. You can use\n");
957 fprintf(output, " this option more than once, allowing up to 2 chopping\n");
958 fprintf(output, " regions within a packet provided that at least 1\n");
959 fprintf(output, " choplen is positive and at least 1 is negative.\n");
960 fprintf(output, " -L adjust the frame (i.e. reported) length when chopping\n");
961 fprintf(output, " and/or snapping.\n");
962 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet.\n");
963 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
964 fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to ensure\n");
965 fprintf(output, " strict chronological increasing order. The <strict\n");
966 fprintf(output, " adjustment> is specified in relative seconds with\n");
967 fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n");
968 fprintf(output, " A negative adjustment value will modify timestamps so\n");
969 fprintf(output, " that each packet's delta time is the absolute value\n");
970 fprintf(output, " of the adjustment specified. A value of -0 will set\n");
971 fprintf(output, " all packets to the timestamp of the first packet.\n");
972 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n");
973 fprintf(output, " a particular packet byte will be randomly changed.\n");
974 fprintf(output, " -o <change offset> When used in conjunction with -E, skip some bytes from the\n");
975 fprintf(output, " beginning of the packet. This allows one to preserve some\n");
976 fprintf(output, " bytes, in order to have some headers untouched.\n");
977 fprintf(output, " --seed <seed> When used in conjunction with -E, set the seed to use for\n");
978 fprintf(output, " the pseudo-random number generator. This allows one to\n");
979 fprintf(output, " repeat a particular sequence of errors.\n");
980 fprintf(output, " -I <bytes to ignore> ignore the specified number of bytes at the beginning\n");
981 fprintf(output, " of the frame during MD5 hash calculation, unless the\n");
982 fprintf(output, " frame is too short, then the full frame is used.\n");
983 fprintf(output, " Useful to remove duplicated packets taken on\n");
984 fprintf(output, " several routers (different mac addresses for\n");
985 fprintf(output, " example).\n");
986 fprintf(output, " e.g. -I 26 in case of Ether/IP will ignore\n");
987 fprintf(output, " ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
988 fprintf(output, " -a <framenum>:<comment> Add or replace comment for given frame number\n");
989 fprintf(output, "\n");
990 fprintf(output, "Output File(s):\n");
991 fprintf(output, " if the output file(s) have the .gz extension, then\n");
992 fprintf(output, " gzip compression will be used\n");
993 fprintf(output, " -c <packets per file> split the packet output to different files based on\n");
994 fprintf(output, " uniform packet counts with a maximum of\n");
995 fprintf(output, " <packets per file> each.\n");
996 fprintf(output, " -i <seconds per file> split the packet output to different files based on\n");
997 fprintf(output, " uniform time intervals with a maximum of\n");
998 fprintf(output, " <seconds per file> each.\n");
999 fprintf(output, " -F <capture type> set the output file type; default is pcapng.\n");
1000 fprintf(output, " An empty \"-F\" option will list the file types.\n");
1001 fprintf(output, " -T <encap type> set the output file encapsulation type; default is the\n");
1002 fprintf(output, " same as the input file. An empty \"-T\" option will\n");
1003 fprintf(output, " list the encapsulation types.\n");
1004 fprintf(output, " --inject-secrets <type>,<file> Insert decryption secrets from <file>. List\n");
1005 fprintf(output, " supported secret types with \"--inject-secrets help\".\n");
1006 fprintf(output, " --extract-secrets Extract decryption secrets into the output file instead.\n");
1007 fprintf(output, " Incompatible with other options besides -V.\n");
1008 fprintf(output, " --discard-all-secrets Discard all decryption secrets from the input file\n");
1009 fprintf(output, " when writing the output file. Does not discard\n");
1010 fprintf(output, " secrets added by \"--inject-secrets\" in the same\n");
1011 fprintf(output, " command line.\n");
1012 fprintf(output, " --capture-comment <comment>\n");
1013 fprintf(output, " Add a capture file comment, if supported.\n");
1014 fprintf(output, " --discard-capture-comment\n");
1015 fprintf(output, " Discard capture file comments from the input file\n");
1016 fprintf(output, " when writing the output file. Does not discard\n");
1017 fprintf(output, " comments added by \"--capture-comment\" in the same\n");
1018 fprintf(output, " command line.\n");
1019 fprintf(output, " --discard-packet-comments\n");
1020 fprintf(output, " Discard all packet comments from the input file\n");
1021 fprintf(output, " when writing the output file. Does not discard\n");
1022 fprintf(output, " comments added by \"-a\" in the same command line.\n");
1023 fprintf(output, " --compress <type> Compress the output file using the type compression format.\n");
1024 fprintf(output, "\n");
1025 fprintf(output, "Miscellaneous:\n");
1026 fprintf(output, " -h, --help display this help and exit.\n");
1027 fprintf(output, " -V verbose output.\n");
1028 fprintf(output, " If -V is used with any of the 'Duplicate Packet\n");
1029 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
1030 fprintf(output, " and MD5 hashes are printed to standard-error.\n");
1031 fprintf(output, " -v, --version print version information and exit.\n");
1032}
1033
1034struct string_elem {
1035 const char *sstr; /* The short string */
1036 const char *lstr; /* The long string */
1037};
1038
1039static int
1040string_nat_compare(const void *a, const void *b)
1041{
1042 return ws_ascii_strnatcmp(((const struct string_elem *)a)->sstr,
1043 ((const struct string_elem *)b)->sstr);
1044}
1045
1046static void
1047string_elem_print(void *data, void *stream_ptr)
1048{
1049 fprintf((FILE *) stream_ptr, " %s - %s\n",
1050 ((struct string_elem *)data)->sstr,
1051 ((struct string_elem *)data)->lstr);
1052}
1053
1054static void
1055list_capture_types(FILE *stream) {
1056 GArray *writable_type_subtypes;
1057
1058 fprintf(stream, "editcap: The available capture file types for the \"-F\" flag are:\n");
1059 writable_type_subtypes = wtap_get_writable_file_types_subtypes(FT_SORT_BY_NAME);
1060 for (unsigned i = 0; i < writable_type_subtypes->len; i++) {
1061 int ft = g_array_index(writable_type_subtypes, int, i)(((int*) (void *) (writable_type_subtypes)->data) [(i)]);
1062 fprintf(stream, " %s - %s\n", wtap_file_type_subtype_name(ft),
1063 wtap_file_type_subtype_description(ft));
1064 }
1065 g_array_free(writable_type_subtypes, TRUE(!(0)));
1066}
1067
1068static void
1069list_encap_types(FILE *stream) {
1070 int i;
1071 struct string_elem *encaps;
1072 GSList *list = NULL((void*)0);
1073
1074 encaps = g_new(struct string_elem, WTAP_NUM_ENCAP_TYPES)((struct string_elem *) g_malloc_n ((wtap_get_num_encap_types
()), sizeof (struct string_elem)))
;
1075 fprintf(stream, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
1076 for (i = 0; i < WTAP_NUM_ENCAP_TYPESwtap_get_num_encap_types(); i++) {
1077 encaps[i].sstr = wtap_encap_name(i);
1078 if (encaps[i].sstr != NULL((void*)0)) {
1079 encaps[i].lstr = wtap_encap_description(i);
1080 list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare);
1081 }
1082 }
1083 g_slist_foreach(list, string_elem_print, stream);
1084 g_slist_free(list);
1085 g_free(encaps);
1086}
1087
1088static void
1089list_output_compression_types(void) {
1090 GSList *output_compression_types;
1091
1092 fprintf(stderrstderr, "editcap: The available output compress type(s) for the \"--compress\" flag are:\n");
1093 output_compression_types = wtap_get_all_output_compression_type_names_list();
1094 for (GSList *compression_type = output_compression_types;
1095 compression_type != NULL((void*)0);
1096 compression_type = g_slist_next(compression_type)((compression_type) ? (((GSList *)(compression_type))->next
) : ((void*)0))
) {
1097 fprintf(stderrstderr, " %s\n", (const char *)compression_type->data);
1098 }
1099
1100 g_slist_free(output_compression_types);
1101}
1102
1103static void
1104list_secrets_types(FILE *stream)
1105{
1106 for (unsigned i = 0; i < G_N_ELEMENTS(secrets_types)(sizeof (secrets_types) / sizeof ((secrets_types)[0])); i++) {
1107 fprintf(stream, " %s\n", secrets_types[i].str);
1108 }
1109}
1110
1111static uint32_t
1112lookup_secrets_type(const char *type)
1113{
1114 for (unsigned i = 0; i < G_N_ELEMENTS(secrets_types)(sizeof (secrets_types) / sizeof ((secrets_types)[0])); i++) {
1115 if (!strcmp(secrets_types[i].str, type)) {
1116 return secrets_types[i].id;
1117 }
1118 }
1119 return 0;
1120}
1121
1122static void
1123validate_secrets_file(const char *filename, uint32_t secrets_type, const char *data)
1124{
1125 if (secrets_type == SECRETS_TYPE_TLS0x544c534b) {
1126 /*
1127 * A key log file is unlikely going to look like either:
1128 * - a PEM-encoded private key file.
1129 * - a BER-encoded PKCS #12 file ("PFX file"). (Look for a Constructed
1130 * SEQUENCE tag, e.g. bytes 0x30 which happens to be ASCII '0'.)
1131 */
1132 if (g_str_has_prefix(data, "-----BEGIN ")(__builtin_constant_p ("-----BEGIN ")? __extension__ ({ const
char * const __str = (data); const char * const __prefix = (
"-----BEGIN "); gboolean __result = (0); if (__str == ((void*
)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (
__str, __prefix); else { const size_t __str_len = strlen (((__str
) + !(__str))); const size_t __prefix_len = strlen (((__prefix
) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (data, "-----BEGIN "
) )
|| data[0] == 0x30) {
1133 fprintf(stderrstderr,
1134 "editcap: Warning: \"%s\" is not a key log file, but an unsupported private key file. Decryption will not work.\n",
1135 filename);
1136 }
1137 }
1138}
1139
1140static int
1141framenum_compare(const void *a, const void *b, void *user_data _U___attribute__((unused)))
1142{
1143 uint64_t *frame_a = (uint64_t*)a;
1144 uint64_t *frame_b = (uint64_t*)b;
1145 if (*frame_a < *frame_b)
1146 return -1;
1147
1148 if (*frame_a > *frame_b)
1149 return 1;
1150
1151 return 0;
1152}
1153
1154static wtap_dumper *
1155editcap_dump_open(const char *filename, const wtap_dump_params *params,
1156 GArray *idbs_seen, int *err, char **err_info,
1157 wtap_compression_type compression_type)
1158{
1159 wtap_dumper *pdh;
1160
1161 if (strcmp(filename, "-") == 0) {
1162 /* Write to the standard output. */
1163 pdh = wtap_dump_open_stdout(out_file_type_subtype, compression_type,
1164 params, err, err_info);
1165 } else {
1166 pdh = wtap_dump_open(filename, out_file_type_subtype, compression_type,
1167 params, err, err_info);
1168 }
1169 if (pdh == NULL((void*)0))
1170 return NULL((void*)0);
1171
1172 /*
1173 * If the output file supports identifying the interfaces on which
1174 * packets arrive, add all the IDBs we've seen so far.
1175 *
1176 * That mean that the abstract interface provided by libwiretap
1177 * involves WTAP_BLOCK_IF_ID_AND_INFO blocks.
1178 */
1179 if (wtap_file_type_subtype_supports_block(wtap_dump_file_type_subtype(pdh),
1180 WTAP_BLOCK_IF_ID_AND_INFO) != BLOCK_NOT_SUPPORTED) {
1181 for (unsigned i = 0; i < idbs_seen->len; i++) {
1182 wtap_block_t if_data = g_array_index(idbs_seen, wtap_block_t, i)(((wtap_block_t*) (void *) (idbs_seen)->data) [(i)]);
1183 wtap_block_t if_data_copy;
1184
1185 /*
1186 * Make a copy of this IDB, so that we can change the
1187 * encapsulation type without trashing the original.
1188 */
1189 if_data_copy = wtap_block_make_copy(if_data);
1190
1191 /*
1192 * If an encapsulation type was specified, override the
1193 * encapsulation type of the interface.
1194 */
1195 if (out_frame_type != -2) {
1196 wtapng_if_descr_mandatory_t *if_mand;
1197
1198 if_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(if_data_copy);
1199 if_mand->wtap_encap = out_frame_type;
1200 }
1201
1202 /*
1203 * Add this possibly-modified IDB to the file to which
1204 * we're currently writing.
1205 */
1206 if (!wtap_dump_add_idb(pdh, if_data_copy, err, err_info)) {
1207 int close_err;
1208 char *close_err_info;
1209
1210 wtap_dump_close(pdh, NULL((void*)0), &close_err, &close_err_info);
1211 g_free(close_err_info);
1212 wtap_block_unref(if_data_copy);
1213 return NULL((void*)0);
1214 }
1215
1216 /*
1217 * Release the copy - wtap_dump_add_idb() makes its own copy.
1218 */
1219 wtap_block_unref(if_data_copy);
1220 }
1221 }
1222
1223 return pdh;
1224}
1225
1226static bool_Bool
1227process_new_idbs(wtap *wth, wtap_dumper *pdh, GArray *idbs_seen,
1228 int *err, char **err_info)
1229{
1230 wtap_block_t if_data;
1231
1232 while ((if_data = wtap_get_next_interface_description(wth)) != NULL((void*)0)) {
1233 /*
1234 * Only add interface blocks if the output file supports (meaning
1235 * *requires*) them.
1236 *
1237 * That mean that the abstract interface provided by libwiretap
1238 * involves WTAP_BLOCK_IF_ID_AND_INFO blocks.
1239 */
1240 if (pdh != NULL((void*)0) && wtap_file_type_subtype_supports_block(wtap_dump_file_type_subtype(pdh),
1241 WTAP_BLOCK_IF_ID_AND_INFO) != BLOCK_NOT_SUPPORTED) {
1242 wtap_block_t if_data_copy;
1243
1244 /*
1245 * Make a copy of this IDB, so that we can change the
1246 * encapsulation type without trashing the original.
1247 */
1248 if_data_copy = wtap_block_make_copy(if_data);
1249
1250 /*
1251 * If an encapsulation type was specified, override the
1252 * encapsulation type of the interface.
1253 */
1254 if (out_frame_type != -2) {
1255 wtapng_if_descr_mandatory_t *if_mand;
1256
1257 if_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(if_data_copy);
1258 if_mand->wtap_encap = out_frame_type;
1259 }
1260
1261 /*
1262 * Add this possibly-modified IDB to the file to which
1263 * we're currently writing.
1264 */
1265 if (!wtap_dump_add_idb(pdh, if_data_copy, err, err_info))
1266 return false0;
1267
1268 /*
1269 * Release the copy - wtap_dump_add_idb() makes its own copy.
1270 */
1271 wtap_block_unref(if_data_copy);
1272
1273 /*
1274 * Also add an unmodified copy to the set of IDBs we've seen,
1275 * in case we start writing to another file (which would be
1276 * of the same type as the current file, and thus will also
1277 * require interface IDs).
1278 */
1279 if_data_copy = wtap_block_make_copy(if_data);
1280 g_array_append_val(idbs_seen, if_data_copy)g_array_append_vals (idbs_seen, &(if_data_copy), 1);
1281 }
1282 }
1283 return true1;
1284}
1285
1286static int
1287extract_secrets(wtap *wth, char* filename, int *err, char **err_info)
1288{
1289 wtap_rec read_rec;
1290 int64_t offset;
1291 char *fprefix = NULL((void*)0);
1292 char *fsuffix = NULL((void*)0);
1293
1294 /* Read all of the packets in turn */
1295 wtap_rec_init(&read_rec, 1514);
1296 while (wtap_read(wth, &read_rec, err, err_info, &offset)) {
1297 /* Do we want to respect the max packet number on the command line?
1298 * Probably more confusing than it's worth, because a user might
1299 * not know if a DSB is at the end of the file.
1300 */
1301 wtap_rec_reset(&read_rec);
1302 }
1303 wtap_rec_cleanup(&read_rec);
1304
1305 wtapng_dsb_mandatory_t *dsb;
1306 if (strcmp(filename, "-") == 0) {
1307 /* Sure. Why not. */
1308 for (unsigned dsb_num = 0; dsb_num < wtap_file_get_num_dsbs(wth); ++dsb_num) {
1309 dsb = (wtapng_dsb_mandatory_t *)wtap_block_get_mandatory_data(wtap_file_get_dsb(wth, dsb_num));
1310 if (verbose) {
1311 fprintf(stderrstderr, "Writing secrets type \"%s\" (0x%08x) to standard out.\n",
1312 secrets_type_description(dsb->secrets_type), dsb->secrets_type);
1313 }
1314 if (fwrite(dsb->secrets_data, 1, dsb->secrets_len, stdoutstdout) != dsb->secrets_len) {
1315 return WRITE_ERROR2;
1316 }
1317 }
1318 } else if (wtap_file_get_num_dsbs(wth) == 1) {
1319 dsb = (wtapng_dsb_mandatory_t *)wtap_block_get_mandatory_data(wtap_file_get_dsb(wth, 0));
1320 if (verbose) {
1321 fprintf(stderrstderr, "Writing secrets type \"%s\" (0x%08x) to \"%s\".\n",
1322 secrets_type_description(dsb->secrets_type), dsb->secrets_type,
1323 filename);
1324 }
1325 if (!write_file_binary_mode(filename, dsb->secrets_data, dsb->secrets_len)) {
1326 return WRITE_ERROR2;
1327 }
1328 } else {
1329 /* We have more than one DSB, so write multiple files. While for some
1330 * types, we could combine the information from different DSBs togther
1331 * (and most of those are text-based, so we'd want to write in text
1332 * mode so that the line endings are uniform (which makes testing
1333 * harder), we don't know that for every type.
1334 */
1335 if (!fileset_extract_prefix_suffix(filename, &fprefix, &fsuffix, NULL((void*)0))) {
1336 return CANT_EXTRACT_PREFIX2;
1337 }
1338 char *extract_filename;
1339 for (unsigned dsb_num = 0; dsb_num < wtap_file_get_num_dsbs(wth); ++dsb_num) {
1340 dsb = (wtapng_dsb_mandatory_t *)wtap_block_get_mandatory_data(wtap_file_get_dsb(wth, dsb_num));
1341 extract_filename = fileset_get_filename_by_pattern(dsb_num, NULL((void*)0), fprefix, fsuffix);
1342 if (verbose) {
1343 fprintf(stderrstderr, "Writing secrets type \"%s\" (0x%08x) to \"%s\".\n",
1344 secrets_type_description(dsb->secrets_type), dsb->secrets_type,
1345 extract_filename);
1346 }
1347 if (!write_file_binary_mode(extract_filename, dsb->secrets_data, dsb->secrets_len)) {
1348 /* write_file_binary_mode already reports failures */
1349 g_free(extract_filename);
1350 g_free(fprefix);
1351 g_free(fsuffix);
1352
1353 return WRITE_ERROR2;
1354 }
1355 g_free(extract_filename);
1356 }
1357 g_free(fprefix);
1358 g_free(fsuffix);
1359 }
1360 return EXIT_SUCCESS0;
1361}
1362
1363int
1364main(int argc, char *argv[])
1365{
1366 char *configuration_init_error;
1367 wtap *wth = NULL((void*)0);
1368 int i, read_err, write_err;
1369 char *read_err_info, *write_err_info;
1370 int opt;
1371
1372#define LONGOPT_NO_VLAN3000 +1 LONGOPT_BASE_APPLICATION3000+1
1373#define LONGOPT_SKIP_RADIOTAP_HEADER3000 +2 LONGOPT_BASE_APPLICATION3000+2
1374#define LONGOPT_SEED3000 +3 LONGOPT_BASE_APPLICATION3000+3
1375#define LONGOPT_INJECT_SECRETS3000 +4 LONGOPT_BASE_APPLICATION3000+4
1376#define LONGOPT_DISCARD_ALL_SECRETS3000 +5 LONGOPT_BASE_APPLICATION3000+5
1377#define LONGOPT_CAPTURE_COMMENT3000 +6 LONGOPT_BASE_APPLICATION3000+6
1378#define LONGOPT_DISCARD_CAPTURE_COMMENT3000 +7 LONGOPT_BASE_APPLICATION3000+7
1379#define LONGOPT_SET_UNUSED3000 +8 LONGOPT_BASE_APPLICATION3000+8
1380#define LONGOPT_DISCARD_PACKET_COMMENTS3000 +9 LONGOPT_BASE_APPLICATION3000+9
1381#define LONGOPT_EXTRACT_SECRETS3000 +10 LONGOPT_BASE_APPLICATION3000+10
1382#define LONGOPT_COMPRESS3000 +11 LONGOPT_BASE_APPLICATION3000+11
1383
1384 static const struct ws_option long_options[] = {
1385 {"novlan", ws_no_argument0, NULL((void*)0), LONGOPT_NO_VLAN3000 +1},
1386 {"skip-radiotap-header", ws_no_argument0, NULL((void*)0), LONGOPT_SKIP_RADIOTAP_HEADER3000 +2},
1387 {"seed", ws_required_argument1, NULL((void*)0), LONGOPT_SEED3000 +3},
1388 {"inject-secrets", ws_required_argument1, NULL((void*)0), LONGOPT_INJECT_SECRETS3000 +4},
1389 {"discard-all-secrets", ws_no_argument0, NULL((void*)0), LONGOPT_DISCARD_ALL_SECRETS3000 +5},
1390 {"help", ws_no_argument0, NULL((void*)0), 'h'},
1391 {"version", ws_no_argument0, NULL((void*)0), 'v'},
1392 {"capture-comment", ws_required_argument1, NULL((void*)0), LONGOPT_CAPTURE_COMMENT3000 +6},
1393 {"discard-capture-comment", ws_no_argument0, NULL((void*)0), LONGOPT_DISCARD_CAPTURE_COMMENT3000 +7},
1394 {"set-unused", ws_no_argument0, NULL((void*)0), LONGOPT_SET_UNUSED3000 +8},
1395 {"discard-packet-comments", ws_no_argument0, NULL((void*)0), LONGOPT_DISCARD_PACKET_COMMENTS3000 +9},
1396 {"extract-secrets", ws_no_argument0, NULL((void*)0), LONGOPT_EXTRACT_SECRETS3000 +10},
1397 {"compress", ws_required_argument1, NULL((void*)0), LONGOPT_COMPRESS3000 +11},
1398 {0, 0, 0, 0 }
1399 };
1400
1401 char *p;
1402 uint32_t snaplen = 0; /* No limit */
1403 chop_t chop = {0, 0, 0, 0, 0, 0}; /* No chop */
1404 bool_Bool adjlen = false0;
1405 wtap_dumper *pdh = NULL((void*)0);
1406 GArray *idbs_seen = NULL((void*)0);
1407 uint64_t count = 1;
1408 uint64_t duplicate_count = 0;
1409 int64_t data_offset;
1410 uint8_t *buf;
1411 uint64_t read_count = 0;
1412 uint64_t split_packet_count = 0;
1413 uint64_t written_count = 0;
1414 char *filename = NULL((void*)0);
1415 bool_Bool ts_okay;
1416 nstime_t secs_per_block = NSTIME_INIT_UNSET{0, 2147483647};
1417 int block_cnt = 0;
1418 nstime_t block_next = NSTIME_INIT_UNSET{0, 2147483647};
1419 char *fprefix = NULL((void*)0);
1420 char *fsuffix = NULL((void*)0);
1421 uint32_t change_offset = 0;
1422 uint64_t max_packet_number = 0;
1423 GArray *dsb_types = NULL((void*)0);
1424 GPtrArray *dsb_filenames = NULL((void*)0);
1425 wtap_rec read_rec;
1426 wtap_dump_params params = WTAP_DUMP_PARAMS_INIT{.snaplen=0};
1427 char *shb_user_appl;
1428 int ret = EXIT_SUCCESS0;
1429 bool_Bool valid_seed = false0;
1430 unsigned int seed = 0;
1431 bool_Bool edit_option_specified = false0;
1432 wtap_compression_type compression_type = WTAP_UNKNOWN_COMPRESSION;
1433
1434 /* Set the program name. */
1435 g_set_prgname("editcap");
1436
1437 cmdarg_err_init(stderr_cmdarg_err, stderr_cmdarg_err_cont);
1438 memset(&read_rec, 0, sizeof read_rec);
1439
1440 /* Initialize log handler early so we can have proper logging during startup. */
1441 ws_log_init(vcmdarg_err);
1442
1443 /* Early logging command-line initialization. */
1444 ws_log_parse_args(&argc, argv, vcmdarg_err, WS_EXIT_INVALID_OPTION1);
1445
1446 ws_noisy("Finished log init and parsing command line log arguments")do { if (1) { ws_log_full("Main", LOG_LEVEL_NOISY, "editcap.c"
, 1446, __func__, "Finished log init and parsing command line log arguments"
); } } while (0)
;
1447
1448#ifdef _WIN32
1449 create_app_running_mutex();
1450#endif /* _WIN32 */
1451
1452 /*
1453 * Get credential information for later use.
1454 */
1455 init_process_policies();
1456
1457 /*
1458 * Attempt to get the pathname of the directory containing the
1459 * executable file.
1460 */
1461 configuration_init_error = configuration_init(argv[0]);
1462 if (configuration_init_error != NULL((void*)0)) {
1463 cmdarg_err("Can't get pathname of directory containing the editcap program: %s.",
1464 configuration_init_error);
1465 g_free(configuration_init_error);
1466 }
1467
1468 /* Initialize the version information. */
1469 ws_init_version_info("Editcap", NULL((void*)0), NULL((void*)0));
1470
1471 init_report_failure_message("editcap");
1472
1473 wtap_init(true1);
1474
1475 /* Process the options */
1476 while ((opt = ws_getopt_long(argc, argv, "a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL((void*)0))) != -1) {
1477 if (opt != LONGOPT_EXTRACT_SECRETS3000 +10 && opt != 'V') {
1478 edit_option_specified = true1;
1479 }
1480 switch (opt) {
1481 case LONGOPT_NO_VLAN3000 +1:
1482 {
1483 rem_vlan = true1;
1484 break;
1485 }
1486
1487 case LONGOPT_SKIP_RADIOTAP_HEADER3000 +2:
1488 {
1489 skip_radiotap = true1;
1490 break;
1491 }
1492
1493 case LONGOPT_SEED3000 +3:
1494 {
1495 if (sscanf(ws_optarg, "%u", &seed) != 1) {
1496 cmdarg_err("\"%s\" isn't a valid seed", ws_optarg);
1497 ret = WS_EXIT_INVALID_OPTION1;
1498 goto clean_exit;
1499 }
1500 valid_seed = true1;
1501 break;
1502 }
1503
1504 case LONGOPT_INJECT_SECRETS3000 +4:
1505 {
1506 uint32_t secrets_type_id = 0;
1507 const char *secrets_filename = NULL((void*)0);
1508 if (strcmp("help", ws_optarg) == 0) {
1509 list_secrets_types(stdoutstdout);
1510 goto clean_exit;
1511 }
1512 char **splitted = g_strsplit(ws_optarg, ",", 2);
1513 if (splitted[0] && splitted[0][0] != '\0') {
1514 secrets_type_id = lookup_secrets_type(splitted[0]);
1515 if (secrets_type_id == 0) {
1516 cmdarg_err("\"%s\" isn't a valid secrets type", splitted[0]);
1517 g_strfreev(splitted);
1518 ret = WS_EXIT_INVALID_OPTION1;
1519 goto clean_exit;
1520 }
1521 secrets_filename = splitted[1];
1522 } else {
1523 cmdarg_err("no secrets type was specified for --inject-secrets");
1524 g_strfreev(splitted);
1525 ret = WS_EXIT_INVALID_OPTION1;
1526 goto clean_exit;
1527 }
1528 if (!dsb_filenames) {
1529 dsb_types = g_array_new(FALSE(0), FALSE(0), sizeof(uint32_t));
1530 dsb_filenames = g_ptr_array_new_with_free_func(g_free);
1531 }
1532 g_array_append_val(dsb_types, secrets_type_id)g_array_append_vals (dsb_types, &(secrets_type_id), 1);
1533 g_ptr_array_add(dsb_filenames, g_strdup(secrets_filename)g_strdup_inline (secrets_filename));
1534 g_strfreev(splitted);
1535 break;
1536 }
1537
1538 case LONGOPT_DISCARD_ALL_SECRETS3000 +5:
1539 {
1540 discard_all_secrets = true1;
1541 break;
1542 }
1543
1544 case LONGOPT_CAPTURE_COMMENT3000 +6:
1545 {
1546 /*
1547 * Make sure this would fit in a pcapng option.
1548 *
1549 * XXX - 65535 is the maximum size for an option in pcapng;
1550 * what if another capture file format supports larger
1551 * comments?
1552 */
1553 if (strlen(ws_optarg) > 65535) {
1554 /* It doesn't fit. Tell the user and give up. */
1555 cmdarg_err("Capture comment %u is too large to save in a capture file.",
1556 capture_comments->len + 1);
1557 ret = WS_EXIT_INVALID_OPTION1;
1558 goto clean_exit;
1559 }
1560
1561 /* pcapng supports multiple comments, so support them here too.
1562 */
1563 if (!capture_comments) {
1564 capture_comments = g_ptr_array_new_with_free_func(g_free);
1565 }
1566 g_ptr_array_add(capture_comments, g_strdup(ws_optarg)g_strdup_inline (ws_optarg));
1567 break;
1568 }
1569
1570 case LONGOPT_DISCARD_CAPTURE_COMMENT3000 +7:
1571 {
1572 discard_cap_comments = true1;
1573 break;
1574 }
1575
1576 case LONGOPT_SET_UNUSED3000 +8:
1577 {
1578 set_unused = true1;
1579 break;
1580 }
1581
1582 case LONGOPT_DISCARD_PACKET_COMMENTS3000 +9:
1583 {
1584 discard_pkt_comments = true1;
1585 break;
1586 }
1587
1588 case LONGOPT_EXTRACT_SECRETS3000 +10:
1589 {
1590 do_extract_secrets = true1;
1591 /* XXX - Would it make sense to specify what types of secrets
1592 * to extract (or any)?
1593 */
1594 break;
1595 }
1596
1597 case LONGOPT_COMPRESS3000 +11:
1598 {
1599 compression_type = wtap_name_to_compression_type(ws_optarg);
1600 if (compression_type == WTAP_UNKNOWN_COMPRESSION) {
1601 cmdarg_err("\"%s\" isn't a valid output compression mode",
1602 ws_optarg);
1603 list_output_compression_types();
1604 goto clean_exit;
1605 }
1606 break;
1607 }
1608
1609 case 'a':
1610 {
1611 uint64_t frame_number;
1612 int string_start_index = 0;
1613
1614 if ((sscanf(ws_optarg, "%" SCNu64"l" "u" ":%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) {
1615 cmdarg_err("\"%s\" isn't a valid <frame>:<comment>", ws_optarg);
1616 ret = WS_EXIT_INVALID_OPTION1;
1617 goto clean_exit;
1618 }
1619
1620 /*
1621 * Make sure this would fit in a pcapng option.
1622 *
1623 * XXX - 65535 is the maximum size for an option in pcapng;
1624 * what if another capture file format supports larger
1625 * comments?
1626 */
1627 if (strlen(ws_optarg+string_start_index) > 65535) {
1628 /* It doesn't fit. Tell the user and give up. */
1629 cmdarg_err("A comment for frame %" PRIu64"l" "u" " is too large to save in a capture file.",
1630 frame_number);
1631 ret = WS_EXIT_INVALID_OPTION1;
1632 goto clean_exit;
1633 }
1634
1635 /* Lazily create the table */
1636 if (!frames_user_comments) {
1637 frames_user_comments = g_tree_new_full(framenum_compare, NULL((void*)0), g_free, g_free);
1638 }
1639
1640 /* Insert this entry (framenum -> comment) */
1641 uint64_t *frame_p = g_new(uint64_t, 1)((uint64_t *) g_malloc_n ((1), sizeof (uint64_t)));
1642 *frame_p = frame_number;
1643 g_tree_replace(frames_user_comments, frame_p, g_strdup(ws_optarg+string_start_index)g_strdup_inline (ws_optarg+string_start_index));
1644 break;
1645 }
1646
1647 case 'A':
1648 case 'B':
1649 {
1650 nstime_t in_time;
1651
1652 check_startstop = true1;
1653 if ((NULL((void*)0) != iso8601_to_nstime(&in_time, ws_optarg, ISO8601_DATETIME)) || (NULL((void*)0) != unix_epoch_to_nstime(&in_time, ws_optarg))) {
1654 if (opt == 'A') {
1655 nstime_copy(&starttime, &in_time);
1656 have_starttime = true1;
1657 } else {
1658 nstime_copy(&stoptime, &in_time);
1659 have_stoptime = true1;
1660 }
1661 break;
1662 }
1663 else {
1664 cmdarg_err("\"%s\" isn't a valid date and time", ws_optarg);
1665 ret = WS_EXIT_INVALID_OPTION1;
1666 goto clean_exit;
1667 }
1668 }
1669
1670 case 'c':
1671 split_packet_count = get_nonzero_uint64(ws_optarg, "packet count");
1672 break;
1673
1674 case 'C':
1675 {
1676 int choplen = 0, chopoff = 0;
1677
1678 switch (sscanf(ws_optarg, "%d:%d", &chopoff, &choplen)) {
1679 case 1: /* only the chop length was specified */
1680 choplen = chopoff;
1681 chopoff = 0;
1682 break;
1683
1684 case 2: /* both an offset and chop length was specified */
1685 break;
1686
1687 default:
1688 cmdarg_err("\"%s\" isn't a valid chop length or offset:length", ws_optarg);
1689 ret = WS_EXIT_INVALID_OPTION1;
1690 goto clean_exit;
1691 break;
1692 }
1693
1694 if (choplen > 0) {
1695 chop.len_begin += choplen;
1696 if (chopoff > 0)
1697 chop.off_begin_pos += chopoff;
1698 else
1699 chop.off_begin_neg += chopoff;
1700 } else if (choplen < 0) {
1701 chop.len_end += choplen;
1702 if (chopoff > 0)
1703 chop.off_end_pos += chopoff;
1704 else
1705 chop.off_end_neg += chopoff;
1706 }
1707 break;
1708 }
1709
1710 case 'd':
1711 dup_detect = true1;
1712 dup_detect_by_time = false0;
1713 dup_window = DEFAULT_DUP_DEPTH5;
1714 break;
1715
1716 case 'D':
1717 dup_detect = true1;
1718 dup_detect_by_time = false0;
1719 dup_window = get_uint32(ws_optarg, "duplicate window");
1720 if (dup_window > MAX_DUP_DEPTH1000000) {
1721 cmdarg_err("\"%d\" duplicate window value must be between 0 and %d inclusive.",
1722 dup_window, MAX_DUP_DEPTH1000000);
1723 ret = WS_EXIT_INVALID_OPTION1;
1724 goto clean_exit;
1725 }
1726 break;
1727
1728 case 'E':
1729 err_prob = g_ascii_strtod(ws_optarg, &p);
1730 if (p == ws_optarg || err_prob < 0.0 || err_prob > 1.0) {
1731 cmdarg_err("probability \"%s\" must be between 0.0 and 1.0", ws_optarg);
1732 ret = WS_EXIT_INVALID_OPTION1;
1733 goto clean_exit;
1734 }
1735 break;
1736
1737 case 'F':
1738 out_file_type_subtype = wtap_name_to_file_type_subtype(ws_optarg);
1739 if (out_file_type_subtype < 0) {
1740 cmdarg_err("\"%s\" isn't a valid capture file type\n", ws_optarg);
1741 list_capture_types(stderrstderr);
1742 ret = WS_EXIT_INVALID_OPTION1;
1743 goto clean_exit;
1744 }
1745 break;
1746
1747 case 'h':
1748 show_help_header("Edit and/or translate the format of capture files.");
1749 print_usage(stdoutstdout);
1750 goto clean_exit;
1751 break;
1752
1753 case 'i': /* break capture file based on time interval */
1754 {
1755 double spb = get_positive_double(ws_optarg, "time interval");
1756 if (spb == 0.0) {
1757 cmdarg_err("The specified interval is zero");
1758 ret = WS_EXIT_INVALID_OPTION1;
1759 goto clean_exit;
1760 }
1761
1762 double spb_int, spb_frac;
1763 spb_frac = modf(spb, &spb_int);
1764 secs_per_block.secs = (time_t) spb_int;
1765 secs_per_block.nsecs = (int) (NANOSECS_PER_SEC1000000000 * spb_frac);
1766 }
1767 break;
1768
1769 case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
1770 ignored_bytes = get_uint32(ws_optarg, "number of bytes to ignore");
1771 break;
1772
1773 case 'L':
1774 adjlen = true1;
1775 break;
1776
1777 case 'o':
1778 change_offset = get_uint32(ws_optarg, "change offset");
1779 break;
1780
1781 case 'r':
1782 if (keep_em) {
1783 cmdarg_err("-r was specified twice");
1784 ret = WS_EXIT_INVALID_OPTION1;
1785 goto clean_exit;
1786 }
1787 keep_em = true1;
1788 break;
1789
1790 case 's':
1791 snaplen = get_nonzero_uint32(ws_optarg, "snapshot length");
1792 break;
1793
1794 case 'S':
1795 if (!set_strict_time_adj(ws_optarg)) {
1796 ret = WS_EXIT_INVALID_OPTION1;
1797 goto clean_exit;
1798 }
1799 do_strict_time_adjustment = true1;
1800 break;
1801
1802 case 't':
1803 if (!set_time_adjustment(ws_optarg)) {
1804 ret = WS_EXIT_INVALID_OPTION1;
1805 goto clean_exit;
1806 }
1807 break;
1808
1809 case 'T':
1810 out_frame_type = wtap_name_to_encap(ws_optarg);
1811 if (out_frame_type < 0) {
1812 cmdarg_err("\"%s\" isn't a valid encapsulation type\n", ws_optarg);
1813 list_encap_types(stderrstderr);
1814 ret = WS_EXIT_INVALID_OPTION1;
1815 goto clean_exit;
1816 }
1817 break;
1818
1819 case 'V':
1820 if (verbose) {
1821 cmdarg_err("-V was specified twice");
1822 ret = WS_EXIT_INVALID_OPTION1;
1823 goto clean_exit;
1824 }
1825 verbose = true1;
1826 break;
1827
1828 case 'v':
1829 show_version();
1830 goto clean_exit;
1831 break;
1832
1833 case 'w':
1834 dup_detect = false0;
1835 dup_detect_by_time = true1;
1836 dup_window = MAX_DUP_DEPTH1000000;
1837 if (!set_rel_time(ws_optarg)) {
1838 ret = WS_EXIT_INVALID_OPTION1;
1839 goto clean_exit;
1840 }
1841 break;
1842
1843 case '?': /* Bad options - print usage */
1844 default:
1845 switch(ws_optopt) {
1846 case'F':
1847 list_capture_types(stdoutstdout);
1848 break;
1849 case'T':
1850 list_encap_types(stdoutstdout);
1851 break;
1852 case LONGOPT_COMPRESS3000 +11:
1853 list_output_compression_types();
1854 break;
1855 default:
1856 print_usage(stderrstderr);
1857 ret = WS_EXIT_INVALID_OPTION1;
1858 break;
1859 }
1860 goto clean_exit;
1861 break;
1862 }
1863 } /* processing command-line options */
1864
1865#ifdef DEBUG
1866 fprintf(stderrstderr, "Optind = %i, argc = %i\n", ws_optind, argc);
1867#endif
1868
1869 if ((argc - ws_optind) < 2) {
1870 print_usage(stderrstderr);
1871 ret = WS_EXIT_INVALID_OPTION1;
1872 goto clean_exit;
1873 }
1874
1875 if (out_file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN-1) {
1876 /* default to pcapng */
1877 out_file_type_subtype = wtap_pcapng_file_type_subtype();
1878 }
1879
1880 if (split_packet_count != 0 || !nstime_is_unset(&secs_per_block)) {
1881 if (!fileset_extract_prefix_suffix(argv[ws_optind+1], &fprefix, &fsuffix, &compression_type)) {
1882 ret = CANT_EXTRACT_PREFIX2;
1883 goto clean_exit;
1884 }
1885 } else if (compression_type == WTAP_UNKNOWN_COMPRESSION) {
1886 /* An explicitly specified compression type overrides filename
1887 * magic. (Should we allow specifying "no" compression with, e.g.
1888 * a ".gz" extension?) */
1889 const char *sfx = strrchr(argv[ws_optind+1], '.');
1890 if (sfx) {
1891 compression_type = wtap_extension_to_compression_type(sfx + 1);
1892 }
1893 }
1894
1895 if (compression_type == WTAP_UNKNOWN_COMPRESSION) {
1896 compression_type = WTAP_UNCOMPRESSED;
1897 }
1898
1899 if (!wtap_can_write_compression_type(compression_type)) {
1900 cmdarg_err("Output files can't be written as %s",
1901 wtap_compression_type_description(compression_type));
1902 ret = WS_EXIT_INVALID_OPTION1;
1903 goto clean_exit;
1904 }
1905
1906 if (compression_type != WTAP_UNCOMPRESSED && !wtap_dump_can_compress(out_file_type_subtype)) {
1907 cmdarg_err("The file format %s can't be written to output compressed format",
1908 wtap_file_type_subtype_name(out_file_type_subtype));
1909 ret = WS_EXIT_INVALID_OPTION1;
1910 goto clean_exit;
1911 }
1912
1913 if (err_prob >= 0.0) {
1914 if (!valid_seed) {
1915 seed = (unsigned int) (time(NULL((void*)0)) + ws_getpidgetpid());
1916 }
1917 if (verbose) {
1918 fprintf(stderrstderr, "Using seed %u\n", seed);
1919 }
1920 srand(seed);
1921 }
1922
1923 if (have_starttime && have_stoptime &&
1924 nstime_cmp(&starttime, &stoptime) > 0) {
1925 cmdarg_err("start time is after the stop time");
1926 ret = WS_EXIT_INVALID_OPTION1;
1927 goto clean_exit;
1928 }
1929
1930 if (split_packet_count != 0 && !nstime_is_unset(&secs_per_block)) {
1931 cmdarg_err("can't split on both packet count and time interval");
1932 cmdarg_err_cont("at the same time");
1933 ret = WS_EXIT_INVALID_OPTION1;
1934 goto clean_exit;
1935 }
1936
1937 wth = wtap_open_offline(argv[ws_optind], WTAP_TYPE_AUTO0, &read_err, &read_err_info, false0);
1938
1939 if (!wth) {
1940 cfile_open_failure_message(argv[ws_optind], read_err, read_err_info);
1941 ret = WS_EXIT_INVALID_FILE3;
1942 goto clean_exit;
1943 }
1944
1945 if (verbose) {
1946 fprintf(stderrstderr, "File %s is a %s capture file.\n", argv[ws_optind],
1947 wtap_file_type_subtype_description(wtap_file_type_subtype(wth)));
1948 }
1949
1950 if (skip_radiotap) {
1951 if (ignored_bytes != 0) {
1952 cmdarg_err("can't skip radiotap headers and %d byte(s)", ignored_bytes);
1953 cmdarg_err_cont("at the start of packet at the same time");
1954 ret = WS_EXIT_INVALID_OPTION1;
1955 goto clean_exit;
1956 }
1957
1958 if (wtap_file_encap(wth) != WTAP_ENCAP_IEEE_802_11_RADIOTAP23) {
1959 cmdarg_err("can't skip radiotap header because input file has non-radiotap packets");
1960 if (wtap_file_encap(wth) == WTAP_ENCAP_PER_PACKET-1) {
1961 cmdarg_err_cont("expected '%s', not all packets are necessarily that type",
1962 wtap_encap_description(WTAP_ENCAP_IEEE_802_11_RADIOTAP23));
1963 } else {
1964 cmdarg_err_cont("expected '%s', packets are '%s'",
1965 wtap_encap_description(WTAP_ENCAP_IEEE_802_11_RADIOTAP23),
1966 wtap_encap_description(wtap_file_encap(wth)));
1967 }
1968 ret = WS_EXIT_INVALID_OPTION1;
1969 goto clean_exit;
1970 }
1971 }
1972
1973 if (do_extract_secrets) {
1974 if (edit_option_specified) {
1975 cmdarg_err("can't extract secrets and use other options at the same time");
1976 ret = WS_EXIT_INVALID_OPTION1;
1977 goto clean_exit;
1978 }
1979 if (compression_type != WTAP_UNCOMPRESSED) {
1980 cmdarg_err("compression isn't supported for extracting secrets");
1981 ret = WS_EXIT_INVALID_OPTION1;
1982 goto clean_exit;
1983 }
1984 ret = extract_secrets(wth, argv[ws_optind+1], &read_err, &read_err_info);
1985
1986 if (read_err != 0) {
1987 /* Print a message noting that the read failed somewhere along the
1988 * line. */
1989 cfile_read_failure_message(argv[ws_optind], read_err, read_err_info);
1990 }
1991 goto clean_exit;
1992 }
1993
1994 wtap_dump_params_init_no_idbs(&params, wth);
1995
1996 /*
1997 * Discard any secrets we read in while opening the file.
1998 */
1999 if (discard_all_secrets) {
2000 wtap_dump_params_discard_decryption_secrets(&params);
2001 }
2002
2003 /*
2004 * Discard capture file comments.
2005 */
2006 if (discard_cap_comments) {
2007 for (unsigned b = 0; b < params.shb_hdrs->len; b++) {
2008 wtap_block_t shb = g_array_index(params.shb_hdrs, wtap_block_t, b)(((wtap_block_t*) (void *) (params.shb_hdrs)->data) [(b)]);
2009 while (WTAP_OPTTYPE_SUCCESS == wtap_block_remove_nth_option_instance(shb, OPT_COMMENT1, 0)) {
2010 ;
2011 }
2012 }
2013 }
2014
2015 /*
2016 * Add new capture file comments.
2017 */
2018 if (capture_comments != NULL((void*)0)) {
2019 for (unsigned b = 0; b < params.shb_hdrs->len; b++) {
2020 wtap_block_t shb = g_array_index(params.shb_hdrs, wtap_block_t, b)(((wtap_block_t*) (void *) (params.shb_hdrs)->data) [(b)]);
2021 for (unsigned c = 0; c < capture_comments->len; c++) {
2022 char *comment = (char *)g_ptr_array_index(capture_comments, c)((capture_comments)->pdata)[c];
2023 wtap_block_add_string_option(shb, OPT_COMMENT1, comment, strlen(comment));
2024 }
2025 }
2026 }
2027
2028 if (dsb_filenames) {
2029 for (unsigned k = 0; k < dsb_filenames->len; k++) {
2030 uint32_t secrets_type_id = g_array_index(dsb_types, uint32_t, k)(((uint32_t*) (void *) (dsb_types)->data) [(k)]);
2031 const char *secrets_filename = (const char *)g_ptr_array_index(dsb_filenames, k)((dsb_filenames)->pdata)[k];
2032 char *data;
2033 size_t data_len;
2034 wtap_block_t block;
2035 wtapng_dsb_mandatory_t *dsb;
2036 GError *err = NULL((void*)0);
2037
2038 if (!g_file_get_contents(secrets_filename, &data, &data_len, &err)) {
2039 cmdarg_err("\"%s\" could not be read: %s", secrets_filename, err->message);
2040 g_clear_error(&err);
2041 ret = WS_EXIT_INVALID_OPTION1;
2042 goto clean_exit;
2043 }
2044 if (data_len == 0) {
2045 cmdarg_err("\"%s\" is an empty file, ignoring", secrets_filename);
2046 g_free(data);
2047 continue;
2048 }
2049 if (data_len >= INT_MAX2147483647) {
2050 cmdarg_err("\"%s\" is too large, ignoring", secrets_filename);
2051 g_free(data);
2052 continue;
2053 }
2054
2055 /* Warn for badly formatted files, but proceed anyway. */
2056 validate_secrets_file(secrets_filename, secrets_type_id, data);
2057
2058 block = wtap_block_create(WTAP_BLOCK_DECRYPTION_SECRETS);
2059 dsb = (wtapng_dsb_mandatory_t *)wtap_block_get_mandatory_data(block);
2060 dsb->secrets_type = secrets_type_id;
2061 dsb->secrets_len = (unsigned)data_len;
2062 dsb->secrets_data = data;
2063 if (params.dsbs_initial == NULL((void*)0)) {
2064 params.dsbs_initial = g_array_new(FALSE(0), FALSE(0), sizeof(wtap_block_t));
2065 }
2066 g_array_append_val(params.dsbs_initial, block)g_array_append_vals (params.dsbs_initial, &(block), 1);
2067 }
2068 }
2069
2070 /*
2071 * If an encapsulation type was specified, override the encapsulation
2072 * type of the input file.
2073 */
2074 if (out_frame_type != -2)
2075 params.encap = out_frame_type;
2076
2077 /*
2078 * If a snapshot length was specified, and it's less than the snapshot
2079 * length of the input file, override the snapshot length of the input
2080 * file.
2081 */
2082 if (snaplen != 0 && snaplen < wtap_snapshot_length(wth))
2083 params.snaplen = snaplen;
2084
2085 /*
2086 * Now process the arguments following the input and output file
2087 * names, if any; they specify packets to include/exclude.
2088 */
2089 for (i = ws_optind + 2; i < argc; i++)
2090 if (add_selection(argv[i], &max_packet_number) == false0)
2091 break;
2092
2093 if (keep_em && max_selected == 0) {
2094 cmdarg_err("must specify packets to keep when using -r");
2095 ret = WS_EXIT_INVALID_OPTION1;
2096 goto clean_exit;
2097 }
2098
2099 if (!keep_em)
2100 max_packet_number = UINT64_MAX(18446744073709551615UL);
2101
2102 if (dup_detect || dup_detect_by_time) {
2103 for (i = 0; i < dup_window; i++) {
2104 memset(&fd_hash[i].digest, 0, 16);
2105 fd_hash[i].len = 0;
2106 nstime_set_unset(&fd_hash[i].frame_time);
2107 }
2108 }
2109
2110 /* Set up an array of all IDBs seen */
2111 idbs_seen = g_array_new(FALSE(0), FALSE(0), sizeof(wtap_block_t));
2112
2113 /* Read all of the packets in turn */
2114 wtap_rec_init(&read_rec, 1514);
2115 while (wtap_read(wth, &read_rec, &read_err, &read_err_info, &data_offset)) {
2116 /*
2117 * XXX - what about non-packet records in the file after this?
2118 * NRBs, DSBs, and ISBs are now written when wtap_dump_close() calls
2119 * pcapng_dump_finish(), and we handle IDBs below, but what about
2120 * custom blocks?
2121 */
2122 if (max_packet_number <= read_count)
2123 break;
2124
2125 read_count++;
2126
2127 /* Extra actions for the first packet */
2128 if (read_count == 1) {
2129 if (split_packet_count != 0 || !nstime_is_unset(&secs_per_block)) {
2130 filename = fileset_get_filename_by_pattern(block_cnt++,
2131 (read_rec.presence_flags & WTAP_HAS_TS0x00000001) ? &read_rec.ts : NULL((void*)0),
2132 fprefix, fsuffix);
2133 } else {
2134 filename = g_strdup(argv[ws_optind+1])g_strdup_inline (argv[ws_optind+1]);
2135 }
2136 ws_assert(filename)do { if ((1) && !(filename)) ws_log_fatal_full("Main"
, LOG_LEVEL_ERROR, "editcap.c", 2136, __func__, "assertion failed: %s"
, "filename"); } while (0)
;
2137
2138 /* If we don't have an application name add one */
2139 if (wtap_block_get_string_option_value(g_array_index(params.shb_hdrs, wtap_block_t, 0)(((wtap_block_t*) (void *) (params.shb_hdrs)->data) [(0)]), OPT_SHB_USERAPPL4, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) {
2140 wtap_block_add_string_option_format(g_array_index(params.shb_hdrs, wtap_block_t, 0)(((wtap_block_t*) (void *) (params.shb_hdrs)->data) [(0)]), OPT_SHB_USERAPPL4, "%s", get_appname_and_version());
2141 }
2142
2143 pdh = editcap_dump_open(filename, &params, idbs_seen, &write_err,
2144 &write_err_info, compression_type);
2145
2146 if (pdh == NULL((void*)0)) {
2147 cfile_dump_open_failure_message(filename,
2148 write_err, write_err_info,
2149 out_file_type_subtype);
2150 ret = WS_EXIT_INVALID_FILE3;
2151 goto clean_exit;
2152 }
2153 } /* first packet only handling */
2154
2155 /*
2156 * Process whatever IDBs we haven't seen yet.
2157 */
2158 if (!process_new_idbs(wth, pdh, idbs_seen, &write_err, &write_err_info)) {
2159 cfile_write_failure_message(argv[ws_optind], filename,
2160 write_err, write_err_info,
2161 read_count,
2162 out_file_type_subtype);
2163 ret = DUMP_ERROR2;
2164
2165 /*
2166 * Close the dump file, but don't report an error
2167 * or set the exit code, as we've already reported
2168 * an error.
2169 */
2170 wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info);
2171 goto clean_exit;
2172 }
2173
2174 buf = ws_buffer_start_ptr(&read_rec.data);
2175
2176 /*
2177 * Not all packets have time stamps. Only process the time
2178 * stamp if we have one.
2179 */
2180 if (read_rec.presence_flags & WTAP_HAS_TS0x00000001) {
2181 if (!nstime_is_unset(&secs_per_block)) {
2182 if (nstime_is_unset(&block_next)) {
2183 block_next = read_rec.ts;
2184 nstime_add(&block_next, &secs_per_block)nstime_sum(&block_next, &block_next, &secs_per_block
)
;
2185 }
2186 while (nstime_cmp(&read_rec.ts, &block_next) > 0) { /* time for the next file */
2187
2188 /* We presumably want to write the DSBs from files given
2189 * on the command line to every file.
2190 */
2191 wtap_block_array_ref(params.dsbs_initial);
2192 if (!wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info)) {
2193 cfile_close_failure_message(filename, write_err,
2194 write_err_info);
2195 ret = WRITE_ERROR2;
2196 goto clean_exit;
2197 }
2198 g_free(filename);
2199 /* Use the interval start time for the filename. */
2200 filename = fileset_get_filename_by_pattern(block_cnt++, &block_next, fprefix, fsuffix);
2201 ws_assert(filename)do { if ((1) && !(filename)) ws_log_fatal_full("Main"
, LOG_LEVEL_ERROR, "editcap.c", 2201, __func__, "assertion failed: %s"
, "filename"); } while (0)
;
2202 nstime_add(&block_next, &secs_per_block)nstime_sum(&block_next, &block_next, &secs_per_block
)
; /* reset for next interval */
2203
2204 if (verbose)
2205 fprintf(stderrstderr, "Continuing writing in file %s\n", filename);
2206
2207 pdh = editcap_dump_open(filename, &params, idbs_seen,
2208 &write_err, &write_err_info, compression_type);
2209
2210 if (pdh == NULL((void*)0)) {
2211 cfile_dump_open_failure_message(filename,
2212 write_err,
2213 write_err_info,
2214 out_file_type_subtype);
2215 ret = WS_EXIT_INVALID_FILE3;
2216 goto clean_exit;
2217 }
2218 }
2219 }
2220 } /* time stamp handling */
2221
2222 if (split_packet_count != 0) {
2223 /* time for the next file? */
2224 if (written_count > 0 && (written_count % split_packet_count) == 0) {
2225
2226 /* We presumably want to write the DSBs from files given
2227 * on the command line to every file.
2228 */
2229 wtap_block_array_ref(params.dsbs_initial);
2230 if (!wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info)) {
2231 cfile_close_failure_message(filename, write_err,
2232 write_err_info);
2233 ret = WRITE_ERROR2;
2234 goto clean_exit;
2235 }
2236
2237 g_free(filename);
2238 filename = fileset_get_filename_by_pattern(block_cnt++,
2239 (read_rec.presence_flags & WTAP_HAS_TS0x00000001) ? &read_rec.ts : NULL((void*)0),
2240 fprefix, fsuffix);
2241 ws_assert(filename)do { if ((1) && !(filename)) ws_log_fatal_full("Main"
, LOG_LEVEL_ERROR, "editcap.c", 2241, __func__, "assertion failed: %s"
, "filename"); } while (0)
;
2242
2243 if (verbose)
2244 fprintf(stderrstderr, "Continuing writing in file %s\n", filename);
2245
2246 pdh = editcap_dump_open(filename, &params, idbs_seen,
2247 &write_err, &write_err_info, compression_type);
2248 if (pdh == NULL((void*)0)) {
2249 cfile_dump_open_failure_message(filename,
2250 write_err, write_err_info,
2251 out_file_type_subtype);
2252 ret = WS_EXIT_INVALID_FILE3;
2253 goto clean_exit;
2254 }
2255 }
2256 } /* split packet handling */
2257
2258 if (check_startstop) {
2259 ts_okay = false0;
2260 /*
2261 * Is the packet in the selected timeframe?
2262 * If the packet has no time stamp, the answer is "no".
2263 */
2264 if (read_rec.presence_flags & WTAP_HAS_TS0x00000001) {
2265 if (have_starttime && have_stoptime) {
2266 ts_okay = nstime_cmp(&read_rec.ts, &starttime) >= 0 &&
2267 nstime_cmp(&read_rec.ts, &stoptime) < 0;
2268 } else if (have_starttime) {
2269 ts_okay = nstime_cmp(&read_rec.ts, &starttime) >= 0;
2270 } else if (have_stoptime) {
2271 ts_okay = nstime_cmp(&read_rec.ts, &stoptime) < 0;
2272 }
2273 }
2274 } else {
2275 /*
2276 * No selected timeframe, so all packets are "in the
2277 * selected timeframe".
2278 */
2279 ts_okay = true1;
2280 }
2281
2282 if (ts_okay && ((!selected(count) && !keep_em)
2283 || (selected(count) && keep_em))) {
2284 /* Write the record, possibly after modifying it. */
2285
2286 if (verbose && !dup_detect && !dup_detect_by_time)
2287 fprintf(stderrstderr, "Packet: %" PRIu64"l" "u" "\n", count);
2288
2289 if (read_rec.presence_flags & WTAP_HAS_TS0x00000001) {
2290 /* Do we adjust timestamps to ensure strict chronological
2291 * order? */
2292 if (do_strict_time_adjustment) {
2293 if (previous_time.secs || previous_time.nsecs) {
2294 if (!strict_time_adj.is_negative) {
2295 nstime_t current;
2296 nstime_t delta;
2297
2298 current = read_rec.ts;
2299
2300 nstime_delta(&delta, &current, &previous_time);
2301
2302 if (delta.secs < 0 || delta.nsecs < 0) {
2303 /*
2304 * A negative delta indicates that the current packet
2305 * has an absolute timestamp less than the previous packet
2306 * that it is being compared to. This is NOT a normal
2307 * situation since trace files usually have packets in
2308 * chronological order (oldest to newest).
2309 */
2310 /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
2311 read_rec.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
2312 read_rec.ts.nsecs = previous_time.nsecs;
2313 if (read_rec.ts.nsecs + strict_time_adj.tv.nsecs >= ONE_BILLION1000000000) {
2314 /* carry */
2315 read_rec.ts.secs++;
2316 read_rec.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION1000000000;
2317 } else {
2318 read_rec.ts.nsecs += strict_time_adj.tv.nsecs;
2319 }
2320 }
2321 } else {
2322 /*
2323 * A negative strict time adjustment is requested.
2324 * Unconditionally set each timestamp to previous
2325 * packet's timestamp plus delta.
2326 */
2327 read_rec.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
2328 read_rec.ts.nsecs = previous_time.nsecs;
2329 if (read_rec.ts.nsecs + strict_time_adj.tv.nsecs >= ONE_BILLION1000000000) {
2330 /* carry */
2331 read_rec.ts.secs++;
2332 read_rec.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION1000000000;
2333 } else {
2334 read_rec.ts.nsecs += strict_time_adj.tv.nsecs;
2335 }
2336 }
2337 }
2338 previous_time = read_rec.ts;
2339 }
2340
2341 if (time_adj.tv.secs != 0) {
2342 if (time_adj.is_negative)
2343 read_rec.ts.secs -= time_adj.tv.secs;
2344 else
2345 read_rec.ts.secs += time_adj.tv.secs;
2346 }
2347
2348 if (time_adj.tv.nsecs != 0) {
2349 if (time_adj.is_negative) { /* subtract */
2350 if (read_rec.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
2351 read_rec.ts.secs--;
2352 read_rec.ts.nsecs += ONE_BILLION1000000000;
2353 }
2354 read_rec.ts.nsecs -= time_adj.tv.nsecs;
2355 } else { /* add */
2356 if (read_rec.ts.nsecs + time_adj.tv.nsecs >= ONE_BILLION1000000000) {
2357 /* carry */
2358 read_rec.ts.secs++;
2359 read_rec.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION1000000000;
2360 } else {
2361 read_rec.ts.nsecs += time_adj.tv.nsecs;
2362 }
2363 }
2364 }
2365 } /* time stamp adjustment */
2366
2367 if (read_rec.rec_type == REC_TYPE_PACKET0) {
2368 if (snaplen != 0) {
2369 /* Limit capture length to snaplen */
2370 if (read_rec.rec_header.packet_header.caplen > snaplen) {
2371 read_rec.rec_header.packet_header.caplen = snaplen;
2372 }
2373 /* If -L, also set reported length to snaplen */
2374 if (adjlen && read_rec.rec_header.packet_header.len > snaplen) {
2375 read_rec.rec_header.packet_header.len = snaplen;
2376 }
2377 }
2378
2379 /*
2380 * If an encapsulation type was specified, override the
2381 * encapsulation type of the packet.
2382 */
2383 if (out_frame_type != -2) {
2384 read_rec.rec_header.packet_header.pkt_encap = out_frame_type;
2385 }
2386
2387 /*
2388 * CHOP
2389 */
2390 handle_chopping(chop, &read_rec.rec_header.packet_header,
2391 &buf, adjlen);
2392
2393 /* set unused info */
2394 if (set_unused) {
2395 /* set unused bytes to zero so that duplicates check ignores unused bytes */
2396 set_unused_info(&read_rec.rec_header.packet_header, buf);
2397 }
2398
2399 /* remove vlan info */
2400 if (rem_vlan) {
2401 remove_vlan_info(&read_rec.rec_header.packet_header, buf);
2402 }
2403
2404 /* suppress duplicates by packet window */
2405 if (dup_detect) {
2406 if (is_duplicate(buf, read_rec.rec_header.packet_header.caplen)) {
2407 if (verbose) {
2408 fprintf(stderrstderr, "Skipped: %" PRIu64"l" "u" ", Len: %u, MD5 Hash: ",
2409 count,
2410 read_rec.rec_header.packet_header.caplen);
2411 for (i = 0; i < 16; i++)
2412 fprintf(stderrstderr, "%02x",
2413 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
2414 fprintf(stderrstderr, "\n");
2415 }
2416 duplicate_count++;
2417 count++;
2418 continue;
2419 } else {
2420 if (verbose) {
2421 fprintf(stderrstderr, "Packet: %" PRIu64"l" "u" ", Len: %u, MD5 Hash: ",
2422 count,
2423 read_rec.rec_header.packet_header.caplen);
2424 for (i = 0; i < 16; i++)
2425 fprintf(stderrstderr, "%02x",
2426 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
2427 fprintf(stderrstderr, "\n");
2428 }
2429 }
2430 } /* suppression of duplicates */
2431
2432 if (read_rec.presence_flags & WTAP_HAS_TS0x00000001) {
2433 /* suppress duplicates by time window */
2434 if (dup_detect_by_time) {
2435 nstime_t current;
2436
2437 current.secs = read_rec.ts.secs;
2438 current.nsecs = read_rec.ts.nsecs;
2439
2440 if (is_duplicate_rel_time(buf,
2441 read_rec.rec_header.packet_header.caplen,
2442 &current)) {
2443 if (verbose) {
2444 fprintf(stderrstderr, "Skipped: %" PRIu64"l" "u" ", Len: %u, MD5 Hash: ",
2445 count,
2446 read_rec.rec_header.packet_header.caplen);
2447 for (i = 0; i < 16; i++)
2448 fprintf(stderrstderr, "%02x",
2449 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
2450 fprintf(stderrstderr, "\n");
2451 }
2452 duplicate_count++;
2453 count++;
2454 continue;
2455 } else {
2456 if (verbose) {
2457 fprintf(stderrstderr, "Packet: %" PRIu64"l" "u" ", Len: %u, MD5 Hash: ",
2458 count,
2459 read_rec.rec_header.packet_header.caplen);
2460 for (i = 0; i < 16; i++)
2461 fprintf(stderrstderr, "%02x",
2462 (unsigned char)fd_hash[cur_dup_entry].digest[i]);
2463 fprintf(stderrstderr, "\n");
2464 }
2465 }
2466 }
2467 } /* suppress duplicates by time window */
2468 }
2469
2470 /* Random error mutation */
2471 if (err_prob > 0.0) {
2472 mutate_packet_data(&read_rec, buf, change_offset, count);
2473 } /* random error mutation */
2474
2475 /* Discard all packet comments when writing */
2476 if (discard_pkt_comments) {
2477 while (WTAP_OPTTYPE_SUCCESS == wtap_block_remove_nth_option_instance(read_rec.block, OPT_COMMENT1, 0)) {
2478 read_rec.block_was_modified = true1;
2479 }
2480 }
2481
2482 /* Find a packet comment we may need to write */
2483 if (frames_user_comments) {
2484 const char *comment =
2485 (const char*)g_tree_lookup(frames_user_comments, &read_count);
2486 if (comment != NULL((void*)0)) {
2487 /* Erase any existing comments before adding the new one */
2488 while (WTAP_OPTTYPE_SUCCESS == wtap_block_remove_nth_option_instance(read_rec.block, OPT_COMMENT1, 0)) {
2489 read_rec.block_was_modified = true1;
2490 }
2491
2492 /* The comment is not modified by dumper, cast away. */
2493 wtap_block_add_string_option(read_rec.block, OPT_COMMENT1, (char *)comment, strlen((char *)comment));
2494 read_rec.block_was_modified = true1;
2495 } else {
2496 read_rec.block_was_modified = false0;
2497 }
2498 }
2499
2500 if (discard_all_secrets) {
2501 /*
2502 * Discard any secrets we've read since the last packet
2503 * we wrote.
2504 */
2505 wtap_dump_discard_decryption_secrets(pdh);
2506 }
2507
2508 /* Attempt to dump out current frame to the output file */
2509 if (!wtap_dump(pdh, &read_rec, buf, &write_err, &write_err_info)) {
2510 cfile_write_failure_message(argv[ws_optind], filename,
2511 write_err, write_err_info,
2512 read_count,
2513 out_file_type_subtype);
2514 ret = DUMP_ERROR2;
2515
2516 /*
2517 * Close the dump file, but don't report an error
2518 * or set the exit code, as we've already reported
2519 * an error.
2520 */
2521 wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info);
2522 goto clean_exit;
2523 }
2524 written_count++;
2525 }
2526 count++;
2527 wtap_rec_reset(&read_rec);
2528 }
2529 wtap_rec_cleanup(&read_rec);
2530
2531 if (verbose)
2532 fprintf(stderrstderr, "Total selected: %" PRIu64"l" "u" "\n", written_count);
2533
2534 if (read_err != 0) {
2535 /* Print a message noting that the read failed somewhere along the
2536 * line. */
2537 cfile_read_failure_message(argv[ws_optind], read_err, read_err_info);
2538 }
2539
2540 if (!pdh) {
2541 /* No valid packets found, open the outfile so we can write an
2542 * empty header */
2543 g_free (filename);
2544 filename = g_strdup(argv[ws_optind+1])g_strdup_inline (argv[ws_optind+1]);
2545
2546 pdh = editcap_dump_open(filename, &params, idbs_seen, &write_err,
2547 &write_err_info, compression_type);
2548 if (pdh == NULL((void*)0)) {
2549 cfile_dump_open_failure_message(filename,
2550 write_err, write_err_info,
2551 out_file_type_subtype);
2552 ret = WS_EXIT_INVALID_FILE3;
2553 goto clean_exit;
2554 }
2555 }
2556
2557 /*
2558 * Process whatever IDBs we haven't seen yet.
2559 */
2560 if (!process_new_idbs(wth, pdh, idbs_seen, &write_err, &write_err_info)) {
2561 cfile_write_failure_message(argv[ws_optind], filename,
2562 write_err, write_err_info,
2563 read_count,
2564 out_file_type_subtype);
2565 ret = DUMP_ERROR2;
2566
2567 /*
2568 * Close the dump file, but don't report an error
2569 * or set the exit code, as we've already reported
2570 * an error.
2571 */
2572 wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info);
2573 goto clean_exit;
2574 }
2575
2576 if (!wtap_dump_close(pdh, NULL((void*)0), &write_err, &write_err_info)) {
2577 cfile_close_failure_message(filename, write_err, write_err_info);
2578 ret = WRITE_ERROR2;
2579 goto clean_exit;
2580 }
2581
2582 if (dup_detect) {
2583 fprintf(stderrstderr, "%" PRIu64"l" "u" " packet%s seen, %" PRIu64"l" "u" " packet%s skipped with duplicate window of %i packets.\n",
2584 count - 1, plurality(count - 1, "", "s")((count - 1) == 1 ? ("") : ("s")), duplicate_count,
2585 plurality(duplicate_count, "", "s")((duplicate_count) == 1 ? ("") : ("s")), dup_window);
2586 } else if (dup_detect_by_time) {
2587 fprintf(stderrstderr, "%" PRIu64"l" "u" " packet%s seen, %" PRIu64"l" "u" " packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
2588 count - 1, plurality(count - 1, "", "s")((count - 1) == 1 ? ("") : ("s")), duplicate_count,
2589 plurality(duplicate_count, "", "s")((duplicate_count) == 1 ? ("") : ("s")),
2590 (long)relative_time_window.secs,
2591 (long int)relative_time_window.nsecs);
2592 }
2593
2594clean_exit:
2595 g_free(fprefix);
2596 g_free(fsuffix);
2597
2598 if (filename) {
2599 g_free(filename);
2600 }
2601 if (frames_user_comments) {
2602 g_tree_destroy(frames_user_comments);
2603 }
2604 if (dsb_filenames) {
2605 g_array_free(dsb_types, TRUE(!(0)));
2606 g_ptr_array_free(dsb_filenames, TRUE(!(0)));
2607 }
2608 if (idbs_seen != NULL((void*)0)) {
2609 for (unsigned b = 0; b < idbs_seen->len; b++) {
2610 wtap_block_t if_data = g_array_index(idbs_seen, wtap_block_t, b)(((wtap_block_t*) (void *) (idbs_seen)->data) [(b)]);
2611 wtap_block_unref(if_data);
2612 }
2613 g_array_free(idbs_seen, TRUE(!(0)));
2614 }
2615 g_free(params.idb_inf);
2616 wtap_dump_params_cleanup(&params);
2617 if (wth != NULL((void*)0))
2618 wtap_close(wth);
2619 wtap_rec_reset(&read_rec);
2620 wtap_cleanup();
2621 free_progdirs();
2622 if (capture_comments != NULL((void*)0)) {
2623 g_ptr_array_free(capture_comments, TRUE(!(0)));
2624 capture_comments = NULL((void*)0);
2625 }
2626 return ret;
2627}
2628
2629/* Skip meta-information read from file to return offset of real
2630 * protocol data */
2631static unsigned
2632find_dct2000_real_data(const uint8_t *buf)
2633{
2634 unsigned n = 0;
2635
2636 for (n = 0; buf[n] != '\0'; n++); /* Context name */
2637 n++;
2638 n++; /* Context port number */
2639 for (; buf[n] != '\0'; n++); /* Timestamp */
2640 n++;
2641 for (; buf[n] != '\0'; n++); /* Protocol name */
2642 n++;
2643 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
2644 n++;
2645 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
2646 n++;
2647 n += 2; /* Direction & encap */
2648
2649 return n;
2650}
2651
2652/*
2653 * We support up to 2 chopping regions in a single pass: one specified by the
2654 * positive chop length, and one by the negative chop length.
2655 */
2656static void
2657handle_chopping(chop_t chop, wtap_packet_header *phdr, uint8_t **buf,
2658 bool_Bool adjlen)
2659{
2660 /* If we're not chopping anything from one side, then the offset for that
2661 * side is meaningless. */
2662 if (chop.len_begin == 0)
2663 chop.off_begin_pos = chop.off_begin_neg = 0;
2664 if (chop.len_end == 0)
2665 chop.off_end_pos = chop.off_end_neg = 0;
2666
2667 if (chop.off_begin_neg < 0) {
2668 chop.off_begin_pos += phdr->caplen + chop.off_begin_neg;
2669 chop.off_begin_neg = 0;
2670 }
2671 if (chop.off_end_pos > 0) {
2672 chop.off_end_neg += chop.off_end_pos - phdr->caplen;
2673 chop.off_end_pos = 0;
2674 }
2675
2676 /* If we've crossed chopping regions, swap them */
2677 if (chop.len_begin && chop.len_end) {
2678 if (chop.off_begin_pos > ((int)phdr->caplen + chop.off_end_neg)) {
2679 int tmp_len, tmp_off;
2680
2681 tmp_off = phdr->caplen + chop.off_end_neg + chop.len_end;
2682 tmp_len = -chop.len_end;
2683
2684 chop.off_end_neg = chop.len_begin + chop.off_begin_pos - phdr->caplen;
2685 chop.len_end = -chop.len_begin;
2686
2687 chop.len_begin = tmp_len;
2688 chop.off_begin_pos = tmp_off;
2689 }
2690 }
2691
2692 /* Make sure we don't chop off more than we have available */
2693 if (phdr->caplen < (uint32_t)(chop.off_begin_pos - chop.off_end_neg)) {
2694 chop.len_begin = 0;
2695 chop.len_end = 0;
2696 }
2697 if ((uint32_t)(chop.len_begin - chop.len_end) >
2698 (phdr->caplen - (uint32_t)(chop.off_begin_pos - chop.off_end_neg))) {
2699 chop.len_begin = phdr->caplen - (chop.off_begin_pos - chop.off_end_neg);
2700 chop.len_end = 0;
2701 }
2702
2703 /* Handle chopping from the beginning. Note that if a beginning offset
2704 * was specified, we need to keep that piece */
2705 if (chop.len_begin > 0) {
2706 if (chop.off_begin_pos > 0) {
2707 memmove(*buf + chop.off_begin_pos,
2708 *buf + chop.off_begin_pos + chop.len_begin,
2709 phdr->caplen - (chop.off_begin_pos + chop.len_begin));
2710 } else {
2711 *buf += chop.len_begin;
2712 }
2713 phdr->caplen -= chop.len_begin;
2714
2715 if (adjlen) {
2716 if (phdr->len > (uint32_t)chop.len_begin)
2717 phdr->len -= chop.len_begin;
2718 else
2719 phdr->len = 0;
2720 }
2721 }
2722
2723 /* Handle chopping from the end. Note that if an ending offset was
2724 * specified, we need to keep that piece */
2725 if (chop.len_end < 0) {
2726 if (chop.off_end_neg < 0) {
2727 memmove(*buf + (int)phdr->caplen + (chop.len_end + chop.off_end_neg),
2728 *buf + (int)phdr->caplen + chop.off_end_neg,
2729 -chop.off_end_neg);
2730 }
2731 phdr->caplen += chop.len_end;
2732
2733 if (adjlen) {
2734 if (((signed int) phdr->len + chop.len_end) > 0)
2735 phdr->len += chop.len_end;
2736 else
2737 phdr->len = 0;
2738 }
2739 }
2740}
2741
2742/*
2743 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2744 *
2745 * Local variables:
2746 * c-basic-offset: 4
2747 * tab-width: 8
2748 * indent-tabs-mode: nil
2749 * End:
2750 *
2751 * vi: set shiftwidth=4 tabstop=8 expandtab:
2752 * :indentSize=4:tabSize=8:noTabs=true:
2753 */