nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 <gerald@wireshark.org> |
||
13 | * Copyright 1998 Gerald Combs |
||
14 | * |
||
15 | * This program is free software; you can redistribute it and/or modify |
||
16 | * it under the terms of the GNU General Public License as published by |
||
17 | * the Free Software Foundation; either version 2 of the License, or |
||
18 | * (at your option) any later version. |
||
19 | * |
||
20 | * This program is distributed in the hope that it will be useful, |
||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
23 | * GNU General Public License for more details. |
||
24 | * |
||
25 | * You should have received a copy of the GNU General Public License along |
||
26 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
27 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
28 | */ |
||
29 | |||
30 | #include <config.h> |
||
31 | |||
32 | #include <stdio.h> |
||
33 | #include <stdlib.h> |
||
34 | #include <string.h> |
||
35 | #include <stdarg.h> |
||
36 | |||
37 | /* |
||
38 | * Just make sure we include the prototype for strptime as well |
||
39 | * (needed for glibc 2.2) but make sure we do this only if not |
||
40 | * yet defined. |
||
41 | */ |
||
42 | |||
43 | #ifndef __USE_XOPEN |
||
44 | # define __USE_XOPEN |
||
45 | #endif |
||
46 | |||
47 | #include <time.h> |
||
48 | #include <glib.h> |
||
49 | |||
50 | #ifdef HAVE_UNISTD_H |
||
51 | #include <unistd.h> |
||
52 | #endif |
||
53 | |||
54 | #ifdef HAVE_GETOPT_H |
||
55 | #include <getopt.h> |
||
56 | #endif |
||
57 | |||
58 | #include <wiretap/wtap.h> |
||
59 | |||
60 | #include "epan/etypes.h" |
||
61 | |||
62 | #ifndef HAVE_GETOPT_LONG |
||
63 | #include "wsutil/wsgetopt.h" |
||
64 | #endif |
||
65 | |||
66 | #ifdef _WIN32 |
||
67 | #include <wsutil/unicode-utils.h> |
||
68 | #include <process.h> /* getpid */ |
||
69 | #ifdef HAVE_WINSOCK2_H |
||
70 | #include <winsock2.h> |
||
71 | #endif |
||
72 | #endif |
||
73 | |||
74 | #ifndef HAVE_STRPTIME |
||
75 | # include "wsutil/strptime.h" |
||
76 | #endif |
||
77 | |||
78 | #include <wsutil/crash_info.h> |
||
79 | #include <wsutil/filesystem.h> |
||
80 | #include <wsutil/file_util.h> |
||
81 | #include <wsutil/md5.h> |
||
82 | #include <wsutil/plugins.h> |
||
83 | #include <wsutil/privileges.h> |
||
84 | #include <wsutil/report_err.h> |
||
85 | #include <wsutil/strnatcmp.h> |
||
86 | #include <wsutil/str_util.h> |
||
87 | #include <ws_version_info.h> |
||
88 | #include <wsutil/pint.h> |
||
89 | #include <wiretap/wtap_opttypes.h> |
||
90 | #include <wiretap/pcapng.h> |
||
91 | |||
92 | #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */ |
||
93 | |||
94 | /* |
||
95 | * Some globals so we can pass things to various routines |
||
96 | */ |
||
97 | |||
98 | struct select_item { |
||
99 | gboolean inclusive; |
||
100 | guint first, second; |
||
101 | }; |
||
102 | |||
103 | /* |
||
104 | * Duplicate frame detection |
||
105 | */ |
||
106 | typedef struct _fd_hash_t { |
||
107 | md5_byte_t digest[16]; |
||
108 | guint32 len; |
||
109 | nstime_t frame_time; |
||
110 | } fd_hash_t; |
||
111 | |||
112 | #define DEFAULT_DUP_DEPTH 5 /* Used with -d */ |
||
113 | #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */ |
||
114 | |||
115 | static fd_hash_t fd_hash[MAX_DUP_DEPTH]; |
||
116 | static int dup_window = DEFAULT_DUP_DEPTH; |
||
117 | static int cur_dup_entry = 0; |
||
118 | |||
119 | static int ignored_bytes = 0; /* Used with -I */ |
||
120 | |||
121 | #define ONE_BILLION 1000000000 |
||
122 | |||
123 | /* Weights of different errors we can introduce */ |
||
124 | /* We should probably make these command-line arguments */ |
||
125 | /* XXX - Should we add a bit-level error? */ |
||
126 | #define ERR_WT_BIT 5 /* Flip a random bit */ |
||
127 | #define ERR_WT_BYTE 5 /* Substitute a random byte */ |
||
128 | #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */ |
||
129 | #define ERR_WT_FMT 2 /* Substitute "%s" */ |
||
130 | #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */ |
||
131 | #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA) |
||
132 | |||
133 | #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" |
||
134 | #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1) |
||
135 | |||
136 | struct time_adjustment { |
||
137 | nstime_t tv; |
||
138 | int is_negative; |
||
139 | }; |
||
140 | |||
141 | typedef struct _chop_t { |
||
142 | int len_begin; |
||
143 | int off_begin_pos; |
||
144 | int off_begin_neg; |
||
145 | int len_end; |
||
146 | int off_end_pos; |
||
147 | int off_end_neg; |
||
148 | } chop_t; |
||
149 | |||
150 | |||
151 | /* Table of user comments */ |
||
152 | GTree *frames_user_comments = NULL; |
||
153 | |||
154 | #define MAX_SELECTIONS 512 |
||
155 | static struct select_item selectfrm[MAX_SELECTIONS]; |
||
156 | static guint max_selected = 0; |
||
157 | static int keep_em = 0; |
||
158 | #ifdef PCAP_NG_DEFAULT |
||
159 | static int out_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; /* default to pcapng */ |
||
160 | #else |
||
161 | static int out_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcap */ |
||
162 | #endif |
||
163 | static int out_frame_type = -2; /* Leave frame type alone */ |
||
164 | static int verbose = 0; /* Not so verbose */ |
||
165 | static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */ |
||
166 | static nstime_t relative_time_window = {0, 0}; /* de-dup time window */ |
||
167 | static double err_prob = 0.0; |
||
168 | static time_t starttime = 0; |
||
169 | static time_t stoptime = 0; |
||
170 | static gboolean check_startstop = FALSE; |
||
171 | static gboolean rem_vlan = FALSE; |
||
172 | static gboolean dup_detect = FALSE; |
||
173 | static gboolean dup_detect_by_time = FALSE; |
||
174 | |||
175 | static int do_strict_time_adjustment = FALSE; |
||
176 | static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */ |
||
177 | static nstime_t previous_time = {0, 0}; /* previous time */ |
||
178 | |||
179 | static int find_dct2000_real_data(guint8 *buf); |
||
180 | static void handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr, |
||
181 | const struct wtap_pkthdr *in_phdr, guint8 **buf, |
||
182 | gboolean adjlen); |
||
183 | |||
184 | static gchar * |
||
185 | abs_time_to_str_with_sec_resolution(const nstime_t *abs_time) |
||
186 | { |
||
187 | struct tm *tmp; |
||
188 | gchar *buf = (gchar *)g_malloc(16); |
||
189 | |||
190 | tmp = localtime(&abs_time->secs); |
||
191 | |||
192 | if (tmp) { |
||
193 | g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d", |
||
194 | tmp->tm_year + 1900, |
||
195 | tmp->tm_mon+1, |
||
196 | tmp->tm_mday, |
||
197 | tmp->tm_hour, |
||
198 | tmp->tm_min, |
||
199 | tmp->tm_sec); |
||
200 | } else { |
||
201 | buf[0] = '\0'; |
||
202 | } |
||
203 | |||
204 | return buf; |
||
205 | } |
||
206 | |||
207 | static gchar * |
||
208 | fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr, |
||
209 | gchar *fprefix, gchar *fsuffix) |
||
210 | { |
||
211 | gchar filenum[5+1]; |
||
212 | gchar *timestr; |
||
213 | gchar *abs_str; |
||
214 | |||
215 | g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES); |
||
216 | if (phdr->presence_flags & WTAP_HAS_TS) { |
||
217 | timestr = abs_time_to_str_with_sec_resolution(&phdr->ts); |
||
218 | abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL); |
||
219 | g_free(timestr); |
||
220 | } else |
||
221 | abs_str = g_strconcat(fprefix, "_", filenum, fsuffix, NULL); |
||
222 | |||
223 | return abs_str; |
||
224 | } |
||
225 | |||
226 | static gboolean |
||
227 | fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix) |
||
228 | { |
||
229 | char *pfx, *last_pathsep; |
||
230 | gchar *save_file; |
||
231 | |||
232 | save_file = g_strdup(fname); |
||
233 | if (save_file == NULL) { |
||
234 | fprintf(stderr, "editcap: Out of memory\n"); |
||
235 | return FALSE; |
||
236 | } |
||
237 | |||
238 | last_pathsep = strrchr(save_file, G_DIR_SEPARATOR); |
||
239 | pfx = strrchr(save_file,'.'); |
||
240 | if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) { |
||
241 | /* The pathname has a "." in it, and it's in the last component |
||
242 | * of the pathname (because there is either only one component, |
||
243 | * i.e. last_pathsep is null as there are no path separators, |
||
244 | * or the "." is after the path separator before the last |
||
245 | * component. |
||
246 | |||
247 | * Treat it as a separator between the rest of the file name and |
||
248 | * the file name suffix, and arrange that the names given to the |
||
249 | * ring buffer files have the specified suffix, i.e. put the |
||
250 | * changing part of the name *before* the suffix. */ |
||
251 | pfx[0] = '\0'; |
||
252 | *fprefix = g_strdup(save_file); |
||
253 | pfx[0] = '.'; /* restore capfile_name */ |
||
254 | *fsuffix = g_strdup(pfx); |
||
255 | } else { |
||
256 | /* Either there's no "." in the pathname, or it's in a directory |
||
257 | * component, so the last component has no suffix. */ |
||
258 | *fprefix = g_strdup(save_file); |
||
259 | *fsuffix = NULL; |
||
260 | } |
||
261 | g_free(save_file); |
||
262 | return TRUE; |
||
263 | } |
||
264 | |||
265 | /* Add a selection item, a simple parser for now */ |
||
266 | static gboolean |
||
267 | add_selection(char *sel, guint* max_selection) |
||
268 | { |
||
269 | char *locn; |
||
270 | char *next; |
||
271 | |||
272 | if (max_selected >= MAX_SELECTIONS) { |
||
273 | /* Let the user know we stopped selecting */ |
||
274 | fprintf(stderr, "Out of room for packet selections!\n"); |
||
275 | return(FALSE); |
||
276 | } |
||
277 | |||
278 | if (verbose) |
||
279 | fprintf(stderr, "Add_Selected: %s\n", sel); |
||
280 | |||
281 | if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */ |
||
282 | if (verbose) |
||
283 | fprintf(stderr, "Not inclusive ..."); |
||
284 | |||
285 | selectfrm[max_selected].inclusive = FALSE; |
||
286 | selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10); |
||
287 | if (selectfrm[max_selected].first > *max_selection) |
||
288 | *max_selection = selectfrm[max_selected].first; |
||
289 | |||
290 | if (verbose) |
||
291 | fprintf(stderr, " %u\n", selectfrm[max_selected].first); |
||
292 | } else { |
||
293 | if (verbose) |
||
294 | fprintf(stderr, "Inclusive ..."); |
||
295 | |||
296 | next = locn + 1; |
||
297 | selectfrm[max_selected].inclusive = TRUE; |
||
298 | selectfrm[max_selected].first = (guint)strtoul(sel, NULL, 10); |
||
299 | selectfrm[max_selected].second = (guint)strtoul(next, NULL, 10); |
||
300 | |||
301 | if (selectfrm[max_selected].second == 0) |
||
302 | { |
||
303 | /* Not a valid number, presume all */ |
||
304 | selectfrm[max_selected].second = *max_selection = G_MAXUINT; |
||
305 | } |
||
306 | else if (selectfrm[max_selected].second > *max_selection) |
||
307 | *max_selection = selectfrm[max_selected].second; |
||
308 | |||
309 | if (verbose) |
||
310 | fprintf(stderr, " %u, %u\n", selectfrm[max_selected].first, |
||
311 | selectfrm[max_selected].second); |
||
312 | } |
||
313 | |||
314 | max_selected++; |
||
315 | return(TRUE); |
||
316 | } |
||
317 | |||
318 | /* Was the packet selected? */ |
||
319 | |||
320 | static int |
||
321 | selected(guint recno) |
||
322 | { |
||
323 | guint i; |
||
324 | |||
325 | for (i = 0; i < max_selected; i++) { |
||
326 | if (selectfrm[i].inclusive) { |
||
327 | if (selectfrm[i].first <= recno && selectfrm[i].second >= recno) |
||
328 | return 1; |
||
329 | } else { |
||
330 | if (recno == selectfrm[i].first) |
||
331 | return 1; |
||
332 | } |
||
333 | } |
||
334 | |||
335 | return 0; |
||
336 | } |
||
337 | |||
338 | static void |
||
339 | set_time_adjustment(char *optarg_str_p) |
||
340 | { |
||
341 | char *frac, *end; |
||
342 | long val; |
||
343 | size_t frac_digits; |
||
344 | |||
345 | if (!optarg_str_p) |
||
346 | return; |
||
347 | |||
348 | /* skip leading whitespace */ |
||
349 | while (*optarg_str_p == ' ' || *optarg_str_p == '\t') |
||
350 | optarg_str_p++; |
||
351 | |||
352 | /* check for a negative adjustment */ |
||
353 | if (*optarg_str_p == '-') { |
||
354 | time_adj.is_negative = 1; |
||
355 | optarg_str_p++; |
||
356 | } |
||
357 | |||
358 | /* collect whole number of seconds, if any */ |
||
359 | if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ |
||
360 | val = 0; |
||
361 | frac = optarg_str_p; |
||
362 | } else { |
||
363 | val = strtol(optarg_str_p, &frac, 10); |
||
364 | if (frac == NULL || frac == optarg_str_p |
||
365 | || val == LONG_MIN || val == LONG_MAX) { |
||
366 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
367 | optarg_str_p); |
||
368 | exit(1); |
||
369 | } |
||
370 | if (val < 0) { /* implies '--' since we caught '-' above */ |
||
371 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
372 | optarg_str_p); |
||
373 | exit(1); |
||
374 | } |
||
375 | } |
||
376 | time_adj.tv.secs = val; |
||
377 | |||
378 | /* now collect the partial seconds, if any */ |
||
379 | if (*frac != '\0') { /* chars left, so get fractional part */ |
||
380 | val = strtol(&(frac[1]), &end, 10); |
||
381 | /* if more than 9 fractional digits truncate to 9 */ |
||
382 | if ((end - &(frac[1])) > 9) { |
||
383 | frac[10] = 't'; /* 't' for truncate */ |
||
384 | val = strtol(&(frac[1]), &end, 10); |
||
385 | } |
||
386 | if (*frac != '.' || end == NULL || end == frac || val < 0 |
||
387 | || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) { |
||
388 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
389 | optarg_str_p); |
||
390 | exit(1); |
||
391 | } |
||
392 | } else { |
||
393 | return; /* no fractional digits */ |
||
394 | } |
||
395 | |||
396 | /* adjust fractional portion from fractional to numerator |
||
397 | * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */ |
||
398 | frac_digits = end - frac - 1; /* fractional digit count (remember '.') */ |
||
399 | while(frac_digits < 9) { /* this is frac of 10^9 */ |
||
400 | val *= 10; |
||
401 | frac_digits++; |
||
402 | } |
||
403 | |||
404 | time_adj.tv.nsecs = (int)val; |
||
405 | } |
||
406 | |||
407 | static void |
||
408 | set_strict_time_adj(char *optarg_str_p) |
||
409 | { |
||
410 | char *frac, *end; |
||
411 | long val; |
||
412 | size_t frac_digits; |
||
413 | |||
414 | if (!optarg_str_p) |
||
415 | return; |
||
416 | |||
417 | /* skip leading whitespace */ |
||
418 | while (*optarg_str_p == ' ' || *optarg_str_p == '\t') |
||
419 | optarg_str_p++; |
||
420 | |||
421 | /* |
||
422 | * check for a negative adjustment |
||
423 | * A negative strict adjustment value is a flag |
||
424 | * to adjust all frames by the specifed delta time. |
||
425 | */ |
||
426 | if (*optarg_str_p == '-') { |
||
427 | strict_time_adj.is_negative = 1; |
||
428 | optarg_str_p++; |
||
429 | } |
||
430 | |||
431 | /* collect whole number of seconds, if any */ |
||
432 | if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ |
||
433 | val = 0; |
||
434 | frac = optarg_str_p; |
||
435 | } else { |
||
436 | val = strtol(optarg_str_p, &frac, 10); |
||
437 | if (frac == NULL || frac == optarg_str_p |
||
438 | || val == LONG_MIN || val == LONG_MAX) { |
||
439 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
440 | optarg_str_p); |
||
441 | exit(1); |
||
442 | } |
||
443 | if (val < 0) { /* implies '--' since we caught '-' above */ |
||
444 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
445 | optarg_str_p); |
||
446 | exit(1); |
||
447 | } |
||
448 | } |
||
449 | strict_time_adj.tv.secs = val; |
||
450 | |||
451 | /* now collect the partial seconds, if any */ |
||
452 | if (*frac != '\0') { /* chars left, so get fractional part */ |
||
453 | val = strtol(&(frac[1]), &end, 10); |
||
454 | /* if more than 9 fractional digits truncate to 9 */ |
||
455 | if ((end - &(frac[1])) > 9) { |
||
456 | frac[10] = 't'; /* 't' for truncate */ |
||
457 | val = strtol(&(frac[1]), &end, 10); |
||
458 | } |
||
459 | if (*frac != '.' || end == NULL || end == frac || val < 0 |
||
460 | || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) { |
||
461 | fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", |
||
462 | optarg_str_p); |
||
463 | exit(1); |
||
464 | } |
||
465 | } else { |
||
466 | return; /* no fractional digits */ |
||
467 | } |
||
468 | |||
469 | /* adjust fractional portion from fractional to numerator |
||
470 | * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */ |
||
471 | frac_digits = end - frac - 1; /* fractional digit count (remember '.') */ |
||
472 | while(frac_digits < 9) { /* this is frac of 10^9 */ |
||
473 | val *= 10; |
||
474 | frac_digits++; |
||
475 | } |
||
476 | |||
477 | strict_time_adj.tv.nsecs = (int)val; |
||
478 | } |
||
479 | |||
480 | static void |
||
481 | set_rel_time(char *optarg_str_p) |
||
482 | { |
||
483 | char *frac, *end; |
||
484 | long val; |
||
485 | size_t frac_digits; |
||
486 | |||
487 | if (!optarg_str_p) |
||
488 | return; |
||
489 | |||
490 | /* skip leading whitespace */ |
||
491 | while (*optarg_str_p == ' ' || *optarg_str_p == '\t') |
||
492 | optarg_str_p++; |
||
493 | |||
494 | /* ignore negative adjustment */ |
||
495 | if (*optarg_str_p == '-') |
||
496 | optarg_str_p++; |
||
497 | |||
498 | /* collect whole number of seconds, if any */ |
||
499 | if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ |
||
500 | val = 0; |
||
501 | frac = optarg_str_p; |
||
502 | } else { |
||
503 | val = strtol(optarg_str_p, &frac, 10); |
||
504 | if (frac == NULL || frac == optarg_str_p |
||
505 | || val == LONG_MIN || val == LONG_MAX) { |
||
506 | fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n", |
||
507 | optarg_str_p); |
||
508 | exit(1); |
||
509 | } |
||
510 | if (val < 0) { /* implies '--' since we caught '-' above */ |
||
511 | fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n", |
||
512 | optarg_str_p); |
||
513 | exit(1); |
||
514 | } |
||
515 | } |
||
516 | relative_time_window.secs = val; |
||
517 | |||
518 | /* now collect the partial seconds, if any */ |
||
519 | if (*frac != '\0') { /* chars left, so get fractional part */ |
||
520 | val = strtol(&(frac[1]), &end, 10); |
||
521 | /* if more than 9 fractional digits truncate to 9 */ |
||
522 | if ((end - &(frac[1])) > 9) { |
||
523 | frac[10] = 't'; /* 't' for truncate */ |
||
524 | val = strtol(&(frac[1]), &end, 10); |
||
525 | } |
||
526 | if (*frac != '.' || end == NULL || end == frac || val < 0 |
||
527 | || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) { |
||
528 | fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n", |
||
529 | optarg_str_p); |
||
530 | exit(1); |
||
531 | } |
||
532 | } else { |
||
533 | return; /* no fractional digits */ |
||
534 | } |
||
535 | |||
536 | /* adjust fractional portion from fractional to numerator |
||
537 | * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */ |
||
538 | frac_digits = end - frac - 1; /* fractional digit count (remember '.') */ |
||
539 | while(frac_digits < 9) { /* this is frac of 10^9 */ |
||
540 | val *= 10; |
||
541 | frac_digits++; |
||
542 | } |
||
543 | |||
544 | relative_time_window.nsecs = (int)val; |
||
545 | } |
||
546 | |||
547 | #define LINUX_SLL_OFFSETP 14 |
||
548 | #define VLAN_SIZE 4 |
||
549 | static void |
||
550 | sll_remove_vlan_info(guint8* fd, guint32* len) { |
||
551 | if (pntoh16(fd + LINUX_SLL_OFFSETP) == ETHERTYPE_VLAN) { |
||
552 | int rest_len; |
||
553 | /* point to start of vlan */ |
||
554 | fd = fd + LINUX_SLL_OFFSETP; |
||
555 | /* bytes to read after vlan info */ |
||
556 | rest_len = *len - (LINUX_SLL_OFFSETP + VLAN_SIZE); |
||
557 | /* remove vlan info from packet */ |
||
558 | memmove(fd, fd + VLAN_SIZE, rest_len); |
||
559 | *len -= 4; |
||
560 | } |
||
561 | } |
||
562 | |||
563 | static void |
||
564 | remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) { |
||
565 | switch (phdr->pkt_encap) { |
||
566 | case WTAP_ENCAP_SLL: |
||
567 | sll_remove_vlan_info(fd, len); |
||
568 | break; |
||
569 | default: |
||
570 | /* no support for current pkt_encap */ |
||
571 | break; |
||
572 | } |
||
573 | } |
||
574 | |||
575 | static gboolean |
||
576 | is_duplicate(guint8* fd, guint32 len) { |
||
577 | int i; |
||
578 | md5_state_t ms; |
||
579 | |||
580 | /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */ |
||
581 | guint32 new_len; |
||
582 | guint8 *new_fd; |
||
583 | |||
584 | new_fd = &fd[ignored_bytes]; |
||
585 | new_len = len - (ignored_bytes); |
||
586 | |||
587 | cur_dup_entry++; |
||
588 | if (cur_dup_entry >= dup_window) |
||
589 | cur_dup_entry = 0; |
||
590 | |||
591 | /* Calculate our digest */ |
||
592 | md5_init(&ms); |
||
593 | md5_append(&ms, new_fd, new_len); |
||
594 | md5_finish(&ms, fd_hash[cur_dup_entry].digest); |
||
595 | |||
596 | fd_hash[cur_dup_entry].len = len; |
||
597 | |||
598 | /* Look for duplicates */ |
||
599 | for (i = 0; i < dup_window; i++) { |
||
600 | if (i == cur_dup_entry) |
||
601 | continue; |
||
602 | |||
603 | if (fd_hash[i].len == fd_hash[cur_dup_entry].len |
||
604 | && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) { |
||
605 | return TRUE; |
||
606 | } |
||
607 | } |
||
608 | |||
609 | return FALSE; |
||
610 | } |
||
611 | |||
612 | static gboolean |
||
613 | is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) { |
||
614 | int i; |
||
615 | md5_state_t ms; |
||
616 | |||
617 | /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */ |
||
618 | guint32 new_len; |
||
619 | guint8 *new_fd; |
||
620 | |||
621 | new_fd = &fd[ignored_bytes]; |
||
622 | new_len = len - (ignored_bytes); |
||
623 | |||
624 | cur_dup_entry++; |
||
625 | if (cur_dup_entry >= dup_window) |
||
626 | cur_dup_entry = 0; |
||
627 | |||
628 | /* Calculate our digest */ |
||
629 | md5_init(&ms); |
||
630 | md5_append(&ms, new_fd, new_len); |
||
631 | md5_finish(&ms, fd_hash[cur_dup_entry].digest); |
||
632 | |||
633 | fd_hash[cur_dup_entry].len = len; |
||
634 | fd_hash[cur_dup_entry].frame_time.secs = current->secs; |
||
635 | fd_hash[cur_dup_entry].frame_time.nsecs = current->nsecs; |
||
636 | |||
637 | /* |
||
638 | * Look for relative time related duplicates. |
||
639 | * This is hopefully a reasonably efficient mechanism for |
||
640 | * finding duplicates by rel time in the fd_hash[] cache. |
||
641 | * We check starting from the most recently added hash |
||
642 | * entries and work backwards towards older packets. |
||
643 | * This approach allows the dup test to be terminated |
||
644 | * when the relative time of a cached entry is found to |
||
645 | * be beyond the dup time window. |
||
646 | * |
||
647 | * Of course this assumes that the input trace file is |
||
648 | * "well-formed" in the sense that the packet timestamps are |
||
649 | * in strict chronologically increasing order (which is NOT |
||
650 | * always the case!!). |
||
651 | * |
||
652 | * The fd_hash[] table was deliberately created large (1,000,000). |
||
653 | * Looking for time related duplicates in large trace files with |
||
654 | * non-fractional dup time window values can potentially take |
||
655 | * a long time to complete. |
||
656 | */ |
||
657 | |||
658 | for (i = cur_dup_entry - 1;; i--) { |
||
659 | nstime_t delta; |
||
660 | int cmp; |
||
661 | |||
662 | if (i < 0) |
||
663 | i = dup_window - 1; |
||
664 | |||
665 | if (i == cur_dup_entry) { |
||
666 | /* |
||
667 | * We've decremented back to where we started. |
||
668 | * Check no more! |
||
669 | */ |
||
670 | break; |
||
671 | } |
||
672 | |||
673 | if (nstime_is_unset(&(fd_hash[i].frame_time))) { |
||
674 | /* |
||
675 | * We've decremented to an unused fd_hash[] entry. |
||
676 | * Check no more! |
||
677 | */ |
||
678 | break; |
||
679 | } |
||
680 | |||
681 | nstime_delta(&delta, current, &fd_hash[i].frame_time); |
||
682 | |||
683 | if (delta.secs < 0 || delta.nsecs < 0) { |
||
684 | /* |
||
685 | * A negative delta implies that the current packet |
||
686 | * has an absolute timestamp less than the cached packet |
||
687 | * that it is being compared to. This is NOT a normal |
||
688 | * situation since trace files usually have packets in |
||
689 | * chronological order (oldest to newest). |
||
690 | * |
||
691 | * There are several possible ways to deal with this: |
||
692 | * 1. 'continue' dup checking with the next cached frame. |
||
693 | * 2. 'break' from looking for a duplicate of the current frame. |
||
694 | * 3. Take the absolute value of the delta and see if that |
||
695 | * falls within the specifed dup time window. |
||
696 | * |
||
697 | * Currently this code does option 1. But it would pretty |
||
698 | * easy to add yet-another-editcap-option to select one of |
||
699 | * the other behaviors for dealing with out-of-sequence |
||
700 | * packets. |
||
701 | */ |
||
702 | continue; |
||
703 | } |
||
704 | |||
705 | cmp = nstime_cmp(&delta, &relative_time_window); |
||
706 | |||
707 | if (cmp > 0) { |
||
708 | /* |
||
709 | * The delta time indicates that we are now looking at |
||
710 | * cached packets beyond the specified dup time window. |
||
711 | * Check no more! |
||
712 | */ |
||
713 | break; |
||
714 | } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len |
||
715 | && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) { |
||
716 | return TRUE; |
||
717 | } |
||
718 | } |
||
719 | |||
720 | return FALSE; |
||
721 | } |
||
722 | |||
723 | static void |
||
724 | print_usage(FILE *output) |
||
725 | { |
||
726 | fprintf(output, "\n"); |
||
727 | fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n"); |
||
728 | fprintf(output, "\n"); |
||
729 | fprintf(output, "<infile> and <outfile> must both be present.\n"); |
||
730 | fprintf(output, "A single packet or a range of packets can be selected.\n"); |
||
731 | fprintf(output, "\n"); |
||
732 | fprintf(output, "Packet selection:\n"); |
||
733 | fprintf(output, " -r keep the selected packets; default is to delete them.\n"); |
||
734 | fprintf(output, " -A <start time> only output packets whose timestamp is after (or equal\n"); |
||
735 | fprintf(output, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n"); |
||
736 | fprintf(output, " -B <stop time> only output packets whose timestamp is before the\n"); |
||
737 | fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n"); |
||
738 | fprintf(output, "\n"); |
||
739 | fprintf(output, "Duplicate packet removal:\n"); |
||
740 | fprintf(output, " --novlan remove vlan info from packets before checking for duplicates.\n"); |
||
741 | fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH); |
||
742 | fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n"); |
||
743 | fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH); |
||
744 | fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n"); |
||
745 | fprintf(output, " useful to print MD5 hashes.\n"); |
||
746 | fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n"); |
||
747 | fprintf(output, " LESS THAN <dup time window> prior to current packet.\n"); |
||
748 | fprintf(output, " A <dup time window> is specified in relative seconds\n"); |
||
749 | fprintf(output, " (e.g. 0.000001).\n"); |
||
750 | fprintf(output, " -a <framenum>:<comment> Add or replace comment for given frame number\n"); |
||
751 | fprintf(output, "\n"); |
||
752 | fprintf(output, " -I <bytes to ignore> ignore the specified bytes at the beginning of\n"); |
||
753 | fprintf(output, " the frame during MD5 hash calculation\n"); |
||
754 | fprintf(output, " Useful to remove duplicated packets taken on\n"); |
||
755 | fprintf(output, " several routers(differents mac addresses for \n"); |
||
756 | fprintf(output, " example)\n"); |
||
757 | fprintf(output, " e.g. -I 26 in case of Ether/IP/ will ignore \n"); |
||
758 | fprintf(output, " ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n"); |
||
759 | fprintf(output, "\n"); |
||
760 | fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n"); |
||
761 | fprintf(output, " other editcap options except -v may not always work as expected.\n"); |
||
762 | fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n"); |
||
763 | fprintf(output, " desired effect if combined with the -d, -D or -w.\n"); |
||
764 | fprintf(output, "\n"); |
||
765 | fprintf(output, "Packet manipulation:\n"); |
||
766 | fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n"); |
||
767 | fprintf(output, " -C [offset:]<choplen> chop each packet by <choplen> bytes. Positive values\n"); |
||
768 | fprintf(output, " chop at the packet beginning, negative values at the\n"); |
||
769 | fprintf(output, " packet end. If an optional offset precedes the length,\n"); |
||
770 | fprintf(output, " then the bytes chopped will be offset from that value.\n"); |
||
771 | fprintf(output, " Positive offsets are from the packet beginning,\n"); |
||
772 | fprintf(output, " negative offsets are from the packet end. You can use\n"); |
||
773 | fprintf(output, " this option more than once, allowing up to 2 chopping\n"); |
||
774 | fprintf(output, " regions within a packet provided that at least 1\n"); |
||
775 | fprintf(output, " choplen is positive and at least 1 is negative.\n"); |
||
776 | fprintf(output, " -L adjust the frame (i.e. reported) length when chopping\n"); |
||
777 | fprintf(output, " and/or snapping\n"); |
||
778 | fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n"); |
||
779 | fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n"); |
||
780 | fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n"); |
||
781 | fprintf(output, " strict chronological increasing order. The <strict\n"); |
||
782 | fprintf(output, " adjustment> is specified in relative seconds with\n"); |
||
783 | fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n"); |
||
784 | fprintf(output, " A negative adjustment value will modify timestamps so\n"); |
||
785 | fprintf(output, " that each packet's delta time is the absolute value\n"); |
||
786 | fprintf(output, " of the adjustment specified. A value of -0 will set\n"); |
||
787 | fprintf(output, " all packets to the timestamp of the first packet.\n"); |
||
788 | fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n"); |
||
789 | fprintf(output, " a particular packet byte will be randomly changed.\n"); |
||
790 | fprintf(output, " -o <change offset> When used in conjunction with -E, skip some bytes from the\n"); |
||
791 | fprintf(output, " beginning of the packet. This allows one to preserve some\n"); |
||
792 | fprintf(output, " bytes, in order to have some headers untouched.\n"); |
||
793 | fprintf(output, "\n"); |
||
794 | fprintf(output, "Output File(s):\n"); |
||
795 | fprintf(output, " -c <packets per file> split the packet output to different files based on\n"); |
||
796 | fprintf(output, " uniform packet counts with a maximum of\n"); |
||
797 | fprintf(output, " <packets per file> each.\n"); |
||
798 | fprintf(output, " -i <seconds per file> split the packet output to different files based on\n"); |
||
799 | fprintf(output, " uniform time intervals with a maximum of\n"); |
||
800 | fprintf(output, " <seconds per file> each.\n"); |
||
801 | fprintf(output, " -F <capture type> set the output file type; default is pcapng. An empty\n"); |
||
802 | fprintf(output, " \"-F\" option will list the file types.\n"); |
||
803 | fprintf(output, " -T <encap type> set the output file encapsulation type; default is the\n"); |
||
804 | fprintf(output, " same as the input file. An empty \"-T\" option will\n"); |
||
805 | fprintf(output, " list the encapsulation types.\n"); |
||
806 | fprintf(output, "\n"); |
||
807 | fprintf(output, "Miscellaneous:\n"); |
||
808 | fprintf(output, " -h display this help and exit.\n"); |
||
809 | fprintf(output, " -v verbose output.\n"); |
||
810 | fprintf(output, " If -v is used with any of the 'Duplicate Packet\n"); |
||
811 | fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n"); |
||
812 | fprintf(output, " and MD5 hashes are printed to standard-error.\n"); |
||
813 | fprintf(output, "\n"); |
||
814 | } |
||
815 | |||
816 | struct string_elem { |
||
817 | const char *sstr; /* The short string */ |
||
818 | const char *lstr; /* The long string */ |
||
819 | }; |
||
820 | |||
821 | static gint |
||
822 | string_compare(gconstpointer a, gconstpointer b) |
||
823 | { |
||
824 | return strcmp(((const struct string_elem *)a)->sstr, |
||
825 | ((const struct string_elem *)b)->sstr); |
||
826 | } |
||
827 | |||
828 | static gint |
||
829 | string_nat_compare(gconstpointer a, gconstpointer b) |
||
830 | { |
||
831 | return ws_ascii_strnatcmp(((const struct string_elem *)a)->sstr, |
||
832 | ((const struct string_elem *)b)->sstr); |
||
833 | } |
||
834 | |||
835 | static void |
||
836 | string_elem_print(gpointer data, gpointer not_used _U_) |
||
837 | { |
||
838 | fprintf(stderr, " %s - %s\n", |
||
839 | ((struct string_elem *)data)->sstr, |
||
840 | ((struct string_elem *)data)->lstr); |
||
841 | } |
||
842 | |||
843 | static void |
||
844 | list_capture_types(void) { |
||
845 | int i; |
||
846 | struct string_elem *captypes; |
||
847 | GSList *list = NULL; |
||
848 | |||
849 | captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES); |
||
850 | fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n"); |
||
851 | for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) { |
||
852 | if (wtap_dump_can_open(i)) { |
||
853 | captypes[i].sstr = wtap_file_type_subtype_short_string(i); |
||
854 | captypes[i].lstr = wtap_file_type_subtype_string(i); |
||
855 | list = g_slist_insert_sorted(list, &captypes[i], string_compare); |
||
856 | } |
||
857 | } |
||
858 | g_slist_foreach(list, string_elem_print, NULL); |
||
859 | g_slist_free(list); |
||
860 | g_free(captypes); |
||
861 | } |
||
862 | |||
863 | static void |
||
864 | list_encap_types(void) { |
||
865 | int i; |
||
866 | struct string_elem *encaps; |
||
867 | GSList *list = NULL; |
||
868 | |||
869 | encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES); |
||
870 | fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n"); |
||
871 | for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) { |
||
872 | encaps[i].sstr = wtap_encap_short_string(i); |
||
873 | if (encaps[i].sstr != NULL) { |
||
874 | encaps[i].lstr = wtap_encap_string(i); |
||
875 | list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare); |
||
876 | } |
||
877 | } |
||
878 | g_slist_foreach(list, string_elem_print, NULL); |
||
879 | g_slist_free(list); |
||
880 | g_free(encaps); |
||
881 | } |
||
882 | |||
883 | static int |
||
884 | framenum_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_) |
||
885 | { |
||
886 | if (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b)) |
||
887 | return -1; |
||
888 | |||
889 | if (GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b)) |
||
890 | return 1; |
||
891 | |||
892 | return 0; |
||
893 | } |
||
894 | |||
895 | #ifdef HAVE_PLUGINS |
||
896 | /* |
||
897 | * Don't report failures to load plugins because most (non-wiretap) plugins |
||
898 | * *should* fail to load (because we're not linked against libwireshark and |
||
899 | * dissector plugins need libwireshark). |
||
900 | */ |
||
901 | static void |
||
902 | failure_message(const char *msg_format _U_, va_list ap _U_) |
||
903 | { |
||
904 | } |
||
905 | #endif |
||
906 | |||
907 | static wtap_dumper * |
||
908 | editcap_dump_open(const char *filename, guint32 snaplen, |
||
909 | GArray* shb_hdrs, |
||
910 | wtapng_iface_descriptions_t *idb_inf, |
||
911 | GArray* nrb_hdrs, int *write_err) |
||
912 | { |
||
913 | wtap_dumper *pdh; |
||
914 | |||
915 | if (strcmp(filename, "-") == 0) { |
||
916 | /* Write to the standard output. */ |
||
917 | pdh = wtap_dump_open_stdout_ng(out_file_type_subtype, out_frame_type, |
||
918 | snaplen, FALSE /* compressed */, |
||
919 | shb_hdrs, idb_inf, nrb_hdrs, write_err); |
||
920 | } else { |
||
921 | pdh = wtap_dump_open_ng(filename, out_file_type_subtype, out_frame_type, |
||
922 | snaplen, FALSE /* compressed */, |
||
923 | shb_hdrs, idb_inf, nrb_hdrs, write_err); |
||
924 | } |
||
925 | return pdh; |
||
926 | } |
||
927 | |||
928 | int |
||
929 | main(int argc, char *argv[]) |
||
930 | { |
||
931 | GString *comp_info_str; |
||
932 | GString *runtime_info_str; |
||
933 | wtap *wth; |
||
934 | int i, j, read_err, write_err; |
||
935 | gchar *read_err_info, *write_err_info; |
||
936 | int opt; |
||
937 | static const struct option long_options[] = { |
||
938 | {"novlan", no_argument, NULL, 0x8100}, |
||
939 | {"help", no_argument, NULL, 'h'}, |
||
940 | {"version", no_argument, NULL, 'V'}, |
||
941 | {0, 0, 0, 0 } |
||
942 | }; |
||
943 | |||
944 | char *p; |
||
945 | guint32 snaplen = 0; /* No limit */ |
||
946 | chop_t chop = {0, 0, 0, 0, 0, 0}; /* No chop */ |
||
947 | gboolean adjlen = FALSE; |
||
948 | wtap_dumper *pdh = NULL; |
||
949 | unsigned int count = 1; |
||
950 | unsigned int duplicate_count = 0; |
||
951 | gint64 data_offset; |
||
952 | int err_type; |
||
953 | guint8 *buf; |
||
954 | guint32 read_count = 0; |
||
955 | int split_packet_count = 0; |
||
956 | int written_count = 0; |
||
957 | char *filename = NULL; |
||
958 | gboolean ts_okay; |
||
959 | int secs_per_block = 0; |
||
960 | int block_cnt = 0; |
||
961 | nstime_t block_start; |
||
962 | gchar *fprefix = NULL; |
||
963 | gchar *fsuffix = NULL; |
||
964 | guint32 change_offset = 0; |
||
965 | guint max_packet_number = 0; |
||
966 | const struct wtap_pkthdr *phdr; |
||
967 | struct wtap_pkthdr temp_phdr; |
||
968 | wtapng_iface_descriptions_t *idb_inf = NULL; |
||
969 | GArray *shb_hdrs = NULL; |
||
970 | GArray *nrb_hdrs = NULL; |
||
971 | char *shb_user_appl; |
||
972 | |||
973 | #ifdef HAVE_PLUGINS |
||
974 | char* init_progfile_dir_error; |
||
975 | #endif |
||
976 | |||
977 | #ifdef _WIN32 |
||
978 | arg_list_utf_16to8(argc, argv); |
||
979 | create_app_running_mutex(); |
||
980 | #endif /* _WIN32 */ |
||
981 | |||
982 | /* Get the compile-time version information string */ |
||
983 | comp_info_str = get_compiled_version_info(NULL, NULL); |
||
984 | |||
985 | /* Get the run-time version information string */ |
||
986 | runtime_info_str = get_runtime_version_info(NULL); |
||
987 | |||
988 | /* Add it to the information to be reported on a crash. */ |
||
989 | ws_add_crash_info("Editcap (Wireshark) %s\n" |
||
990 | "\n" |
||
991 | "%s" |
||
992 | "\n" |
||
993 | "%s", |
||
994 | get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str); |
||
995 | |||
996 | /* |
||
997 | * Get credential information for later use. |
||
998 | */ |
||
999 | init_process_policies(); |
||
1000 | init_open_routines(); |
||
1001 | |||
1002 | #ifdef HAVE_PLUGINS |
||
1003 | /* Register wiretap plugins */ |
||
1004 | if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) { |
||
1005 | g_warning("editcap: init_progfile_dir(): %s", init_progfile_dir_error); |
||
1006 | g_free(init_progfile_dir_error); |
||
1007 | } else { |
||
1008 | /* Register all the plugin types we have. */ |
||
1009 | wtap_register_plugin_types(); /* Types known to libwiretap */ |
||
1010 | |||
1011 | init_report_err(failure_message,NULL,NULL,NULL); |
||
1012 | |||
1013 | /* Scan for plugins. This does *not* call their registration routines; |
||
1014 | that's done later. */ |
||
1015 | scan_plugins(); |
||
1016 | |||
1017 | /* Register all libwiretap plugin modules. */ |
||
1018 | register_all_wiretap_modules(); |
||
1019 | } |
||
1020 | #endif |
||
1021 | |||
1022 | /* Process the options */ |
||
1023 | while ((opt = getopt_long(argc, argv, "a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) { |
||
1024 | switch (opt) { |
||
1025 | case 0x8100: |
||
1026 | { |
||
1027 | rem_vlan = TRUE; |
||
1028 | break; |
||
1029 | } |
||
1030 | |||
1031 | case 'a': |
||
1032 | { |
||
1033 | guint frame_number; |
||
1034 | gint string_start_index = 0; |
||
1035 | |||
1036 | if ((sscanf(optarg, "%u:%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) { |
||
1037 | fprintf(stderr, "editcap: \"%s\" isn't a valid <frame>:<comment>\n\n", |
||
1038 | optarg); |
||
1039 | exit(1); |
||
1040 | } |
||
1041 | |||
1042 | /* Lazily create the table */ |
||
1043 | if (!frames_user_comments) { |
||
1044 | frames_user_comments = g_tree_new_full(framenum_compare, NULL, NULL, g_free); |
||
1045 | } |
||
1046 | |||
1047 | /* Insert this entry (framenum -> comment) */ |
||
1048 | g_tree_replace(frames_user_comments, GUINT_TO_POINTER(frame_number), g_strdup(optarg+string_start_index)); |
||
1049 | break; |
||
1050 | } |
||
1051 | |||
1052 | case 'A': |
||
1053 | { |
||
1054 | struct tm starttm; |
||
1055 | |||
1056 | memset(&starttm,0,sizeof(struct tm)); |
||
1057 | |||
1058 | if (!strptime(optarg,"%Y-%m-%d %T", &starttm)) { |
||
1059 | fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", |
||
1060 | optarg); |
||
1061 | exit(1); |
||
1062 | } |
||
1063 | |||
1064 | check_startstop = TRUE; |
||
1065 | starttm.tm_isdst = -1; |
||
1066 | |||
1067 | starttime = mktime(&starttm); |
||
1068 | break; |
||
1069 | } |
||
1070 | |||
1071 | case 'B': |
||
1072 | { |
||
1073 | struct tm stoptm; |
||
1074 | |||
1075 | memset(&stoptm,0,sizeof(struct tm)); |
||
1076 | |||
1077 | if (!strptime(optarg,"%Y-%m-%d %T", &stoptm)) { |
||
1078 | fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", |
||
1079 | optarg); |
||
1080 | exit(1); |
||
1081 | } |
||
1082 | check_startstop = TRUE; |
||
1083 | stoptm.tm_isdst = -1; |
||
1084 | stoptime = mktime(&stoptm); |
||
1085 | break; |
||
1086 | } |
||
1087 | |||
1088 | case 'c': |
||
1089 | split_packet_count = (int)strtol(optarg, &p, 10); |
||
1090 | if (p == optarg || *p != '\0') { |
||
1091 | fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n", |
||
1092 | optarg); |
||
1093 | exit(1); |
||
1094 | } |
||
1095 | if (split_packet_count <= 0) { |
||
1096 | fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n", |
||
1097 | split_packet_count); |
||
1098 | exit(1); |
||
1099 | } |
||
1100 | break; |
||
1101 | |||
1102 | case 'C': |
||
1103 | { |
||
1104 | int choplen = 0, chopoff = 0; |
||
1105 | |||
1106 | switch (sscanf(optarg, "%d:%d", &chopoff, &choplen)) { |
||
1107 | case 1: /* only the chop length was specififed */ |
||
1108 | choplen = chopoff; |
||
1109 | chopoff = 0; |
||
1110 | break; |
||
1111 | |||
1112 | case 2: /* both an offset and chop length was specified */ |
||
1113 | break; |
||
1114 | |||
1115 | default: |
||
1116 | fprintf(stderr, "editcap: \"%s\" isn't a valid chop length or offset:length\n", |
||
1117 | optarg); |
||
1118 | exit(1); |
||
1119 | break; |
||
1120 | } |
||
1121 | |||
1122 | if (choplen > 0) { |
||
1123 | chop.len_begin += choplen; |
||
1124 | if (chopoff > 0) |
||
1125 | chop.off_begin_pos += chopoff; |
||
1126 | else |
||
1127 | chop.off_begin_neg += chopoff; |
||
1128 | } else if (choplen < 0) { |
||
1129 | chop.len_end += choplen; |
||
1130 | if (chopoff > 0) |
||
1131 | chop.off_end_pos += chopoff; |
||
1132 | else |
||
1133 | chop.off_end_neg += chopoff; |
||
1134 | } |
||
1135 | break; |
||
1136 | } |
||
1137 | |||
1138 | case 'd': |
||
1139 | dup_detect = TRUE; |
||
1140 | dup_detect_by_time = FALSE; |
||
1141 | dup_window = DEFAULT_DUP_DEPTH; |
||
1142 | break; |
||
1143 | |||
1144 | case 'D': |
||
1145 | dup_detect = TRUE; |
||
1146 | dup_detect_by_time = FALSE; |
||
1147 | dup_window = (int)strtol(optarg, &p, 10); |
||
1148 | if (p == optarg || *p != '\0') { |
||
1149 | fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n", |
||
1150 | optarg); |
||
1151 | exit(1); |
||
1152 | } |
||
1153 | if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) { |
||
1154 | fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n", |
||
1155 | dup_window, MAX_DUP_DEPTH); |
||
1156 | exit(1); |
||
1157 | } |
||
1158 | break; |
||
1159 | |||
1160 | case 'E': |
||
1161 | err_prob = g_ascii_strtod(optarg, &p); |
||
1162 | if (p == optarg || err_prob < 0.0 || err_prob > 1.0) { |
||
1163 | fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n", |
||
1164 | optarg); |
||
1165 | exit(1); |
||
1166 | } |
||
1167 | srand( (unsigned int) (time(NULL) + ws_getpid()) ); |
||
1168 | break; |
||
1169 | |||
1170 | case 'F': |
||
1171 | out_file_type_subtype = wtap_short_string_to_file_type_subtype(optarg); |
||
1172 | if (out_file_type_subtype < 0) { |
||
1173 | fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n", |
||
1174 | optarg); |
||
1175 | list_capture_types(); |
||
1176 | exit(1); |
||
1177 | } |
||
1178 | break; |
||
1179 | |||
1180 | case 'h': |
||
1181 | printf("Editcap (Wireshark) %s\n" |
||
1182 | "Edit and/or translate the format of capture files.\n" |
||
1183 | "See https://www.wireshark.org for more information.\n", |
||
1184 | get_ws_vcs_version_info()); |
||
1185 | print_usage(stdout); |
||
1186 | exit(0); |
||
1187 | break; |
||
1188 | |||
1189 | case 'i': /* break capture file based on time interval */ |
||
1190 | secs_per_block = atoi(optarg); |
||
1191 | if (secs_per_block <= 0) { |
||
1192 | fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", |
||
1193 | optarg); |
||
1194 | exit(1); |
||
1195 | } |
||
1196 | break; |
||
1197 | |||
1198 | case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */ |
||
1199 | ignored_bytes = atoi(optarg); |
||
1200 | if(ignored_bytes <= 0) { |
||
1201 | fprintf(stderr, "editcap: \"%s\" isn't a valid number of bytes to ignore\n", optarg); |
||
1202 | exit(1); |
||
1203 | } |
||
1204 | break; |
||
1205 | |||
1206 | case 'L': |
||
1207 | adjlen = TRUE; |
||
1208 | break; |
||
1209 | |||
1210 | case 'o': |
||
1211 | change_offset = (guint32)strtol(optarg, &p, 10); |
||
1212 | break; |
||
1213 | |||
1214 | case 'r': |
||
1215 | keep_em = !keep_em; /* Just invert */ |
||
1216 | break; |
||
1217 | |||
1218 | case 's': |
||
1219 | snaplen = (guint32)strtol(optarg, &p, 10); |
||
1220 | if (p == optarg || *p != '\0') { |
||
1221 | fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n", |
||
1222 | optarg); |
||
1223 | exit(1); |
||
1224 | } |
||
1225 | break; |
||
1226 | |||
1227 | case 'S': |
||
1228 | set_strict_time_adj(optarg); |
||
1229 | do_strict_time_adjustment = TRUE; |
||
1230 | break; |
||
1231 | |||
1232 | case 't': |
||
1233 | set_time_adjustment(optarg); |
||
1234 | break; |
||
1235 | |||
1236 | case 'T': |
||
1237 | out_frame_type = wtap_short_string_to_encap(optarg); |
||
1238 | if (out_frame_type < 0) { |
||
1239 | fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n", |
||
1240 | optarg); |
||
1241 | list_encap_types(); |
||
1242 | exit(1); |
||
1243 | } |
||
1244 | break; |
||
1245 | |||
1246 | case 'v': |
||
1247 | verbose = !verbose; /* Just invert */ |
||
1248 | break; |
||
1249 | |||
1250 | case 'V': |
||
1251 | show_version("Editcap (Wireshark)", comp_info_str, runtime_info_str); |
||
1252 | g_string_free(comp_info_str, TRUE); |
||
1253 | g_string_free(runtime_info_str, TRUE); |
||
1254 | exit(0); |
||
1255 | break; |
||
1256 | |||
1257 | case 'w': |
||
1258 | dup_detect = FALSE; |
||
1259 | dup_detect_by_time = TRUE; |
||
1260 | dup_window = MAX_DUP_DEPTH; |
||
1261 | set_rel_time(optarg); |
||
1262 | break; |
||
1263 | |||
1264 | case '?': /* Bad options if GNU getopt */ |
||
1265 | switch(optopt) { |
||
1266 | case'F': |
||
1267 | list_capture_types(); |
||
1268 | break; |
||
1269 | case'T': |
||
1270 | list_encap_types(); |
||
1271 | break; |
||
1272 | default: |
||
1273 | print_usage(stderr); |
||
1274 | break; |
||
1275 | } |
||
1276 | exit(1); |
||
1277 | break; |
||
1278 | } |
||
1279 | } /* processing commmand-line options */ |
||
1280 | |||
1281 | #ifdef DEBUG |
||
1282 | fprintf(stderr, "Optind = %i, argc = %i\n", optind, argc); |
||
1283 | #endif |
||
1284 | |||
1285 | if ((argc - optind) < 1) { |
||
1286 | print_usage(stderr); |
||
1287 | exit(1); |
||
1288 | } |
||
1289 | |||
1290 | if (check_startstop && !stoptime) { |
||
1291 | struct tm stoptm; |
||
1292 | |||
1293 | /* XXX: will work until 2035 */ |
||
1294 | memset(&stoptm,0,sizeof(struct tm)); |
||
1295 | stoptm.tm_year = 135; |
||
1296 | stoptm.tm_mday = 31; |
||
1297 | stoptm.tm_mon = 11; |
||
1298 | |||
1299 | stoptime = mktime(&stoptm); |
||
1300 | } |
||
1301 | |||
1302 | nstime_set_unset(&block_start); |
||
1303 | |||
1304 | if (starttime > stoptime) { |
||
1305 | fprintf(stderr, "editcap: start time is after the stop time\n"); |
||
1306 | exit(1); |
||
1307 | } |
||
1308 | |||
1309 | if (split_packet_count > 0 && secs_per_block > 0) { |
||
1310 | fprintf(stderr, "editcap: can't split on both packet count and time interval\n"); |
||
1311 | fprintf(stderr, "editcap: at the same time\n"); |
||
1312 | exit(1); |
||
1313 | } |
||
1314 | |||
1315 | wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE); |
||
1316 | |||
1317 | if (!wth) { |
||
1318 | fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind], |
||
1319 | wtap_strerror(read_err)); |
||
1320 | if (read_err_info != NULL) { |
||
1321 | fprintf(stderr, "(%s)\n", read_err_info); |
||
1322 | g_free(read_err_info); |
||
1323 | } |
||
1324 | exit(2); |
||
1325 | } |
||
1326 | |||
1327 | if (verbose) { |
||
1328 | fprintf(stderr, "File %s is a %s capture file.\n", argv[optind], |
||
1329 | wtap_file_type_subtype_string(wtap_file_type_subtype(wth))); |
||
1330 | } |
||
1331 | |||
1332 | shb_hdrs = wtap_file_get_shb_for_new_file(wth); |
||
1333 | idb_inf = wtap_file_get_idb_info(wth); |
||
1334 | nrb_hdrs = wtap_file_get_nrb_for_new_file(wth); |
||
1335 | |||
1336 | /* |
||
1337 | * Now, process the rest, if any ... we only write if there is an extra |
||
1338 | * argument or so ... |
||
1339 | */ |
||
1340 | |||
1341 | if ((argc - optind) >= 2) { |
||
1342 | if (out_frame_type == -2) |
||
1343 | out_frame_type = wtap_file_encap(wth); |
||
1344 | |||
1345 | for (i = optind + 2; i < argc; i++) |
||
1346 | if (add_selection(argv[i], &max_packet_number) == FALSE) |
||
1347 | break; |
||
1348 | |||
1349 | if (keep_em == FALSE) |
||
1350 | max_packet_number = G_MAXUINT; |
||
1351 | |||
1352 | if (dup_detect || dup_detect_by_time) { |
||
1353 | for (i = 0; i < dup_window; i++) { |
||
1354 | memset(&fd_hash[i].digest, 0, 16); |
||
1355 | fd_hash[i].len = 0; |
||
1356 | nstime_set_unset(&fd_hash[i].frame_time); |
||
1357 | } |
||
1358 | } |
||
1359 | |||
1360 | /* Read all of the packets in turn */ |
||
1361 | while (wtap_read(wth, &read_err, &read_err_info, &data_offset)) { |
||
1362 | if (max_packet_number <= read_count) |
||
1363 | break; |
||
1364 | |||
1365 | read_count++; |
||
1366 | |||
1367 | phdr = wtap_phdr(wth); |
||
1368 | |||
1369 | /* Extra actions for the first packet */ |
||
1370 | if (read_count == 1) { |
||
1371 | if (split_packet_count > 0 || secs_per_block > 0) { |
||
1372 | if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix)) |
||
1373 | goto error_on_exit; |
||
1374 | |||
1375 | filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix); |
||
1376 | } else { |
||
1377 | filename = g_strdup(argv[optind+1]); |
||
1378 | } |
||
1379 | g_assert(filename); |
||
1380 | |||
1381 | /* If we don't have an application name add Editcap */ |
||
1382 | if (wtap_block_get_string_option_value(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) { |
||
1383 | wtap_block_add_string_option_format(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, "Editcap " VERSION); |
||
1384 | } |
||
1385 | |||
1386 | pdh = editcap_dump_open(filename, |
||
1387 | snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth), |
||
1388 | shb_hdrs, idb_inf, nrb_hdrs, &write_err); |
||
1389 | |||
1390 | if (pdh == NULL) { |
||
1391 | fprintf(stderr, "editcap: Can't open or create %s: %s\n", |
||
1392 | filename, wtap_strerror(write_err)); |
||
1393 | goto error_on_exit; |
||
1394 | } |
||
1395 | } /* first packet only handling */ |
||
1396 | |||
1397 | |||
1398 | buf = wtap_buf_ptr(wth); |
||
1399 | |||
1400 | /* |
||
1401 | * Not all packets have time stamps. Only process the time |
||
1402 | * stamp if we have one. |
||
1403 | */ |
||
1404 | if (phdr->presence_flags & WTAP_HAS_TS) { |
||
1405 | if (nstime_is_unset(&block_start)) { |
||
1406 | block_start = phdr->ts; |
||
1407 | } |
||
1408 | |||
1409 | if (secs_per_block > 0) { |
||
1410 | while ((phdr->ts.secs - block_start.secs > secs_per_block) |
||
1411 | || (phdr->ts.secs - block_start.secs == secs_per_block |
||
1412 | && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */ |
||
1413 | |||
1414 | if (!wtap_dump_close(pdh, &write_err)) { |
||
1415 | fprintf(stderr, "editcap: Error writing to %s: %s\n", |
||
1416 | filename, wtap_strerror(write_err)); |
||
1417 | goto error_on_exit; |
||
1418 | } |
||
1419 | block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */ |
||
1420 | g_free(filename); |
||
1421 | filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix); |
||
1422 | g_assert(filename); |
||
1423 | |||
1424 | if (verbose) |
||
1425 | fprintf(stderr, "Continuing writing in file %s\n", filename); |
||
1426 | |||
1427 | pdh = editcap_dump_open(filename, |
||
1428 | snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth), |
||
1429 | shb_hdrs, idb_inf, nrb_hdrs, &write_err); |
||
1430 | |||
1431 | if (pdh == NULL) { |
||
1432 | fprintf(stderr, "editcap: Can't open or create %s: %s\n", |
||
1433 | filename, wtap_strerror(write_err)); |
||
1434 | goto error_on_exit; |
||
1435 | } |
||
1436 | } |
||
1437 | } |
||
1438 | } /* time stamp handling */ |
||
1439 | |||
1440 | if (split_packet_count > 0) { |
||
1441 | /* time for the next file? */ |
||
1442 | if (written_count > 0 && written_count % split_packet_count == 0) { |
||
1443 | if (!wtap_dump_close(pdh, &write_err)) { |
||
1444 | fprintf(stderr, "editcap: Error writing to %s: %s\n", |
||
1445 | filename, wtap_strerror(write_err)); |
||
1446 | goto error_on_exit; |
||
1447 | } |
||
1448 | |||
1449 | g_free(filename); |
||
1450 | filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix); |
||
1451 | g_assert(filename); |
||
1452 | |||
1453 | if (verbose) |
||
1454 | fprintf(stderr, "Continuing writing in file %s\n", filename); |
||
1455 | |||
1456 | pdh = editcap_dump_open(filename, |
||
1457 | snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth), |
||
1458 | shb_hdrs, idb_inf, nrb_hdrs, &write_err); |
||
1459 | if (pdh == NULL) { |
||
1460 | fprintf(stderr, "editcap: Can't open or create %s: %s\n", |
||
1461 | filename, wtap_strerror(write_err)); |
||
1462 | goto error_on_exit; |
||
1463 | } |
||
1464 | } |
||
1465 | } /* split packet handling */ |
||
1466 | |||
1467 | if (check_startstop) { |
||
1468 | /* |
||
1469 | * Is the packet in the selected timeframe? |
||
1470 | * If the packet has no time stamp, the answer is "no". |
||
1471 | */ |
||
1472 | if (phdr->presence_flags & WTAP_HAS_TS) |
||
1473 | ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime); |
||
1474 | else |
||
1475 | ts_okay = FALSE; |
||
1476 | } else { |
||
1477 | /* |
||
1478 | * No selected timeframe, so all packets are "in the |
||
1479 | * selected timeframe". |
||
1480 | */ |
||
1481 | ts_okay = TRUE; |
||
1482 | } |
||
1483 | |||
1484 | if (ts_okay && ((!selected(count) && !keep_em) |
||
1485 | || (selected(count) && keep_em))) { |
||
1486 | |||
1487 | if (verbose && !dup_detect && !dup_detect_by_time) |
||
1488 | fprintf(stderr, "Packet: %u\n", count); |
||
1489 | |||
1490 | /* We simply write it, perhaps after truncating it; we could |
||
1491 | * do other things, like modify it. */ |
||
1492 | |||
1493 | phdr = wtap_phdr(wth); |
||
1494 | |||
1495 | if (snaplen != 0) { |
||
1496 | /* Limit capture length to snaplen */ |
||
1497 | if (phdr->caplen > snaplen) { |
||
1498 | /* Copy and change rather than modify returned phdr */ |
||
1499 | temp_phdr = *phdr; |
||
1500 | temp_phdr.caplen = snaplen; |
||
1501 | phdr = &temp_phdr; |
||
1502 | } |
||
1503 | /* If -L, also set reported length to snaplen */ |
||
1504 | if (adjlen && phdr->len > snaplen) { |
||
1505 | /* Copy and change rather than modify returned phdr */ |
||
1506 | temp_phdr = *phdr; |
||
1507 | temp_phdr.len = snaplen; |
||
1508 | phdr = &temp_phdr; |
||
1509 | } |
||
1510 | } |
||
1511 | |||
1512 | /* CHOP */ |
||
1513 | temp_phdr = *phdr; |
||
1514 | handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen); |
||
1515 | phdr = &temp_phdr; |
||
1516 | |||
1517 | if (phdr->presence_flags & WTAP_HAS_TS) { |
||
1518 | /* Do we adjust timestamps to ensure strict chronological |
||
1519 | * order? */ |
||
1520 | if (do_strict_time_adjustment) { |
||
1521 | if (previous_time.secs || previous_time.nsecs) { |
||
1522 | if (!strict_time_adj.is_negative) { |
||
1523 | nstime_t current; |
||
1524 | nstime_t delta; |
||
1525 | |||
1526 | current = phdr->ts; |
||
1527 | |||
1528 | nstime_delta(&delta, ¤t, &previous_time); |
||
1529 | |||
1530 | if (delta.secs < 0 || delta.nsecs < 0) { |
||
1531 | /* |
||
1532 | * A negative delta indicates that the current packet |
||
1533 | * has an absolute timestamp less than the previous packet |
||
1534 | * that it is being compared to. This is NOT a normal |
||
1535 | * situation since trace files usually have packets in |
||
1536 | * chronological order (oldest to newest). |
||
1537 | */ |
||
1538 | /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */ |
||
1539 | temp_phdr = *phdr; |
||
1540 | temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs; |
||
1541 | temp_phdr.ts.nsecs = previous_time.nsecs; |
||
1542 | if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) { |
||
1543 | /* carry */ |
||
1544 | temp_phdr.ts.secs++; |
||
1545 | temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION; |
||
1546 | } else { |
||
1547 | temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs; |
||
1548 | } |
||
1549 | phdr = &temp_phdr; |
||
1550 | } |
||
1551 | } else { |
||
1552 | /* |
||
1553 | * A negative strict time adjustment is requested. |
||
1554 | * Unconditionally set each timestamp to previous |
||
1555 | * packet's timestamp plus delta. |
||
1556 | */ |
||
1557 | temp_phdr = *phdr; |
||
1558 | temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs; |
||
1559 | temp_phdr.ts.nsecs = previous_time.nsecs; |
||
1560 | if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) { |
||
1561 | /* carry */ |
||
1562 | temp_phdr.ts.secs++; |
||
1563 | temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION; |
||
1564 | } else { |
||
1565 | temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs; |
||
1566 | } |
||
1567 | phdr = &temp_phdr; |
||
1568 | } |
||
1569 | } |
||
1570 | previous_time = phdr->ts; |
||
1571 | } |
||
1572 | |||
1573 | if (time_adj.tv.secs != 0) { |
||
1574 | temp_phdr = *phdr; |
||
1575 | if (time_adj.is_negative) |
||
1576 | temp_phdr.ts.secs -= time_adj.tv.secs; |
||
1577 | else |
||
1578 | temp_phdr.ts.secs += time_adj.tv.secs; |
||
1579 | phdr = &temp_phdr; |
||
1580 | } |
||
1581 | |||
1582 | if (time_adj.tv.nsecs != 0) { |
||
1583 | temp_phdr = *phdr; |
||
1584 | if (time_adj.is_negative) { /* subtract */ |
||
1585 | if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */ |
||
1586 | temp_phdr.ts.secs--; |
||
1587 | temp_phdr.ts.nsecs += ONE_BILLION; |
||
1588 | } |
||
1589 | temp_phdr.ts.nsecs -= time_adj.tv.nsecs; |
||
1590 | } else { /* add */ |
||
1591 | if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) { |
||
1592 | /* carry */ |
||
1593 | temp_phdr.ts.secs++; |
||
1594 | temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION; |
||
1595 | } else { |
||
1596 | temp_phdr.ts.nsecs += time_adj.tv.nsecs; |
||
1597 | } |
||
1598 | } |
||
1599 | phdr = &temp_phdr; |
||
1600 | } |
||
1601 | } /* time stamp adjustment */ |
||
1602 | |||
1603 | /* remove vlan info */ |
||
1604 | if (rem_vlan) { |
||
1605 | /* TODO: keep casting const like this? change pointer instead of value? */ |
||
1606 | remove_vlan_info(phdr, buf, (guint32 *) &phdr->caplen); |
||
1607 | } |
||
1608 | |||
1609 | /* suppress duplicates by packet window */ |
||
1610 | if (dup_detect) { |
||
1611 | if (is_duplicate(buf, phdr->caplen)) { |
||
1612 | if (verbose) { |
||
1613 | fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ", |
||
1614 | count, phdr->caplen); |
||
1615 | for (i = 0; i < 16; i++) |
||
1616 | fprintf(stderr, "%02x", |
||
1617 | (unsigned char)fd_hash[cur_dup_entry].digest[i]); |
||
1618 | fprintf(stderr, "\n"); |
||
1619 | } |
||
1620 | duplicate_count++; |
||
1621 | count++; |
||
1622 | continue; |
||
1623 | } else { |
||
1624 | if (verbose) { |
||
1625 | fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ", |
||
1626 | count, phdr->caplen); |
||
1627 | for (i = 0; i < 16; i++) |
||
1628 | fprintf(stderr, "%02x", |
||
1629 | (unsigned char)fd_hash[cur_dup_entry].digest[i]); |
||
1630 | fprintf(stderr, "\n"); |
||
1631 | } |
||
1632 | } |
||
1633 | } /* suppression of duplicates */ |
||
1634 | |||
1635 | if (phdr->presence_flags & WTAP_HAS_TS) { |
||
1636 | /* suppress duplicates by time window */ |
||
1637 | if (dup_detect_by_time) { |
||
1638 | nstime_t current; |
||
1639 | |||
1640 | current.secs = phdr->ts.secs; |
||
1641 | current.nsecs = phdr->ts.nsecs; |
||
1642 | |||
1643 | if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) { |
||
1644 | if (verbose) { |
||
1645 | fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ", |
||
1646 | count, phdr->caplen); |
||
1647 | for (i = 0; i < 16; i++) |
||
1648 | fprintf(stderr, "%02x", |
||
1649 | (unsigned char)fd_hash[cur_dup_entry].digest[i]); |
||
1650 | fprintf(stderr, "\n"); |
||
1651 | } |
||
1652 | duplicate_count++; |
||
1653 | count++; |
||
1654 | continue; |
||
1655 | } else { |
||
1656 | if (verbose) { |
||
1657 | fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ", |
||
1658 | count, phdr->caplen); |
||
1659 | for (i = 0; i < 16; i++) |
||
1660 | fprintf(stderr, "%02x", |
||
1661 | (unsigned char)fd_hash[cur_dup_entry].digest[i]); |
||
1662 | fprintf(stderr, "\n"); |
||
1663 | } |
||
1664 | } |
||
1665 | } |
||
1666 | } /* suppress duplicates by time window */ |
||
1667 | |||
1668 | if (change_offset > phdr->caplen) { |
||
1669 | fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n", |
||
1670 | change_offset, phdr->caplen, count); |
||
1671 | } |
||
1672 | |||
1673 | /* Random error mutation */ |
||
1674 | if (err_prob > 0.0 && change_offset <= phdr->caplen) { |
||
1675 | int real_data_start = 0; |
||
1676 | |||
1677 | /* Protect non-protocol data */ |
||
1678 | if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000) |
||
1679 | real_data_start = find_dct2000_real_data(buf); |
||
1680 | |||
1681 | real_data_start += change_offset; |
||
1682 | |||
1683 | for (i = real_data_start; i < (int) phdr->caplen; i++) { |
||
1684 | if (rand() <= err_prob * RAND_MAX) { |
||
1685 | err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1); |
||
1686 | |||
1687 | if (err_type < ERR_WT_BIT) { |
||
1688 | buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1)); |
||
1689 | err_type = ERR_WT_TOTAL; |
||
1690 | } else { |
||
1691 | err_type -= ERR_WT_BYTE; |
||
1692 | } |
||
1693 | |||
1694 | if (err_type < ERR_WT_BYTE) { |
||
1695 | buf[i] = rand() / (RAND_MAX / 255 + 1); |
||
1696 | err_type = ERR_WT_TOTAL; |
||
1697 | } else { |
||
1698 | err_type -= ERR_WT_BYTE; |
||
1699 | } |
||
1700 | |||
1701 | if (err_type < ERR_WT_ALNUM) { |
||
1702 | buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)]; |
||
1703 | err_type = ERR_WT_TOTAL; |
||
1704 | } else { |
||
1705 | err_type -= ERR_WT_ALNUM; |
||
1706 | } |
||
1707 | |||
1708 | if (err_type < ERR_WT_FMT) { |
||
1709 | if ((unsigned int)i < phdr->caplen - 2) |
||
1710 | g_strlcpy((char*) &buf[i], "%s", 2); |
||
1711 | err_type = ERR_WT_TOTAL; |
||
1712 | } else { |
||
1713 | err_type -= ERR_WT_FMT; |
||
1714 | } |
||
1715 | |||
1716 | if (err_type < ERR_WT_AA) { |
||
1717 | for (j = i; j < (int) phdr->caplen; j++) |
||
1718 | buf[j] = 0xAA; |
||
1719 | i = phdr->caplen; |
||
1720 | } |
||
1721 | } |
||
1722 | } |
||
1723 | } /* random error mutation */ |
||
1724 | |||
1725 | /* Find a packet comment we may need to write */ |
||
1726 | if (frames_user_comments) { |
||
1727 | const char *comment = |
||
1728 | (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count)); |
||
1729 | if (comment != NULL) { |
||
1730 | /* Copy and change rather than modify returned phdr */ |
||
1731 | temp_phdr = *phdr; |
||
1732 | temp_phdr.opt_comment = g_strdup(comment); |
||
1733 | phdr = &temp_phdr; |
||
1734 | } |
||
1735 | } |
||
1736 | |||
1737 | /* Attempt to dump out current frame to the output file */ |
||
1738 | if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) { |
||
1739 | switch (write_err) { |
||
1740 | case WTAP_ERR_UNWRITABLE_ENCAP: |
||
1741 | /* |
||
1742 | * This is a problem with the particular frame we're |
||
1743 | * writing and the file type and subtype we're |
||
1744 | * writing; note that, and report the frame number |
||
1745 | * and file type/subtype. |
||
1746 | */ |
||
1747 | fprintf(stderr, |
||
1748 | "editcap: Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n", |
||
1749 | read_count, argv[optind], |
||
1750 | wtap_file_type_subtype_string(out_file_type_subtype)); |
||
1751 | break; |
||
1752 | |||
1753 | case WTAP_ERR_PACKET_TOO_LARGE: |
||
1754 | /* |
||
1755 | * This is a problem with the particular frame we're |
||
1756 | * writing and the file type and subtype we're |
||
1757 | * writing; note that, and report the frame number |
||
1758 | * and file type/subtype. |
||
1759 | */ |
||
1760 | fprintf(stderr, |
||
1761 | "editcap: Frame %u of \"%s\" is too large for a \"%s\" file.\n", |
||
1762 | read_count, argv[optind], |
||
1763 | wtap_file_type_subtype_string(out_file_type_subtype)); |
||
1764 | break; |
||
1765 | |||
1766 | case WTAP_ERR_UNWRITABLE_REC_TYPE: |
||
1767 | /* |
||
1768 | * This is a problem with the particular record we're |
||
1769 | * writing and the file type and subtype we're |
||
1770 | * writing; note that, and report the record number |
||
1771 | * and file type/subtype. |
||
1772 | */ |
||
1773 | fprintf(stderr, |
||
1774 | "editcap: Record %u of \"%s\" has a record type that can't be saved in a \"%s\" file.\n", |
||
1775 | read_count, argv[optind], |
||
1776 | wtap_file_type_subtype_string(out_file_type_subtype)); |
||
1777 | break; |
||
1778 | |||
1779 | case WTAP_ERR_UNWRITABLE_REC_DATA: |
||
1780 | /* |
||
1781 | * This is a problem with the particular record we're |
||
1782 | * writing and the file type and subtype we're |
||
1783 | * writing; note that, and report the record number |
||
1784 | * and file type/subtype. |
||
1785 | */ |
||
1786 | fprintf(stderr, |
||
1787 | "editcap: Record %u of \"%s\" has data that can't be saved in a \"%s\" file.\n(%s)\n", |
||
1788 | read_count, argv[optind], |
||
1789 | wtap_file_type_subtype_string(out_file_type_subtype), |
||
1790 | write_err_info != NULL ? write_err_info : "no information supplied"); |
||
1791 | g_free(write_err_info); |
||
1792 | break; |
||
1793 | |||
1794 | default: |
||
1795 | fprintf(stderr, "editcap: Error writing to %s: %s\n", |
||
1796 | filename, wtap_strerror(write_err)); |
||
1797 | break; |
||
1798 | } |
||
1799 | goto error_on_exit; |
||
1800 | } |
||
1801 | written_count++; |
||
1802 | } |
||
1803 | count++; |
||
1804 | } |
||
1805 | |||
1806 | g_free(fprefix); |
||
1807 | g_free(fsuffix); |
||
1808 | |||
1809 | if (read_err != 0) { |
||
1810 | /* Print a message noting that the read failed somewhere along the |
||
1811 | * line. */ |
||
1812 | fprintf(stderr, |
||
1813 | "editcap: An error occurred while reading \"%s\": %s.\n", |
||
1814 | argv[optind], wtap_strerror(read_err)); |
||
1815 | if (read_err_info != NULL) { |
||
1816 | fprintf(stderr, "(%s)\n", read_err_info); |
||
1817 | g_free(read_err_info); |
||
1818 | } |
||
1819 | } |
||
1820 | |||
1821 | if (!pdh) { |
||
1822 | /* No valid packages found, open the outfile so we can write an |
||
1823 | * empty header */ |
||
1824 | g_free (filename); |
||
1825 | filename = g_strdup(argv[optind+1]); |
||
1826 | |||
1827 | pdh = editcap_dump_open(filename, |
||
1828 | snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth), |
||
1829 | shb_hdrs, idb_inf, nrb_hdrs, &write_err); |
||
1830 | if (pdh == NULL) { |
||
1831 | fprintf(stderr, "editcap: Can't open or create %s: %s\n", |
||
1832 | filename, wtap_strerror(write_err)); |
||
1833 | goto error_on_exit; |
||
1834 | } |
||
1835 | } |
||
1836 | |||
1837 | g_free(idb_inf); |
||
1838 | idb_inf = NULL; |
||
1839 | |||
1840 | if (!wtap_dump_close(pdh, &write_err)) { |
||
1841 | fprintf(stderr, "editcap: Error writing to %s: %s\n", filename, |
||
1842 | wtap_strerror(write_err)); |
||
1843 | goto error_on_exit; |
||
1844 | } |
||
1845 | wtap_block_array_free(shb_hdrs); |
||
1846 | shb_hdrs = NULL; |
||
1847 | wtap_block_array_free(nrb_hdrs); |
||
1848 | nrb_hdrs = NULL; |
||
1849 | g_free(filename); |
||
1850 | |||
1851 | if (frames_user_comments) { |
||
1852 | g_tree_destroy(frames_user_comments); |
||
1853 | } |
||
1854 | } |
||
1855 | |||
1856 | if (dup_detect) { |
||
1857 | fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate window of %i packets.\n", |
||
1858 | count - 1, plurality(count - 1, "", "s"), duplicate_count, |
||
1859 | plurality(duplicate_count, "", "s"), dup_window); |
||
1860 | } else if (dup_detect_by_time) { |
||
1861 | fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n", |
||
1862 | count - 1, plurality(count - 1, "", "s"), duplicate_count, |
||
1863 | plurality(duplicate_count, "", "s"), |
||
1864 | (long)relative_time_window.secs, |
||
1865 | (long int)relative_time_window.nsecs); |
||
1866 | } |
||
1867 | |||
1868 | return 0; |
||
1869 | |||
1870 | error_on_exit: |
||
1871 | wtap_block_array_free(shb_hdrs); |
||
1872 | wtap_block_array_free(nrb_hdrs); |
||
1873 | g_free(idb_inf); |
||
1874 | exit(2); |
||
1875 | } |
||
1876 | |||
1877 | /* Skip meta-information read from file to return offset of real |
||
1878 | * protocol data */ |
||
1879 | static int |
||
1880 | find_dct2000_real_data(guint8 *buf) |
||
1881 | { |
||
1882 | int n = 0; |
||
1883 | |||
1884 | for (n = 0; buf[n] != '\0'; n++); /* Context name */ |
||
1885 | n++; |
||
1886 | n++; /* Context port number */ |
||
1887 | for (; buf[n] != '\0'; n++); /* Timestamp */ |
||
1888 | n++; |
||
1889 | for (; buf[n] != '\0'; n++); /* Protocol name */ |
||
1890 | n++; |
||
1891 | for (; buf[n] != '\0'; n++); /* Variant number (as string) */ |
||
1892 | n++; |
||
1893 | for (; buf[n] != '\0'; n++); /* Outhdr (as string) */ |
||
1894 | n++; |
||
1895 | n += 2; /* Direction & encap */ |
||
1896 | |||
1897 | return n; |
||
1898 | } |
||
1899 | |||
1900 | /* |
||
1901 | * We support up to 2 chopping regions in a single pass: one specified by the |
||
1902 | * positive chop length, and one by the negative chop length. |
||
1903 | */ |
||
1904 | static void |
||
1905 | handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr, |
||
1906 | const struct wtap_pkthdr *in_phdr, guint8 **buf, |
||
1907 | gboolean adjlen) |
||
1908 | { |
||
1909 | /* Only packets can be chopped. */ |
||
1910 | if (in_phdr->rec_type != REC_TYPE_PACKET) |
||
1911 | return; |
||
1912 | |||
1913 | /* If we're not chopping anything from one side, then the offset for that |
||
1914 | * side is meaningless. */ |
||
1915 | if (chop.len_begin == 0) |
||
1916 | chop.off_begin_pos = chop.off_begin_neg = 0; |
||
1917 | if (chop.len_end == 0) |
||
1918 | chop.off_end_pos = chop.off_end_neg = 0; |
||
1919 | |||
1920 | if (chop.off_begin_neg < 0) { |
||
1921 | chop.off_begin_pos += in_phdr->caplen + chop.off_begin_neg; |
||
1922 | chop.off_begin_neg = 0; |
||
1923 | } |
||
1924 | if (chop.off_end_pos > 0) { |
||
1925 | chop.off_end_neg += chop.off_end_pos - in_phdr->caplen; |
||
1926 | chop.off_end_pos = 0; |
||
1927 | } |
||
1928 | |||
1929 | /* If we've crossed chopping regions, swap them */ |
||
1930 | if (chop.len_begin && chop.len_end) { |
||
1931 | if (chop.off_begin_pos > ((int)in_phdr->caplen + chop.off_end_neg)) { |
||
1932 | int tmp_len, tmp_off; |
||
1933 | |||
1934 | tmp_off = in_phdr->caplen + chop.off_end_neg + chop.len_end; |
||
1935 | tmp_len = -chop.len_end; |
||
1936 | |||
1937 | chop.off_end_neg = chop.len_begin + chop.off_begin_pos - in_phdr->caplen; |
||
1938 | chop.len_end = -chop.len_begin; |
||
1939 | |||
1940 | chop.len_begin = tmp_len; |
||
1941 | chop.off_begin_pos = tmp_off; |
||
1942 | } |
||
1943 | } |
||
1944 | |||
1945 | /* Make sure we don't chop off more than we have available */ |
||
1946 | if (in_phdr->caplen < (guint32)(chop.off_begin_pos - chop.off_end_neg)) { |
||
1947 | chop.len_begin = 0; |
||
1948 | chop.len_end = 0; |
||
1949 | } |
||
1950 | if ((guint32)(chop.len_begin - chop.len_end) > |
||
1951 | (in_phdr->caplen - (guint32)(chop.off_begin_pos - chop.off_end_neg))) { |
||
1952 | chop.len_begin = in_phdr->caplen - (chop.off_begin_pos - chop.off_end_neg); |
||
1953 | chop.len_end = 0; |
||
1954 | } |
||
1955 | |||
1956 | /* Handle chopping from the beginning. Note that if a beginning offset |
||
1957 | * was specified, we need to keep that piece */ |
||
1958 | if (chop.len_begin > 0) { |
||
1959 | *out_phdr = *in_phdr; |
||
1960 | |||
1961 | if (chop.off_begin_pos > 0) { |
||
1962 | memmove(*buf + chop.off_begin_pos, |
||
1963 | *buf + chop.off_begin_pos + chop.len_begin, |
||
1964 | out_phdr->caplen - chop.len_begin); |
||
1965 | } else { |
||
1966 | *buf += chop.len_begin; |
||
1967 | } |
||
1968 | out_phdr->caplen -= chop.len_begin; |
||
1969 | |||
1970 | if (adjlen) { |
||
1971 | if (in_phdr->len > (guint32)chop.len_begin) |
||
1972 | out_phdr->len -= chop.len_begin; |
||
1973 | else |
||
1974 | out_phdr->len = 0; |
||
1975 | } |
||
1976 | in_phdr = out_phdr; |
||
1977 | } |
||
1978 | |||
1979 | /* Handle chopping from the end. Note that if an ending offset was |
||
1980 | * specified, we need to keep that piece */ |
||
1981 | if (chop.len_end < 0) { |
||
1982 | *out_phdr = *in_phdr; |
||
1983 | |||
1984 | if (chop.off_end_neg < 0) { |
||
1985 | memmove(*buf + (gint)out_phdr->caplen + (chop.len_end + chop.off_end_neg), |
||
1986 | *buf + (gint)out_phdr->caplen + chop.off_end_neg, |
||
1987 | -chop.off_end_neg); |
||
1988 | } |
||
1989 | out_phdr->caplen += chop.len_end; |
||
1990 | |||
1991 | if (adjlen) { |
||
1992 | if (((signed int) in_phdr->len + chop.len_end) > 0) |
||
1993 | out_phdr->len += chop.len_end; |
||
1994 | else |
||
1995 | out_phdr->len = 0; |
||
1996 | } |
||
1997 | /*in_phdr = out_phdr;*/ |
||
1998 | } |
||
1999 | } |
||
2000 | |||
2001 | /* |
||
2002 | * Editor modelines - http://www.wireshark.org/tools/modelines.html |
||
2003 | * |
||
2004 | * Local variables: |
||
2005 | * c-basic-offset: 4 |
||
2006 | * tab-width: 8 |
||
2007 | * indent-tabs-mode: nil |
||
2008 | * End: |
||
2009 | * |
||
2010 | * vi: set shiftwidth=4 tabstop=8 expandtab: |
||
2011 | * :indentSize=4:tabSize=8:noTabs=true: |
||
2012 | */ |