1 /* Edit capture files. We can delete packets, adjust timestamps, or
2 * simply convert from one format to another format.
4 * Originally written by Richard Sharpe.
5 * Improved by Guy Harris.
6 * Further improved by Richard Sharpe.
8 * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39 * Just make sure we include the prototype for strptime as well
40 * (needed for glibc 2.2) but make sure we do this only if not
55 #ifdef HAVE_SYS_TIME_H
62 #include "wsutil/wsgetopt.h"
66 #include <wsutil/file_util.h>
67 #include <wsutil/unicode-utils.h>
68 #include <process.h> /* getpid */
69 #ifdef HAVE_WINSOCK2_H
74 #ifdef NEED_STRPTIME_H
75 # include "wsutil/strptime.h"
78 #include <wsutil/privileges.h>
79 #include <wsutil/report_err.h>
80 #include <wsutil/strnatcmp.h>
81 #include <wsutil/md5.h>
84 * The symbols declared in the below are exported from libwireshark,
85 * but we don't want to link whole libwireshark to editcap.
86 * We link the object directly instead and this needs a little trick
87 * with the WS_BUILD_DLL #define.
90 #define RESET_SYMBOL_EXPORT /* wsutil/wsgetopt.h set export behavior above. */
91 #include "epan/plugins.h"
92 #include "epan/filesystem.h"
94 #define RESET_SYMBOL_EXPORT
96 #include "svnversion.h"
98 #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
101 * Some globals so we can pass things to various routines
110 * Duplicate frame detection
112 typedef struct _fd_hash_t
{
113 md5_byte_t digest
[16];
118 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
119 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
121 static fd_hash_t fd_hash
[MAX_DUP_DEPTH
];
122 static int dup_window
= DEFAULT_DUP_DEPTH
;
123 static int cur_dup_entry
= 0;
125 #define ONE_MILLION 1000000
126 #define ONE_BILLION 1000000000
128 /* Weights of different errors we can introduce */
129 /* We should probably make these command-line arguments */
130 /* XXX - Should we add a bit-level error? */
131 #define ERR_WT_BIT 5 /* Flip a random bit */
132 #define ERR_WT_BYTE 5 /* Substitute a random byte */
133 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
134 #define ERR_WT_FMT 2 /* Substitute "%s" */
135 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
136 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
138 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
139 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
141 struct time_adjustment
{
146 typedef struct _chop_t
{
155 #define MAX_SELECTIONS 512
156 static struct select_item selectfrm
[MAX_SELECTIONS
];
157 static int max_selected
= -1;
158 static int keep_em
= 0;
159 #ifdef PCAP_NG_DEFAULT
160 static int out_file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_PCAPNG
; /* default to pcapng */
162 static int out_file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_PCAP
; /* default to pcap */
164 static int out_frame_type
= -2; /* Leave frame type alone */
165 static int verbose
= 0; /* Not so verbose */
166 static struct time_adjustment time_adj
= {{0, 0}, 0}; /* no adjustment */
167 static nstime_t relative_time_window
= {0, 0}; /* de-dup time window */
168 static double err_prob
= 0.0;
169 static time_t starttime
= 0;
170 static time_t stoptime
= 0;
171 static gboolean check_startstop
= FALSE
;
172 static gboolean dup_detect
= FALSE
;
173 static gboolean dup_detect_by_time
= FALSE
;
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 */
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
,
185 abs_time_to_str_with_sec_resolution(const nstime_t
*abs_time
)
188 gchar
*buf
= (gchar
*)g_malloc(16);
190 #if (defined _WIN32) && (_MSC_VER < 1500)
191 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
192 /* XXX - find the exact value that still does work */
193 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
194 if (abs_time
->secs
> 2000000000)
198 tmp
= localtime(&abs_time
->secs
);
201 g_snprintf(buf
, 16, "%d%02d%02d%02d%02d%02d",
216 fileset_get_filename_by_pattern(guint idx
, const nstime_t
*time_val
,
217 gchar
*fprefix
, gchar
*fsuffix
)
223 timestr
= abs_time_to_str_with_sec_resolution(time_val
);
224 g_snprintf(filenum
, sizeof(filenum
), "%05u", idx
% RINGBUFFER_MAX_NUM_FILES
);
225 abs_str
= g_strconcat(fprefix
, "_", filenum
, "_", timestr
, fsuffix
, NULL
);
232 fileset_extract_prefix_suffix(const char *fname
, gchar
**fprefix
, gchar
**fsuffix
)
234 char *pfx
, *last_pathsep
;
237 save_file
= g_strdup(fname
);
238 if (save_file
== NULL
) {
239 fprintf(stderr
, "editcap: Out of memory\n");
243 last_pathsep
= strrchr(save_file
, G_DIR_SEPARATOR
);
244 pfx
= strrchr(save_file
,'.');
245 if (pfx
!= NULL
&& (last_pathsep
== NULL
|| pfx
> last_pathsep
)) {
246 /* The pathname has a "." in it, and it's in the last component
247 * of the pathname (because there is either only one component,
248 * i.e. last_pathsep is null as there are no path separators,
249 * or the "." is after the path separator before the last
252 * Treat it as a separator between the rest of the file name and
253 * the file name suffix, and arrange that the names given to the
254 * ring buffer files have the specified suffix, i.e. put the
255 * changing part of the name *before* the suffix. */
257 *fprefix
= g_strdup(save_file
);
258 pfx
[0] = '.'; /* restore capfile_name */
259 *fsuffix
= g_strdup(pfx
);
261 /* Either there's no "." in the pathname, or it's in a directory
262 * component, so the last component has no suffix. */
263 *fprefix
= g_strdup(save_file
);
270 /* Add a selection item, a simple parser for now */
272 add_selection(char *sel
)
277 if (++max_selected
>= MAX_SELECTIONS
) {
278 /* Let the user know we stopped selecting */
279 fprintf(stderr
, "Out of room for packet selections!\n");
284 fprintf(stderr
, "Add_Selected: %s\n", sel
);
286 if ((locn
= strchr(sel
, '-')) == NULL
) { /* No dash, so a single number? */
288 fprintf(stderr
, "Not inclusive ...");
290 selectfrm
[max_selected
].inclusive
= 0;
291 selectfrm
[max_selected
].first
= atoi(sel
);
294 fprintf(stderr
, " %i\n", selectfrm
[max_selected
].first
);
297 fprintf(stderr
, "Inclusive ...");
300 selectfrm
[max_selected
].inclusive
= 1;
301 selectfrm
[max_selected
].first
= atoi(sel
);
302 selectfrm
[max_selected
].second
= atoi(next
);
305 fprintf(stderr
, " %i, %i\n", selectfrm
[max_selected
].first
,
306 selectfrm
[max_selected
].second
);
312 /* Was the packet selected? */
319 for (i
= 0; i
<= max_selected
; i
++) {
320 if (selectfrm
[i
].inclusive
) {
321 if (selectfrm
[i
].first
<= recno
&& selectfrm
[i
].second
>= recno
)
324 if (recno
== selectfrm
[i
].first
)
332 /* is the packet in the selected timeframe */
334 check_timestamp(wtap
*wth
)
336 struct wtap_pkthdr
* pkthdr
= wtap_phdr(wth
);
338 return (pkthdr
->ts
.secs
>= starttime
) && (pkthdr
->ts
.secs
< stoptime
);
342 set_time_adjustment(char *optarg_str_p
)
351 /* skip leading whitespace */
352 while (*optarg_str_p
== ' ' || *optarg_str_p
== '\t')
355 /* check for a negative adjustment */
356 if (*optarg_str_p
== '-') {
357 time_adj
.is_negative
= 1;
361 /* collect whole number of seconds, if any */
362 if (*optarg_str_p
== '.') { /* only fractional (i.e., .5 is ok) */
366 val
= strtol(optarg_str_p
, &frac
, 10);
367 if (frac
== NULL
|| frac
== optarg_str_p
368 || val
== LONG_MIN
|| val
== LONG_MAX
) {
369 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
373 if (val
< 0) { /* implies '--' since we caught '-' above */
374 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
379 time_adj
.tv
.tv_sec
= val
;
381 /* now collect the partial seconds, if any */
382 if (*frac
!= '\0') { /* chars left, so get fractional part */
383 val
= strtol(&(frac
[1]), &end
, 10);
384 /* if more than 6 fractional digits truncate to 6 */
385 if ((end
- &(frac
[1])) > 6) {
386 frac
[7] = 't'; /* 't' for truncate */
387 val
= strtol(&(frac
[1]), &end
, 10);
389 if (*frac
!= '.' || end
== NULL
|| end
== frac
|| val
< 0
390 || val
> ONE_MILLION
|| val
== LONG_MIN
|| val
== LONG_MAX
) {
391 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
396 return; /* no fractional digits */
399 /* adjust fractional portion from fractional to numerator
400 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
401 if (frac
&& end
) { /* both are valid */
402 frac_digits
= end
- frac
- 1; /* fractional digit count (remember '.') */
403 while(frac_digits
< 6) { /* this is frac of 10^6 */
408 time_adj
.tv
.tv_usec
= (int)val
;
412 set_strict_time_adj(char *optarg_str_p
)
421 /* skip leading whitespace */
422 while (*optarg_str_p
== ' ' || *optarg_str_p
== '\t')
426 * check for a negative adjustment
427 * A negative strict adjustment value is a flag
428 * to adjust all frames by the specifed delta time.
430 if (*optarg_str_p
== '-') {
431 strict_time_adj
.is_negative
= 1;
435 /* collect whole number of seconds, if any */
436 if (*optarg_str_p
== '.') { /* only fractional (i.e., .5 is ok) */
440 val
= strtol(optarg_str_p
, &frac
, 10);
441 if (frac
== NULL
|| frac
== optarg_str_p
442 || val
== LONG_MIN
|| val
== LONG_MAX
) {
443 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
447 if (val
< 0) { /* implies '--' since we caught '-' above */
448 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
453 strict_time_adj
.tv
.tv_sec
= val
;
455 /* now collect the partial seconds, if any */
456 if (*frac
!= '\0') { /* chars left, so get fractional part */
457 val
= strtol(&(frac
[1]), &end
, 10);
458 /* if more than 6 fractional digits truncate to 6 */
459 if ((end
- &(frac
[1])) > 6) {
460 frac
[7] = 't'; /* 't' for truncate */
461 val
= strtol(&(frac
[1]), &end
, 10);
463 if (*frac
!= '.' || end
== NULL
|| end
== frac
|| val
< 0
464 || val
> ONE_MILLION
|| val
== LONG_MIN
|| val
== LONG_MAX
) {
465 fprintf(stderr
, "editcap: \"%s\" isn't a valid time adjustment\n",
470 return; /* no fractional digits */
473 /* adjust fractional portion from fractional to numerator
474 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
475 if (frac
&& end
) { /* both are valid */
476 frac_digits
= end
- frac
- 1; /* fractional digit count (remember '.') */
477 while(frac_digits
< 6) { /* this is frac of 10^6 */
482 strict_time_adj
.tv
.tv_usec
= (int)val
;
486 set_rel_time(char *optarg_str_p
)
495 /* skip leading whitespace */
496 while (*optarg_str_p
== ' ' || *optarg_str_p
== '\t')
499 /* ignore negative adjustment */
500 if (*optarg_str_p
== '-')
503 /* collect whole number of seconds, if any */
504 if (*optarg_str_p
== '.') { /* only fractional (i.e., .5 is ok) */
508 val
= strtol(optarg_str_p
, &frac
, 10);
509 if (frac
== NULL
|| frac
== optarg_str_p
510 || val
== LONG_MIN
|| val
== LONG_MAX
) {
511 fprintf(stderr
, "1: editcap: \"%s\" isn't a valid rel time value\n",
515 if (val
< 0) { /* implies '--' since we caught '-' above */
516 fprintf(stderr
, "2: editcap: \"%s\" isn't a valid rel time value\n",
521 relative_time_window
.secs
= val
;
523 /* now collect the partial seconds, if any */
524 if (*frac
!= '\0') { /* chars left, so get fractional part */
525 val
= strtol(&(frac
[1]), &end
, 10);
526 /* if more than 9 fractional digits truncate to 9 */
527 if ((end
- &(frac
[1])) > 9) {
528 frac
[10] = 't'; /* 't' for truncate */
529 val
= strtol(&(frac
[1]), &end
, 10);
531 if (*frac
!= '.' || end
== NULL
|| end
== frac
|| val
< 0
532 || val
> ONE_BILLION
|| val
== LONG_MIN
|| val
== LONG_MAX
) {
533 fprintf(stderr
, "3: editcap: \"%s\" isn't a valid rel time value\n",
538 return; /* no fractional digits */
541 /* adjust fractional portion from fractional to numerator
542 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
543 if (frac
&& end
) { /* both are valid */
544 frac_digits
= end
- frac
- 1; /* fractional digit count (remember '.') */
545 while(frac_digits
< 9) { /* this is frac of 10^9 */
550 relative_time_window
.nsecs
= (int)val
;
554 is_duplicate(guint8
* fd
, guint32 len
) {
559 if (cur_dup_entry
>= dup_window
)
562 /* Calculate our digest */
564 md5_append(&ms
, fd
, len
);
565 md5_finish(&ms
, fd_hash
[cur_dup_entry
].digest
);
567 fd_hash
[cur_dup_entry
].len
= len
;
569 /* Look for duplicates */
570 for (i
= 0; i
< dup_window
; i
++) {
571 if (i
== cur_dup_entry
)
574 if (fd_hash
[i
].len
== fd_hash
[cur_dup_entry
].len
575 && memcmp(fd_hash
[i
].digest
, fd_hash
[cur_dup_entry
].digest
, 16) == 0) {
584 is_duplicate_rel_time(guint8
* fd
, guint32 len
, const nstime_t
*current
) {
589 if (cur_dup_entry
>= dup_window
)
592 /* Calculate our digest */
594 md5_append(&ms
, fd
, len
);
595 md5_finish(&ms
, fd_hash
[cur_dup_entry
].digest
);
597 fd_hash
[cur_dup_entry
].len
= len
;
598 fd_hash
[cur_dup_entry
].time
.secs
= current
->secs
;
599 fd_hash
[cur_dup_entry
].time
.nsecs
= current
->nsecs
;
602 * Look for relative time related duplicates.
603 * This is hopefully a reasonably efficient mechanism for
604 * finding duplicates by rel time in the fd_hash[] cache.
605 * We check starting from the most recently added hash
606 * entries and work backwards towards older packets.
607 * This approach allows the dup test to be terminated
608 * when the relative time of a cached entry is found to
609 * be beyond the dup time window.
611 * Of course this assumes that the input trace file is
612 * "well-formed" in the sense that the packet timestamps are
613 * in strict chronologically increasing order (which is NOT
614 * always the case!!).
616 * The fd_hash[] table was deliberatly created large (1,000,000).
617 * Looking for time related duplicates in large trace files with
618 * non-fractional dup time window values can potentially take
619 * a long time to complete.
622 for (i
= cur_dup_entry
- 1;; i
--) {
629 if (i
== cur_dup_entry
) {
631 * We've decremented back to where we started.
637 if (nstime_is_unset(&(fd_hash
[i
].time
))) {
639 * We've decremented to an unused fd_hash[] entry.
645 nstime_delta(&delta
, current
, &fd_hash
[i
].time
);
647 if (delta
.secs
< 0 || delta
.nsecs
< 0) {
649 * A negative delta implies that the current packet
650 * has an absolute timestamp less than the cached packet
651 * that it is being compared to. This is NOT a normal
652 * situation since trace files usually have packets in
653 * chronological order (oldest to newest).
655 * There are several possible ways to deal with this:
656 * 1. 'continue' dup checking with the next cached frame.
657 * 2. 'break' from looking for a duplicate of the current frame.
658 * 3. Take the absolute value of the delta and see if that
659 * falls within the specifed dup time window.
661 * Currently this code does option 1. But it would pretty
662 * easy to add yet-another-editcap-option to select one of
663 * the other behaviors for dealing with out-of-sequence
669 cmp
= nstime_cmp(&delta
, &relative_time_window
);
673 * The delta time indicates that we are now looking at
674 * cached packets beyond the specified dup time window.
678 } else if (fd_hash
[i
].len
== fd_hash
[cur_dup_entry
].len
679 && memcmp(fd_hash
[i
].digest
, fd_hash
[cur_dup_entry
].digest
, 16) == 0) {
688 usage(gboolean is_error
)
697 fprintf(output
, "Editcap %s"
699 " (" SVNVERSION
" from " SVNPATH
")"
702 fprintf(output
, "Edit and/or translate the format of capture files.\n");
703 fprintf(output
, "See http://www.wireshark.org for more information.\n");
704 fprintf(output
, "\n");
705 fprintf(output
, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
706 fprintf(output
, "\n");
707 fprintf(output
, "<infile> and <outfile> must both be present.\n");
708 fprintf(output
, "A single packet or a range of packets can be selected.\n");
709 fprintf(output
, "\n");
710 fprintf(output
, "Packet selection:\n");
711 fprintf(output
, " -r keep the selected packets; default is to delete them.\n");
712 fprintf(output
, " -A <start time> only output packets whose timestamp is after (or equal\n");
713 fprintf(output
, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
714 fprintf(output
, " -B <stop time> only output packets whose timestamp is before the\n");
715 fprintf(output
, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
716 fprintf(output
, "\n");
717 fprintf(output
, "Duplicate packet removal:\n");
718 fprintf(output
, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH
);
719 fprintf(output
, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
720 fprintf(output
, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH
);
721 fprintf(output
, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
722 fprintf(output
, " useful to print MD5 hashes.\n");
723 fprintf(output
, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
724 fprintf(output
, " LESS THAN <dup time window> prior to current packet.\n");
725 fprintf(output
, " A <dup time window> is specified in relative seconds\n");
726 fprintf(output
, " (e.g. 0.000001).\n");
727 fprintf(output
, "\n");
728 fprintf(output
, " NOTE: The use of the 'Duplicate packet removal' options with\n");
729 fprintf(output
, " other editcap options except -v may not always work as expected.\n");
730 fprintf(output
, " Specifically the -r, -t or -S options will very likely NOT have the\n");
731 fprintf(output
, " desired effect if combined with the -d, -D or -w.\n");
732 fprintf(output
, "\n");
733 fprintf(output
, "Packet manipulation:\n");
734 fprintf(output
, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
735 fprintf(output
, " -C [offset:]<choplen> chop each packet by <choplen> bytes. Positive values\n");
736 fprintf(output
, " chop at the packet beginning, negative values at the\n");
737 fprintf(output
, " packet end. If an optional offset precedes the length,\n");
738 fprintf(output
, " then the bytes chopped will be offset from that value.\n");
739 fprintf(output
, " Positive offsets are from the packet beginning,\n");
740 fprintf(output
, " negative offsets are from the packet end. You can use\n");
741 fprintf(output
, " this option more than once, allowing up to 2 chopping\n");
742 fprintf(output
, " regions within a packet provided that at least 1\n");
743 fprintf(output
, " choplen is positive and at least 1 is negative.\n");
744 fprintf(output
, " -L adjust the frame length when chopping and/or snapping\n");
745 fprintf(output
, " -t <time adjustment> adjust the timestamp of each packet;\n");
746 fprintf(output
, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
747 fprintf(output
, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
748 fprintf(output
, " strict chronological increasing order. The <strict\n");
749 fprintf(output
, " adjustment> is specified in relative seconds with\n");
750 fprintf(output
, " values of 0 or 0.000001 being the most reasonable.\n");
751 fprintf(output
, " A negative adjustment value will modify timestamps so\n");
752 fprintf(output
, " that each packet's delta time is the absolute value\n");
753 fprintf(output
, " of the adjustment specified. A value of -0 will set\n");
754 fprintf(output
, " all packets to the timestamp of the first packet.\n");
755 fprintf(output
, " -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n");
756 fprintf(output
, " a particular packet byte will be randomly changed.\n");
757 fprintf(output
, "\n");
758 fprintf(output
, "Output File(s):\n");
759 fprintf(output
, " -c <packets per file> split the packet output to different files based on\n");
760 fprintf(output
, " uniform packet counts with a maximum of\n");
761 fprintf(output
, " <packets per file> each.\n");
762 fprintf(output
, " -i <seconds per file> split the packet output to different files based on\n");
763 fprintf(output
, " uniform time intervals with a maximum of\n");
764 fprintf(output
, " <seconds per file> each.\n");
765 fprintf(output
, " -F <capture type> set the output file type; default is pcapng. An empty\n");
766 fprintf(output
, " \"-F\" option will list the file types.\n");
767 fprintf(output
, " -T <encap type> set the output file encapsulation type; default is the\n");
768 fprintf(output
, " same as the input file. An empty \"-T\" option will\n");
769 fprintf(output
, " list the encapsulation types.\n");
770 fprintf(output
, "\n");
771 fprintf(output
, "Miscellaneous:\n");
772 fprintf(output
, " -h display this help and exit.\n");
773 fprintf(output
, " -v verbose output.\n");
774 fprintf(output
, " If -v is used with any of the 'Duplicate Packet\n");
775 fprintf(output
, " Removal' options (-d, -D or -w) then Packet lengths\n");
776 fprintf(output
, " and MD5 hashes are printed to standard-out.\n");
777 fprintf(output
, "\n");
781 const char *sstr
; /* The short string */
782 const char *lstr
; /* The long string */
786 string_compare(gconstpointer a
, gconstpointer b
)
788 return strcmp(((const struct string_elem
*)a
)->sstr
,
789 ((const struct string_elem
*)b
)->sstr
);
793 string_nat_compare(gconstpointer a
, gconstpointer b
)
795 return strnatcmp(((const struct string_elem
*)a
)->sstr
,
796 ((const struct string_elem
*)b
)->sstr
);
800 string_elem_print(gpointer data
, gpointer not_used _U_
)
802 fprintf(stderr
, " %s - %s\n",
803 ((struct string_elem
*)data
)->sstr
,
804 ((struct string_elem
*)data
)->lstr
);
808 list_capture_types(void) {
810 struct string_elem
*captypes
;
813 captypes
= g_new(struct string_elem
,WTAP_NUM_FILE_TYPES_SUBTYPES
);
814 fprintf(stderr
, "editcap: The available capture file types for the \"-F\" flag are:\n");
815 for (i
= 0; i
< WTAP_NUM_FILE_TYPES_SUBTYPES
; i
++) {
816 if (wtap_dump_can_open(i
)) {
817 captypes
[i
].sstr
= wtap_file_type_subtype_short_string(i
);
818 captypes
[i
].lstr
= wtap_file_type_subtype_string(i
);
819 list
= g_slist_insert_sorted(list
, &captypes
[i
], string_compare
);
822 g_slist_foreach(list
, string_elem_print
, NULL
);
828 list_encap_types(void) {
830 struct string_elem
*encaps
;
833 encaps
= (struct string_elem
*)g_malloc(sizeof(struct string_elem
) * WTAP_NUM_ENCAP_TYPES
);
834 fprintf(stderr
, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
835 for (i
= 0; i
< WTAP_NUM_ENCAP_TYPES
; i
++) {
836 encaps
[i
].sstr
= wtap_encap_short_string(i
);
837 if (encaps
[i
].sstr
!= NULL
) {
838 encaps
[i
].lstr
= wtap_encap_string(i
);
839 list
= g_slist_insert_sorted(list
, &encaps
[i
], string_nat_compare
);
842 g_slist_foreach(list
, string_elem_print
, NULL
);
849 * Don't report failures to load plugins because most (non-wiretap) plugins
850 * *should* fail to load (because we're not linked against libwireshark and
851 * dissector plugins need libwireshark).
854 failure_message(const char *msg_format _U_
, va_list ap _U_
)
860 main(int argc
, char *argv
[])
868 guint32 snaplen
= 0; /* No limit */
869 chop_t chop
= {0, 0, 0, 0, 0, 0}; /* No chop */
870 gboolean adjlen
= FALSE
;
871 wtap_dumper
*pdh
= NULL
;
872 unsigned int count
= 1;
873 unsigned int duplicate_count
= 0;
875 struct wtap_pkthdr snap_phdr
;
876 const struct wtap_pkthdr
*phdr
;
878 wtapng_section_t
*shb_hdr
;
879 wtapng_iface_descriptions_t
*idb_inf
;
881 guint32 read_count
= 0;
882 int split_packet_count
= 0;
883 int written_count
= 0;
884 char *filename
= NULL
;
885 gboolean ts_okay
= TRUE
;
886 int secs_per_block
= 0;
888 nstime_t block_start
;
889 gchar
*fprefix
= NULL
;
890 gchar
*fsuffix
= NULL
;
894 char* init_progfile_dir_error
;
898 arg_list_utf_16to8(argc
, argv
);
899 create_app_running_mutex();
903 * Get credential information for later use.
905 init_process_policies();
908 /* Register wiretap plugins */
909 if ((init_progfile_dir_error
= init_progfile_dir(argv
[0], main
))) {
910 g_warning("editcap: init_progfile_dir(): %s", init_progfile_dir_error
);
911 g_free(init_progfile_dir_error
);
913 init_report_err(failure_message
,NULL
,NULL
,NULL
);
918 /* Process the options */
919 while ((opt
= getopt(argc
, argv
, "A:B:c:C:dD:E:F:hi:Lrs:S:t:T:vw:")) != -1) {
925 memset(&starttm
,0,sizeof(struct tm
));
927 if (!strptime(optarg
,"%Y-%m-%d %T", &starttm
)) {
928 fprintf(stderr
, "editcap: \"%s\" isn't a valid time format\n\n",
933 check_startstop
= TRUE
;
934 starttm
.tm_isdst
= -1;
936 starttime
= mktime(&starttm
);
944 memset(&stoptm
,0,sizeof(struct tm
));
946 if (!strptime(optarg
,"%Y-%m-%d %T", &stoptm
)) {
947 fprintf(stderr
, "editcap: \"%s\" isn't a valid time format\n\n",
951 check_startstop
= TRUE
;
952 stoptm
.tm_isdst
= -1;
953 stoptime
= mktime(&stoptm
);
958 split_packet_count
= (int)strtol(optarg
, &p
, 10);
959 if (p
== optarg
|| *p
!= '\0') {
960 fprintf(stderr
, "editcap: \"%s\" isn't a valid packet count\n",
964 if (split_packet_count
<= 0) {
965 fprintf(stderr
, "editcap: \"%d\" packet count must be larger than zero\n",
973 int choplen
= 0, chopoff
= 0;
975 switch (sscanf(optarg
, "%d:%d", &chopoff
, &choplen
)) {
976 case 1: /* only the chop length was specififed */
981 case 2: /* both an offset and chop length was specified */
985 fprintf(stderr
, "editcap: \"%s\" isn't a valid chop length or offset:length\n",
992 chop
.len_begin
+= choplen
;
994 chop
.off_begin_pos
+= chopoff
;
996 chop
.off_begin_neg
+= chopoff
;
997 } else if (choplen
< 0) {
998 chop
.len_end
+= choplen
;
1000 chop
.off_end_pos
+= chopoff
;
1002 chop
.off_end_neg
+= chopoff
;
1009 dup_detect_by_time
= FALSE
;
1010 dup_window
= DEFAULT_DUP_DEPTH
;
1015 dup_detect_by_time
= FALSE
;
1016 dup_window
= (int)strtol(optarg
, &p
, 10);
1017 if (p
== optarg
|| *p
!= '\0') {
1018 fprintf(stderr
, "editcap: \"%s\" isn't a valid duplicate window value\n",
1022 if (dup_window
< 0 || dup_window
> MAX_DUP_DEPTH
) {
1023 fprintf(stderr
, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
1024 dup_window
, MAX_DUP_DEPTH
);
1030 err_prob
= strtod(optarg
, &p
);
1031 if (p
== optarg
|| err_prob
< 0.0 || err_prob
> 1.0) {
1032 fprintf(stderr
, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
1036 srand( (unsigned int) (time(NULL
) + getpid()) );
1040 out_file_type_subtype
= wtap_short_string_to_file_type_subtype(optarg
);
1041 if (out_file_type_subtype
< 0) {
1042 fprintf(stderr
, "editcap: \"%s\" isn't a valid capture file type\n\n",
1044 list_capture_types();
1054 case 'i': /* break capture file based on time interval */
1055 secs_per_block
= atoi(optarg
);
1056 if (secs_per_block
<= 0) {
1057 fprintf(stderr
, "editcap: \"%s\" isn't a valid time interval\n\n",
1068 keep_em
= !keep_em
; /* Just invert */
1072 snaplen
= (guint32
)strtol(optarg
, &p
, 10);
1073 if (p
== optarg
|| *p
!= '\0') {
1074 fprintf(stderr
, "editcap: \"%s\" isn't a valid snapshot length\n",
1081 set_strict_time_adj(optarg
);
1082 do_strict_time_adjustment
= TRUE
;
1086 set_time_adjustment(optarg
);
1090 out_frame_type
= wtap_short_string_to_encap(optarg
);
1091 if (out_frame_type
< 0) {
1092 fprintf(stderr
, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1100 verbose
= !verbose
; /* Just invert */
1105 dup_detect_by_time
= TRUE
;
1106 dup_window
= MAX_DUP_DEPTH
;
1107 set_rel_time(optarg
);
1110 case '?': /* Bad options if GNU getopt */
1113 list_capture_types();
1128 fprintf(stderr
, "Optind = %i, argc = %i\n", optind
, argc
);
1131 if ((argc
- optind
) < 1) {
1136 if (check_startstop
&& !stoptime
) {
1139 /* XXX: will work until 2035 */
1140 memset(&stoptm
,0,sizeof(struct tm
));
1141 stoptm
.tm_year
= 135;
1142 stoptm
.tm_mday
= 31;
1145 stoptime
= mktime(&stoptm
);
1148 nstime_set_unset(&block_start
);
1150 if (starttime
> stoptime
) {
1151 fprintf(stderr
, "editcap: start time is after the stop time\n");
1155 if (split_packet_count
> 0 && secs_per_block
> 0) {
1156 fprintf(stderr
, "editcap: can't split on both packet count and time interval\n");
1157 fprintf(stderr
, "editcap: at the same time\n");
1161 wth
= wtap_open_offline(argv
[optind
], &err
, &err_info
, FALSE
);
1164 fprintf(stderr
, "editcap: Can't open %s: %s\n", argv
[optind
],
1165 wtap_strerror(err
));
1167 case WTAP_ERR_UNSUPPORTED
:
1168 case WTAP_ERR_UNSUPPORTED_ENCAP
:
1169 case WTAP_ERR_BAD_FILE
:
1170 fprintf(stderr
, "(%s)\n", err_info
);
1178 fprintf(stderr
, "File %s is a %s capture file.\n", argv
[optind
],
1179 wtap_file_type_subtype_string(wtap_file_type_subtype(wth
)));
1182 shb_hdr
= wtap_file_get_shb_info(wth
);
1183 idb_inf
= wtap_file_get_idb_info(wth
);
1186 * Now, process the rest, if any ... we only write if there is an extra
1187 * argument or so ...
1190 if ((argc
- optind
) >= 2) {
1191 if (out_frame_type
== -2)
1192 out_frame_type
= wtap_file_encap(wth
);
1194 for (i
= optind
+ 2; i
< argc
; i
++)
1195 if (add_selection(argv
[i
]) == FALSE
)
1198 if (dup_detect
|| dup_detect_by_time
) {
1199 for (i
= 0; i
< dup_window
; i
++) {
1200 memset(&fd_hash
[i
].digest
, 0, 16);
1202 nstime_set_unset(&fd_hash
[i
].time
);
1206 while (wtap_read(wth
, &err
, &err_info
, &data_offset
)) {
1209 phdr
= wtap_phdr(wth
);
1210 buf
= wtap_buf_ptr(wth
);
1212 if (nstime_is_unset(&block_start
)) { /* should only be the first packet */
1213 block_start
.secs
= phdr
->ts
.secs
;
1214 block_start
.nsecs
= phdr
->ts
.nsecs
;
1216 if (split_packet_count
> 0 || secs_per_block
> 0) {
1217 if (!fileset_extract_prefix_suffix(argv
[optind
+1], &fprefix
, &fsuffix
))
1220 filename
= fileset_get_filename_by_pattern(block_cnt
++, &phdr
->ts
, fprefix
, fsuffix
);
1222 filename
= g_strdup(argv
[optind
+1]);
1225 /* If we don't have an application name add Editcap */
1226 if (shb_hdr
->shb_user_appl
== NULL
) {
1227 g_snprintf(appname
, sizeof(appname
), "Editcap " VERSION
);
1228 shb_hdr
->shb_user_appl
= appname
;
1231 pdh
= wtap_dump_open_ng(filename
, out_file_type_subtype
, out_frame_type
,
1232 snaplen
? MIN(snaplen
, wtap_snapshot_length(wth
)) : wtap_snapshot_length(wth
),
1233 FALSE
/* compressed */, shb_hdr
, idb_inf
, &err
);
1236 fprintf(stderr
, "editcap: Can't open or create %s: %s\n",
1237 filename
, wtap_strerror(err
));
1244 if (secs_per_block
> 0) {
1245 while ((phdr
->ts
.secs
- block_start
.secs
> secs_per_block
)
1246 || (phdr
->ts
.secs
- block_start
.secs
== secs_per_block
1247 && phdr
->ts
.nsecs
>= block_start
.nsecs
)) { /* time for the next file */
1249 if (!wtap_dump_close(pdh
, &err
)) {
1250 fprintf(stderr
, "editcap: Error writing to %s: %s\n",
1251 filename
, wtap_strerror(err
));
1254 block_start
.secs
= block_start
.secs
+ secs_per_block
; /* reset for next interval */
1256 filename
= fileset_get_filename_by_pattern(block_cnt
++, &phdr
->ts
, fprefix
, fsuffix
);
1260 fprintf(stderr
, "Continuing writing in file %s\n", filename
);
1262 pdh
= wtap_dump_open_ng(filename
, out_file_type_subtype
, out_frame_type
,
1263 snaplen
? MIN(snaplen
, wtap_snapshot_length(wth
)) : wtap_snapshot_length(wth
),
1264 FALSE
/* compressed */, shb_hdr
, idb_inf
, &err
);
1267 fprintf(stderr
, "editcap: Can't open or create %s: %s\n",
1268 filename
, wtap_strerror(err
));
1274 if (split_packet_count
> 0) {
1275 /* time for the next file? */
1276 if (written_count
> 0 && written_count
% split_packet_count
== 0) {
1277 if (!wtap_dump_close(pdh
, &err
)) {
1278 fprintf(stderr
, "editcap: Error writing to %s: %s\n",
1279 filename
, wtap_strerror(err
));
1284 filename
= fileset_get_filename_by_pattern(block_cnt
++, &phdr
->ts
, fprefix
, fsuffix
);
1288 fprintf(stderr
, "Continuing writing in file %s\n", filename
);
1290 pdh
= wtap_dump_open_ng(filename
, out_file_type_subtype
, out_frame_type
,
1291 snaplen
? MIN(snaplen
, wtap_snapshot_length(wth
)) : wtap_snapshot_length(wth
),
1292 FALSE
/* compressed */, shb_hdr
, idb_inf
, &err
);
1294 fprintf(stderr
, "editcap: Can't open or create %s: %s\n",
1295 filename
, wtap_strerror(err
));
1301 if (check_startstop
)
1302 ts_okay
= check_timestamp(wth
);
1304 if (ts_okay
&& ((!selected(count
) && !keep_em
)
1305 || (selected(count
) && keep_em
))) {
1307 if (verbose
&& !dup_detect
&& !dup_detect_by_time
)
1308 fprintf(stderr
, "Packet: %u\n", count
);
1310 /* We simply write it, perhaps after truncating it; we could
1311 * do other things, like modify it. */
1313 phdr
= wtap_phdr(wth
);
1316 if (phdr
->caplen
> snaplen
) {
1318 snap_phdr
.caplen
= snaplen
;
1321 if (adjlen
&& phdr
->len
> snaplen
) {
1323 snap_phdr
.len
= snaplen
;
1330 handle_chopping(chop
, &snap_phdr
, phdr
, buf
, adjlen
);
1333 /* Do we adjust timestamps to ensure strict chronological
1335 if (do_strict_time_adjustment
) {
1336 if (previous_time
.secs
|| previous_time
.nsecs
) {
1337 if (!strict_time_adj
.is_negative
) {
1341 current
.secs
= phdr
->ts
.secs
;
1342 current
.nsecs
= phdr
->ts
.nsecs
;
1344 nstime_delta(&delta
, ¤t
, &previous_time
);
1346 if (delta
.secs
< 0 || delta
.nsecs
< 0) {
1348 * A negative delta indicates that the current packet
1349 * has an absolute timestamp less than the previous packet
1350 * that it is being compared to. This is NOT a normal
1351 * situation since trace files usually have packets in
1352 * chronological order (oldest to newest).
1354 /* printf("++out of order, need to adjust this packet!\n"); */
1356 snap_phdr
.ts
.secs
= previous_time
.secs
+ strict_time_adj
.tv
.tv_sec
;
1357 snap_phdr
.ts
.nsecs
= previous_time
.nsecs
;
1358 if (snap_phdr
.ts
.nsecs
+ strict_time_adj
.tv
.tv_usec
* 1000 > ONE_MILLION
* 1000) {
1360 snap_phdr
.ts
.secs
++;
1361 snap_phdr
.ts
.nsecs
+= (strict_time_adj
.tv
.tv_usec
- ONE_MILLION
) * 1000;
1363 snap_phdr
.ts
.nsecs
+= strict_time_adj
.tv
.tv_usec
* 1000;
1369 * A negative strict time adjustment is requested.
1370 * Unconditionally set each timestamp to previous
1371 * packet's timestamp plus delta.
1374 snap_phdr
.ts
.secs
= previous_time
.secs
+ strict_time_adj
.tv
.tv_sec
;
1375 snap_phdr
.ts
.nsecs
= previous_time
.nsecs
;
1376 if (snap_phdr
.ts
.nsecs
+ strict_time_adj
.tv
.tv_usec
* 1000 > ONE_MILLION
* 1000) {
1378 snap_phdr
.ts
.secs
++;
1379 snap_phdr
.ts
.nsecs
+= (strict_time_adj
.tv
.tv_usec
- ONE_MILLION
) * 1000;
1381 snap_phdr
.ts
.nsecs
+= strict_time_adj
.tv
.tv_usec
* 1000;
1386 previous_time
.secs
= phdr
->ts
.secs
;
1387 previous_time
.nsecs
= phdr
->ts
.nsecs
;
1390 /* assume that if the frame's tv_sec is 0, then
1391 * the timestamp isn't supported */
1392 if (phdr
->ts
.secs
> 0 && time_adj
.tv
.tv_sec
!= 0) {
1394 if (time_adj
.is_negative
)
1395 snap_phdr
.ts
.secs
-= time_adj
.tv
.tv_sec
;
1397 snap_phdr
.ts
.secs
+= time_adj
.tv
.tv_sec
;
1401 /* assume that if the frame's tv_sec is 0, then
1402 * the timestamp isn't supported */
1403 if (phdr
->ts
.secs
> 0 && time_adj
.tv
.tv_usec
!= 0) {
1405 if (time_adj
.is_negative
) { /* subtract */
1406 if (snap_phdr
.ts
.nsecs
/1000 < time_adj
.tv
.tv_usec
) { /* borrow */
1407 snap_phdr
.ts
.secs
--;
1408 snap_phdr
.ts
.nsecs
+= ONE_MILLION
* 1000;
1410 snap_phdr
.ts
.nsecs
-= time_adj
.tv
.tv_usec
* 1000;
1412 if (snap_phdr
.ts
.nsecs
+ time_adj
.tv
.tv_usec
* 1000 > ONE_MILLION
* 1000) {
1414 snap_phdr
.ts
.secs
++;
1415 snap_phdr
.ts
.nsecs
+= (time_adj
.tv
.tv_usec
- ONE_MILLION
) * 1000;
1417 snap_phdr
.ts
.nsecs
+= time_adj
.tv
.tv_usec
* 1000;
1423 /* suppress duplicates by packet window */
1425 if (is_duplicate(buf
, phdr
->caplen
)) {
1427 fprintf(stdout
, "Skipped: %u, Len: %u, MD5 Hash: ",
1428 count
, phdr
->caplen
);
1429 for (i
= 0; i
< 16; i
++)
1430 fprintf(stdout
, "%02x",
1431 (unsigned char)fd_hash
[cur_dup_entry
].digest
[i
]);
1432 fprintf(stdout
, "\n");
1439 fprintf(stdout
, "Packet: %u, Len: %u, MD5 Hash: ",
1440 count
, phdr
->caplen
);
1441 for (i
= 0; i
< 16; i
++)
1442 fprintf(stdout
, "%02x",
1443 (unsigned char)fd_hash
[cur_dup_entry
].digest
[i
]);
1444 fprintf(stdout
, "\n");
1449 /* suppress duplicates by time window */
1450 if (dup_detect_by_time
) {
1453 current
.secs
= phdr
->ts
.secs
;
1454 current
.nsecs
= phdr
->ts
.nsecs
;
1456 if (is_duplicate_rel_time(buf
, phdr
->caplen
, ¤t
)) {
1458 fprintf(stdout
, "Skipped: %u, Len: %u, MD5 Hash: ",
1459 count
, phdr
->caplen
);
1460 for (i
= 0; i
< 16; i
++)
1461 fprintf(stdout
, "%02x",
1462 (unsigned char)fd_hash
[cur_dup_entry
].digest
[i
]);
1463 fprintf(stdout
, "\n");
1470 fprintf(stdout
, "Packet: %u, Len: %u, MD5 Hash: ",
1471 count
, phdr
->caplen
);
1472 for (i
= 0; i
< 16; i
++)
1473 fprintf(stdout
, "%02x",
1474 (unsigned char)fd_hash
[cur_dup_entry
].digest
[i
]);
1475 fprintf(stdout
, "\n");
1480 /* Random error mutation */
1481 if (err_prob
> 0.0) {
1482 int real_data_start
= 0;
1484 /* Protect non-protocol data */
1485 if (wtap_file_type_subtype(wth
) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000
)
1486 real_data_start
= find_dct2000_real_data(buf
);
1488 for (i
= real_data_start
; i
< (int) phdr
->caplen
; i
++) {
1489 if (rand() <= err_prob
* RAND_MAX
) {
1490 err_type
= rand() / (RAND_MAX
/ ERR_WT_TOTAL
+ 1);
1492 if (err_type
< ERR_WT_BIT
) {
1493 buf
[i
] ^= 1 << (rand() / (RAND_MAX
/ 8 + 1));
1494 err_type
= ERR_WT_TOTAL
;
1496 err_type
-= ERR_WT_BYTE
;
1499 if (err_type
< ERR_WT_BYTE
) {
1500 buf
[i
] = rand() / (RAND_MAX
/ 255 + 1);
1501 err_type
= ERR_WT_TOTAL
;
1503 err_type
-= ERR_WT_BYTE
;
1506 if (err_type
< ERR_WT_ALNUM
) {
1507 buf
[i
] = ALNUM_CHARS
[rand() / (RAND_MAX
/ ALNUM_LEN
+ 1)];
1508 err_type
= ERR_WT_TOTAL
;
1510 err_type
-= ERR_WT_ALNUM
;
1513 if (err_type
< ERR_WT_FMT
) {
1514 if ((unsigned int)i
< phdr
->caplen
- 2)
1515 g_strlcpy((char*) &buf
[i
], "%s", 2);
1516 err_type
= ERR_WT_TOTAL
;
1518 err_type
-= ERR_WT_FMT
;
1521 if (err_type
< ERR_WT_AA
) {
1522 for (j
= i
; j
< (int) phdr
->caplen
; j
++)
1530 if (!wtap_dump(pdh
, phdr
, buf
, &err
)) {
1532 case WTAP_ERR_UNSUPPORTED_ENCAP
:
1534 * This is a problem with the particular frame we're
1535 * writing; note that, and give the frame number.
1538 "editcap: Frame %u of \"%s\" has a network type that can't be saved in a file with that format\n.",
1539 read_count
, argv
[optind
]);
1543 fprintf(stderr
, "editcap: Error writing to %s: %s\n",
1544 filename
, wtap_strerror(err
));
1558 /* Print a message noting that the read failed somewhere along the
1561 "editcap: An error occurred while reading \"%s\": %s.\n",
1562 argv
[optind
], wtap_strerror(err
));
1564 case WTAP_ERR_UNSUPPORTED
:
1565 case WTAP_ERR_UNSUPPORTED_ENCAP
:
1566 case WTAP_ERR_BAD_FILE
:
1567 fprintf(stderr
, "(%s)\n", err_info
);
1574 /* No valid packages found, open the outfile so we can write an
1577 filename
= g_strdup(argv
[optind
+1]);
1579 pdh
= wtap_dump_open_ng(filename
, out_file_type_subtype
, out_frame_type
,
1580 snaplen
? MIN(snaplen
, wtap_snapshot_length(wth
)): wtap_snapshot_length(wth
),
1581 FALSE
/* compressed */, shb_hdr
, idb_inf
, &err
);
1583 fprintf(stderr
, "editcap: Can't open or create %s: %s\n",
1584 filename
, wtap_strerror(err
));
1592 if (!wtap_dump_close(pdh
, &err
)) {
1593 fprintf(stderr
, "editcap: Error writing to %s: %s\n", filename
,
1594 wtap_strerror(err
));
1602 fprintf(stdout
, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1603 count
- 1, plurality(count
- 1, "", "s"), duplicate_count
,
1604 plurality(duplicate_count
, "", "s"), dup_window
);
1605 } else if (dup_detect_by_time
) {
1606 fprintf(stdout
, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1607 count
- 1, plurality(count
- 1, "", "s"), duplicate_count
,
1608 plurality(duplicate_count
, "", "s"),
1609 (long)relative_time_window
.secs
,
1610 (long int)relative_time_window
.nsecs
);
1616 /* Skip meta-information read from file to return offset of real
1619 find_dct2000_real_data(guint8
*buf
)
1623 for (n
= 0; buf
[n
] != '\0'; n
++); /* Context name */
1625 n
++; /* Context port number */
1626 for (; buf
[n
] != '\0'; n
++); /* Timestamp */
1628 for (; buf
[n
] != '\0'; n
++); /* Protocol name */
1630 for (; buf
[n
] != '\0'; n
++); /* Variant number (as string) */
1632 for (; buf
[n
] != '\0'; n
++); /* Outhdr (as string) */
1634 n
+= 2; /* Direction & encap */
1640 * We support up to 2 chopping regions in a single pas, one specified by the
1641 * positive chop length, and one by the negative chop length.
1644 handle_chopping(chop_t chop
, struct wtap_pkthdr
*out_phdr
,
1645 const struct wtap_pkthdr
*in_phdr
, guint8
*buf
,
1648 /* If we're not chopping anything from one side, then the offset for that
1649 * side is meaningless. */
1650 if (chop
.len_begin
== 0)
1651 chop
.off_begin_pos
= chop
.off_begin_neg
= 0;
1652 if (chop
.len_end
== 0)
1653 chop
.off_end_pos
= chop
.off_end_neg
= 0;
1655 if (chop
.off_begin_neg
< 0) {
1656 chop
.off_begin_pos
+= in_phdr
->caplen
+ chop
.off_begin_neg
;
1657 chop
.off_begin_neg
= 0;
1659 if (chop
.off_end_pos
> 0) {
1660 chop
.off_end_neg
+= chop
.off_end_pos
- in_phdr
->caplen
;
1661 chop
.off_end_pos
= 0;
1664 /* If we've crossed chopping regions, swap them */
1665 if (chop
.len_begin
&& chop
.len_end
) {
1666 if (chop
.off_begin_pos
> ((int)in_phdr
->caplen
+ chop
.off_end_neg
)) {
1667 int tmp_len
, tmp_off
;
1669 tmp_off
= in_phdr
->caplen
+ chop
.off_end_neg
+ chop
.len_end
;
1670 tmp_len
= -chop
.len_end
;
1672 chop
.off_end_neg
= chop
.len_begin
+ chop
.off_begin_pos
- in_phdr
->caplen
;
1673 chop
.len_end
= -chop
.len_begin
;
1675 chop
.len_begin
= tmp_len
;
1676 chop
.off_begin_pos
= tmp_off
;
1680 /* Make sure we don't chop off more than we have available */
1681 if (in_phdr
->caplen
< (guint32
)(chop
.off_begin_pos
- chop
.off_end_neg
)) {
1685 if ((guint32
)(chop
.len_begin
- chop
.len_end
) >
1686 (in_phdr
->caplen
- (guint32
)(chop
.off_begin_pos
- chop
.off_end_neg
))) {
1687 chop
.len_begin
= in_phdr
->caplen
- (chop
.off_begin_pos
- chop
.off_end_neg
);
1691 /* Handle chopping from the beginning. Note that if a beginning offset
1692 * was specified, we need to keep that piece */
1693 if (chop
.len_begin
> 0) {
1694 *out_phdr
= *in_phdr
;
1696 if (chop
.off_begin_pos
> 0) {
1697 memmove(&buf
[chop
.off_begin_pos
],
1698 &buf
[chop
.off_begin_pos
+ chop
.len_begin
],
1699 out_phdr
->caplen
- chop
.len_begin
);
1701 buf
+= chop
.len_begin
;
1703 out_phdr
->caplen
-= chop
.len_begin
;
1706 if (in_phdr
->len
> (guint32
)chop
.len_begin
)
1707 out_phdr
->len
-= chop
.len_begin
;
1714 /* Handle chopping from the end. Note that if an ending offset was
1715 * specified, we need to keep that piece */
1716 if (chop
.len_end
< 0) {
1717 *out_phdr
= *in_phdr
;
1719 if (chop
.off_end_neg
< 0) {
1720 memmove(&buf
[(gint
)out_phdr
->caplen
+ (chop
.len_end
+ chop
.off_end_neg
)],
1721 &buf
[(gint
)out_phdr
->caplen
+ chop
.off_end_neg
],
1724 out_phdr
->caplen
+= chop
.len_end
;
1727 if (((signed int) in_phdr
->len
+ chop
.len_end
) > 0)
1728 out_phdr
->len
+= chop
.len_end
;
1732 /*in_phdr = out_phdr;*/
1737 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1742 * indent-tabs-mode: nil
1745 * vi: set shiftwidth=4 tabstop=4 expandtab:
1746 * :indentSize=4:tabSize=4:noTabs=true: