1 /* Edit capture files. We can delete packets, adjust timestamps, or
2 * simply convert from one format to another format.
6 * Originally written by Richard Sharpe.
7 * Improved by Guy Harris.
8 * Further improved by Richard Sharpe.
21 * Just make sure we include the prototype for strptime as well
22 * (needed for glibc 2.2) but make sure we do this only if not
39 #ifdef HAVE_SYS_TIME_H
48 #include "wsutil/wsgetopt.h"
54 #include <process.h> /* getpid */
55 #ifdef HAVE_WINSOCK2_H
60 #ifdef NEED_STRPTIME_H
61 # include "wsutil/strptime.h"
64 #include "epan/crypt/crypt-md5.h"
65 #include "epan/plugins.h"
66 #include "epan/report_err.h"
67 #include "epan/filesystem.h"
68 #include <wsutil/privileges.h>
69 #include "epan/nstime.h"
71 #include "svnversion.h"
74 * Some globals so we can pass things to various routines
86 * Duplicate frame detection
88 typedef struct _fd_hash_t {
89 md5_byte_t digest[16];
94 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
95 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
97 fd_hash_t fd_hash[MAX_DUP_DEPTH];
98 int dup_window = DEFAULT_DUP_DEPTH;
99 int cur_dup_entry = 0;
101 #define ONE_MILLION 1000000
102 #define ONE_BILLION 1000000000
104 /* Weights of different errors we can introduce */
105 /* We should probably make these command-line arguments */
106 /* XXX - Should we add a bit-level error? */
107 #define ERR_WT_BIT 5 /* Flip a random bit */
108 #define ERR_WT_BYTE 5 /* Substitute a random byte */
109 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
110 #define ERR_WT_FMT 2 /* Substitute "%s" */
111 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
112 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
114 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
115 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
118 struct time_adjustment {
123 #define MAX_SELECTIONS 512
124 static struct select_item selectfrm[MAX_SELECTIONS];
125 static int max_selected = -1;
126 static int keep_em = 0;
127 static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */
128 static int out_frame_type = -2; /* Leave frame type alone */
129 static int verbose = 0; /* Not so verbose */
130 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
131 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
132 static double err_prob = 0.0;
133 static time_t starttime = 0;
134 static time_t stoptime = 0;
135 static gboolean check_startstop = FALSE;
136 static gboolean dup_detect = FALSE;
137 static gboolean dup_detect_by_time = FALSE;
139 static int do_strict_time_adjustment = FALSE;
140 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
141 static nstime_t previous_time = {0, 0}; /* previous time */
143 static int find_dct2000_real_data(guint8 *buf);
146 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
149 gchar *buf = g_malloc(16);
152 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
153 /* XXX - find the exact value that still does work */
154 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
155 if(abs_time->secs > 2000000000) {
159 tmp = localtime(&abs_time->secs);
161 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
175 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time_val,
176 gchar *fprefix, gchar *fsuffix)
182 timestr = abs_time_to_str_with_sec_resolution(time_val);
183 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
184 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
191 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
193 char *pfx, *last_pathsep;
196 save_file = g_strdup(fname);
197 if (save_file == NULL) {
198 fprintf(stderr, "editcap: Out of memory\n");
202 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
203 pfx = strrchr(save_file,'.');
204 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
205 /* The pathname has a "." in it, and it's in the last component
206 of the pathname (because there is either only one component,
207 i.e. last_pathsep is null as there are no path separators,
208 or the "." is after the path separator before the last
211 Treat it as a separator between the rest of the file name and
212 the file name suffix, and arrange that the names given to the
213 ring buffer files have the specified suffix, i.e. put the
214 changing part of the name *before* the suffix. */
216 *fprefix = g_strdup(save_file);
217 pfx[0] = '.'; /* restore capfile_name */
218 *fsuffix = g_strdup(pfx);
220 /* Either there's no "." in the pathname, or it's in a directory
221 component, so the last component has no suffix. */
222 *fprefix = g_strdup(save_file);
229 /* Add a selection item, a simple parser for now */
231 add_selection(char *sel)
236 if (++max_selected >= MAX_SELECTIONS) {
237 /* Let the user know we stopped selecting */
238 printf("Out of room for packet selections!\n");
242 printf("Add_Selected: %s\n", sel);
244 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
246 printf("Not inclusive ...");
248 selectfrm[max_selected].inclusive = 0;
249 selectfrm[max_selected].first = atoi(sel);
251 printf(" %i\n", selectfrm[max_selected].first);
256 printf("Inclusive ...");
259 selectfrm[max_selected].inclusive = 1;
260 selectfrm[max_selected].first = atoi(sel);
261 selectfrm[max_selected].second = atoi(next);
263 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
270 /* Was the packet selected? */
277 for (i = 0; i<= max_selected; i++) {
279 if (selectfrm[i].inclusive) {
280 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
284 if (recno == selectfrm[i].first)
293 /* is the packet in the selected timeframe */
295 check_timestamp(wtap *wth)
297 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
299 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime );
303 set_time_adjustment(char *optarg_str_p)
312 /* skip leading whitespace */
313 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
317 /* check for a negative adjustment */
318 if (*optarg_str_p == '-') {
319 time_adj.is_negative = 1;
323 /* collect whole number of seconds, if any */
324 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
328 val = strtol(optarg_str_p, &frac, 10);
329 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
330 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
334 if (val < 0) { /* implies '--' since we caught '-' above */
335 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
340 time_adj.tv.tv_sec = val;
342 /* now collect the partial seconds, if any */
343 if (*frac != '\0') { /* chars left, so get fractional part */
344 val = strtol(&(frac[1]), &end, 10);
345 /* if more than 6 fractional digits truncate to 6 */
346 if((end - &(frac[1])) > 6) {
347 frac[7] = 't'; /* 't' for truncate */
348 val = strtol(&(frac[1]), &end, 10);
350 if (*frac != '.' || end == NULL || end == frac
351 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
352 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
358 return; /* no fractional digits */
361 /* adjust fractional portion from fractional to numerator
362 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
363 if (frac && end) { /* both are valid */
364 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
365 while(frac_digits < 6) { /* this is frac of 10^6 */
370 time_adj.tv.tv_usec = val;
374 set_strict_time_adj(char *optarg_str_p)
383 /* skip leading whitespace */
384 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
389 * check for a negative adjustment
390 * A negative strict adjustment value is a flag
391 * to adjust all frames by the specifed delta time.
393 if (*optarg_str_p == '-') {
394 strict_time_adj.is_negative = 1;
398 /* collect whole number of seconds, if any */
399 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
403 val = strtol(optarg_str_p, &frac, 10);
404 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
405 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
409 if (val < 0) { /* implies '--' since we caught '-' above */
410 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
415 strict_time_adj.tv.tv_sec = val;
417 /* now collect the partial seconds, if any */
418 if (*frac != '\0') { /* chars left, so get fractional part */
419 val = strtol(&(frac[1]), &end, 10);
420 /* if more than 6 fractional digits truncate to 6 */
421 if((end - &(frac[1])) > 6) {
422 frac[7] = 't'; /* 't' for truncate */
423 val = strtol(&(frac[1]), &end, 10);
425 if (*frac != '.' || end == NULL || end == frac
426 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
427 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
433 return; /* no fractional digits */
436 /* adjust fractional portion from fractional to numerator
437 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
438 if (frac && end) { /* both are valid */
439 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
440 while(frac_digits < 6) { /* this is frac of 10^6 */
445 strict_time_adj.tv.tv_usec = val;
449 set_rel_time(char *optarg_str_p)
458 /* skip leading whitespace */
459 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
463 /* ignore negative adjustment */
464 if (*optarg_str_p == '-') {
468 /* collect whole number of seconds, if any */
469 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
473 val = strtol(optarg_str_p, &frac, 10);
474 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
475 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
479 if (val < 0) { /* implies '--' since we caught '-' above */
480 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
485 relative_time_window.secs = val;
487 /* now collect the partial seconds, if any */
488 if (*frac != '\0') { /* chars left, so get fractional part */
489 val = strtol(&(frac[1]), &end, 10);
490 /* if more than 9 fractional digits truncate to 9 */
491 if((end - &(frac[1])) > 9) {
492 frac[10] = 't'; /* 't' for truncate */
493 val = strtol(&(frac[1]), &end, 10);
495 if (*frac != '.' || end == NULL || end == frac
496 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
497 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
503 return; /* no fractional digits */
506 /* adjust fractional portion from fractional to numerator
507 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
508 if (frac && end) { /* both are valid */
509 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
510 while(frac_digits < 9) { /* this is frac of 10^9 */
515 relative_time_window.nsecs = val;
519 is_duplicate(guint8* fd, guint32 len) {
524 if (cur_dup_entry >= dup_window)
527 /* Calculate our digest */
529 md5_append(&ms, fd, len);
530 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
532 fd_hash[cur_dup_entry].len = len;
534 /* Look for duplicates */
535 for (i = 0; i < dup_window; i++) {
536 if (i == cur_dup_entry)
539 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
540 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
549 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
554 if (cur_dup_entry >= dup_window)
557 /* Calculate our digest */
559 md5_append(&ms, fd, len);
560 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
562 fd_hash[cur_dup_entry].len = len;
563 fd_hash[cur_dup_entry].time.secs = current->secs;
564 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
567 * Look for relative time related duplicates.
568 * This is hopefully a reasonably efficient mechanism for
569 * finding duplicates by rel time in the fd_hash[] cache.
570 * We check starting from the most recently added hash
571 * entries and work backwards towards older packets.
572 * This approach allows the dup test to be terminated
573 * when the relative time of a cached entry is found to
574 * be beyond the dup time window.
576 * Of course this assumes that the input trace file is
577 * "well-formed" in the sense that the packet timestamps are
578 * in strict chronologically increasing order (which is NOT
579 * always the case!!).
581 * The fd_hash[] table was deliberatly created large (1,000,000).
582 * Looking for time related duplicates in large trace files with
583 * non-fractional dup time window values can potentially take
584 * a long time to complete.
587 for (i = cur_dup_entry - 1;; i--) {
595 if (i == cur_dup_entry) {
597 * We've decremented back to where we started.
603 if (nstime_is_unset(&(fd_hash[i].time))) {
605 * We've decremented to an unused fd_hash[] entry.
611 nstime_delta(&delta, current, &fd_hash[i].time);
613 if(delta.secs < 0 || delta.nsecs < 0)
616 * A negative delta implies that the current packet
617 * has an absolute timestamp less than the cached packet
618 * that it is being compared to. This is NOT a normal
619 * situation since trace files usually have packets in
620 * chronological order (oldest to newest).
622 * There are several possible ways to deal with this:
623 * 1. 'continue' dup checking with the next cached frame.
624 * 2. 'break' from looking for a duplicate of the current frame.
625 * 3. Take the absolute value of the delta and see if that
626 * falls within the specifed dup time window.
628 * Currently this code does option 1. But it would pretty
629 * easy to add yet-another-editcap-option to select one of
630 * the other behaviors for dealing with out-of-sequence
636 cmp = nstime_cmp(&delta, &relative_time_window);
640 * The delta time indicates that we are now looking at
641 * cached packets beyond the specified dup time window.
645 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
646 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
655 usage(gboolean is_error)
664 fprintf(output, "Editcap %s"
666 " (" SVNVERSION " from " SVNPATH ")"
669 fprintf(output, "Edit and/or translate the format of capture files.\n");
670 fprintf(output, "See http://www.wireshark.org for more information.\n");
671 fprintf(output, "\n");
672 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
673 fprintf(output, "\n");
674 fprintf(output, "<infile> and <outfile> must both be present.\n");
675 fprintf(output, "A single packet or a range of packets can be selected.\n");
676 fprintf(output, "\n");
677 fprintf(output, "Packet selection:\n");
678 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
679 fprintf(output, " -A <start time> only output packets whose timestamp is after (or equal\n");
680 fprintf(output, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
681 fprintf(output, " -B <stop time> only output packets whose timestamp is before the\n");
682 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
683 fprintf(output, "\n");
684 fprintf(output, "Duplicate packet removal:\n");
685 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
686 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
687 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
688 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
689 fprintf(output, " useful to print MD5 hashes.\n");
690 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
691 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
692 fprintf(output, " A <dup time window> is specified in relative seconds\n");
693 fprintf(output, " (e.g. 0.000001).\n");
694 fprintf(output, "\n");
695 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
696 fprintf(output, " other editcap options except -v may not always work as expected.\n");
697 fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n");
698 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
699 fprintf(output, "\n");
700 fprintf(output, "Packet manipulation:\n");
701 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
702 fprintf(output, " -C <choplen> chop each packet by <choplen> bytes. Positive values\n");
703 fprintf(output, " chop at the packet beginning, negative values at the\n");
704 fprintf(output, " packet end.\n");
705 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
706 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
707 fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
708 fprintf(output, " strict chronological increasing order. The <strict\n");
709 fprintf(output, " adjustment> is specified in relative seconds with\n");
710 fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n");
711 fprintf(output, " A negative adjustment value will modify timestamps so\n");
712 fprintf(output, " that each packet's delta time is the absolute value\n");
713 fprintf(output, " of the adjustment specified. A value of -0 will set\n");
714 fprintf(output, " all packets to the timestamp of the first packet.\n");
715 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
716 fprintf(output, " that a particular packet byte will be randomly changed.\n");
717 fprintf(output, "\n");
718 fprintf(output, "Output File(s):\n");
719 fprintf(output, " -c <packets per file> split the packet output to different files\n");
720 fprintf(output, " based on uniform packet counts\n");
721 fprintf(output, " with a maximum of <packets per file> each.\n");
722 fprintf(output, " -i <seconds per file> split the packet output to different files\n");
723 fprintf(output, " based on uniform time intervals\n");
724 fprintf(output, " with a maximum of <seconds per file> each.\n");
725 fprintf(output, " -F <capture type> set the output file type; default is libpcap.\n");
726 fprintf(output, " an empty \"-F\" option will list the file types.\n");
727 fprintf(output, " -T <encap type> set the output file encapsulation type;\n");
728 fprintf(output, " default is the same as the input file.\n");
729 fprintf(output, " an empty \"-T\" option will list the encapsulation types.\n");
730 fprintf(output, "\n");
731 fprintf(output, "Miscellaneous:\n");
732 fprintf(output, " -h display this help and exit.\n");
733 fprintf(output, " -v verbose output.\n");
734 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
735 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
736 fprintf(output, " and MD5 hashes are printed to standard-out.\n");
737 fprintf(output, "\n");
741 const char *sstr; /* The short string */
742 const char *lstr; /* The long string */
746 string_compare(gconstpointer a, gconstpointer b)
748 return strcmp(((struct string_elem *)a)->sstr,
749 ((struct string_elem *)b)->sstr);
753 string_elem_print(gpointer data, gpointer not_used _U_)
755 fprintf(stderr, " %s - %s\n",
756 ((struct string_elem *)data)->sstr,
757 ((struct string_elem *)data)->lstr);
761 list_capture_types(void) {
763 struct string_elem *captypes;
766 captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES);
767 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
768 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
769 if (wtap_dump_can_open(i)) {
770 captypes[i].sstr = wtap_file_type_short_string(i);
771 captypes[i].lstr = wtap_file_type_string(i);
772 list = g_slist_insert_sorted(list, &captypes[i], string_compare);
775 g_slist_foreach(list, string_elem_print, NULL);
781 list_encap_types(void) {
783 struct string_elem *encaps;
786 encaps = g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
787 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
788 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
789 encaps[i].sstr = wtap_encap_short_string(i);
790 if (encaps[i].sstr != NULL) {
791 encaps[i].lstr = wtap_encap_string(i);
792 list = g_slist_insert_sorted(list, &encaps[i], string_compare);
795 g_slist_foreach(list, string_elem_print, NULL);
802 * Don't report failures to load plugins because most (non-wiretap) plugins
803 * *should* fail to load (because we're not linked against libwireshark and
804 * dissector plugins need libwireshark).
807 failure_message(const char *msg_format _U_, va_list ap _U_)
814 main(int argc, char *argv[])
827 unsigned int snaplen = 0; /* No limit */
828 int choplen = 0; /* No chop */
829 wtap_dumper *pdh = NULL;
831 unsigned duplicate_count = 0;
833 struct wtap_pkthdr snap_phdr;
834 const struct wtap_pkthdr *phdr;
837 int split_packet_count = 0;
838 int written_count = 0;
839 char *filename = NULL;
841 int secs_per_block = 0;
843 nstime_t block_start;
844 gchar *fprefix = NULL;
845 gchar *fsuffix = NULL;
848 char* init_progfile_dir_error;
852 /* Convert our arg list to UTF-8. */
853 wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc);
854 if (wc_argv && wc_argc == argc) {
855 for (i = 0; i < argc; i++) {
856 argv[i] = g_utf16_to_utf8(wc_argv[i], -1, NULL, NULL, NULL);
858 } /* XXX else bail because something is horribly, horribly wrong? */
862 * Get credential information for later use.
864 init_process_policies();
867 /* Register wiretap plugins */
868 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
869 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
870 g_free(init_progfile_dir_error);
872 init_report_err(failure_message,NULL,NULL,NULL);
877 /* Process the options */
878 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
883 err_prob = strtod(optarg, &p);
884 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
885 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
889 srand( (unsigned int) (time(NULL) + getpid()) );
893 out_file_type = wtap_short_string_to_file_type(optarg);
894 if (out_file_type < 0) {
895 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
897 list_capture_types();
903 split_packet_count = strtol(optarg, &p, 10);
904 if (p == optarg || *p != '\0') {
905 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
909 if (split_packet_count <= 0) {
910 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
917 choplen = strtol(optarg, &p, 10);
918 if (p == optarg || *p != '\0') {
919 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
927 dup_detect_by_time = FALSE;
928 dup_window = DEFAULT_DUP_DEPTH;
933 dup_detect_by_time = FALSE;
934 dup_window = strtol(optarg, &p, 10);
935 if (p == optarg || *p != '\0') {
936 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
940 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
941 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
942 dup_window, MAX_DUP_DEPTH);
949 dup_detect_by_time = TRUE;
950 dup_window = MAX_DUP_DEPTH;
951 set_rel_time(optarg);
954 case '?': /* Bad options if GNU getopt */
957 list_capture_types();
974 keep_em = !keep_em; /* Just invert */
978 snaplen = strtol(optarg, &p, 10);
979 if (p == optarg || *p != '\0') {
980 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
987 set_time_adjustment(optarg);
991 set_strict_time_adj(optarg);
992 do_strict_time_adjustment = TRUE;
996 out_frame_type = wtap_short_string_to_encap(optarg);
997 if (out_frame_type < 0) {
998 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1006 verbose = !verbose; /* Just invert */
1009 case 'i': /* break capture file based on time interval */
1010 secs_per_block = atoi(optarg);
1011 if(secs_per_block <= 0) {
1012 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1021 memset(&starttm,0,sizeof(struct tm));
1023 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1024 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1028 check_startstop = TRUE;
1029 starttm.tm_isdst = -1;
1031 starttime = mktime(&starttm);
1039 memset(&stoptm,0,sizeof(struct tm));
1041 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1042 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1045 check_startstop = TRUE;
1046 stoptm.tm_isdst = -1;
1047 stoptime = mktime(&stoptm);
1055 printf("Optind = %i, argc = %i\n", optind, argc);
1058 if ((argc - optind) < 1) {
1065 if (check_startstop && !stoptime) {
1067 /* XXX: will work until 2035 */
1068 memset(&stoptm,0,sizeof(struct tm));
1069 stoptm.tm_year = 135;
1070 stoptm.tm_mday = 31;
1073 stoptime = mktime(&stoptm);
1076 nstime_set_unset(&block_start);
1078 if (starttime > stoptime) {
1079 fprintf(stderr, "editcap: start time is after the stop time\n");
1083 if (split_packet_count > 0 && secs_per_block > 0) {
1084 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1085 fprintf(stderr, "editcap: at the same time\n");
1089 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1092 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1093 wtap_strerror(err));
1096 case WTAP_ERR_UNSUPPORTED:
1097 case WTAP_ERR_UNSUPPORTED_ENCAP:
1098 case WTAP_ERR_BAD_RECORD:
1099 fprintf(stderr, "(%s)\n", err_info);
1108 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1109 wtap_file_type_string(wtap_file_type(wth)));
1113 * Now, process the rest, if any ... we only write if there is an extra
1114 * argument or so ...
1117 if ((argc - optind) >= 2) {
1119 if (out_frame_type == -2)
1120 out_frame_type = wtap_file_encap(wth);
1122 for (i = optind + 2; i < argc; i++)
1123 if (add_selection(argv[i]) == FALSE)
1126 if (dup_detect || dup_detect_by_time) {
1127 for (i = 0; i < dup_window; i++) {
1128 memset(&fd_hash[i].digest, 0, 16);
1130 nstime_set_unset(&fd_hash[i].time);
1134 while (wtap_read(wth, &err, &err_info, &data_offset)) {
1135 phdr = wtap_phdr(wth);
1136 buf = wtap_buf_ptr(wth);
1138 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
1139 block_start.secs = phdr->ts.secs;
1140 block_start.nsecs = phdr->ts.nsecs;
1142 if (split_packet_count > 0 || secs_per_block > 0) {
1143 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1146 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1148 filename = g_strdup(argv[optind+1]);
1150 pdh = wtap_dump_open(filename, out_file_type,
1151 out_frame_type, wtap_snapshot_length(wth),
1152 FALSE /* compressed */, &err);
1154 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1155 wtap_strerror(err));
1162 if (secs_per_block > 0) {
1163 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1164 (phdr->ts.secs - block_start.secs == secs_per_block &&
1165 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1167 if (!wtap_dump_close(pdh, &err)) {
1168 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1169 wtap_strerror(err));
1172 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1174 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1178 fprintf(stderr, "Continuing writing in file %s\n", filename);
1181 pdh = wtap_dump_open(filename, out_file_type,
1182 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1185 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1186 wtap_strerror(err));
1192 if (split_packet_count > 0) {
1194 /* time for the next file? */
1195 if (written_count > 0 &&
1196 written_count % split_packet_count == 0) {
1197 if (!wtap_dump_close(pdh, &err)) {
1198 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1199 wtap_strerror(err));
1204 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1208 fprintf(stderr, "Continuing writing in file %s\n", filename);
1211 pdh = wtap_dump_open(filename, out_file_type,
1212 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1214 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1215 wtap_strerror(err));
1221 check_ts = check_timestamp(wth);
1223 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1224 (selected(count) && keep_em)) ) {
1226 if (verbose && !dup_detect && !dup_detect_by_time)
1227 printf("Packet: %u\n", count);
1229 /* We simply write it, perhaps after truncating it; we could do other
1230 things, like modify it. */
1232 phdr = wtap_phdr(wth);
1234 if (choplen < 0 && (phdr->caplen + choplen) > 0) {
1236 snap_phdr.caplen += choplen;
1240 if (choplen > 0 && phdr->caplen > (unsigned int) choplen) {
1242 snap_phdr.caplen -= choplen;
1243 snap_phdr.len -= choplen;
1248 if (snaplen != 0 && phdr->caplen > snaplen) {
1250 snap_phdr.caplen = snaplen;
1255 * Do we adjust timestamps to insure strict chronologically order?
1258 if (do_strict_time_adjustment) {
1259 if (previous_time.secs || previous_time.nsecs) {
1260 if (!strict_time_adj.is_negative) {
1264 current.secs = phdr->ts.secs;
1265 current.nsecs = phdr->ts.nsecs;
1267 nstime_delta(&delta, ¤t, &previous_time);
1269 if (delta.secs < 0 || delta.nsecs < 0)
1272 * A negative delta indicates that the current packet
1273 * has an absolute timestamp less than the previous packet
1274 * that it is being compared to. This is NOT a normal
1275 * situation since trace files usually have packets in
1276 * chronological order (oldest to newest).
1278 /* printf("++out of order, need to adjust this packet!\n"); */
1280 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1281 snap_phdr.ts.nsecs = previous_time.nsecs;
1282 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1284 snap_phdr.ts.secs++;
1285 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1287 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1293 * A negative strict time adjustment is requested.
1294 * Unconditionally set each timestamp to previous
1295 * packet's timestamp plus delta.
1298 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1299 snap_phdr.ts.nsecs = previous_time.nsecs;
1300 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1302 snap_phdr.ts.secs++;
1303 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1305 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1310 previous_time.secs = phdr->ts.secs;
1311 previous_time.nsecs = phdr->ts.nsecs;
1314 /* assume that if the frame's tv_sec is 0, then
1315 * the timestamp isn't supported */
1316 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1318 if (time_adj.is_negative)
1319 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1321 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1325 /* assume that if the frame's tv_sec is 0, then
1326 * the timestamp isn't supported */
1327 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1329 if (time_adj.is_negative) { /* subtract */
1330 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1331 snap_phdr.ts.secs--;
1332 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1334 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1336 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1338 snap_phdr.ts.secs++;
1339 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1341 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1347 /* suppress duplicates by packet window */
1349 if (is_duplicate(buf, phdr->caplen)) {
1351 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1352 for (i = 0; i < 16; i++) {
1353 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1355 fprintf(stdout, "\n");
1362 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1363 for (i = 0; i < 16; i++) {
1364 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1366 fprintf(stdout, "\n");
1371 /* suppress duplicates by time window */
1372 if (dup_detect_by_time) {
1375 current.secs = phdr->ts.secs;
1376 current.nsecs = phdr->ts.nsecs;
1378 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1380 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1381 for (i = 0; i < 16; i++) {
1382 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1384 fprintf(stdout, "\n");
1391 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1392 for (i = 0; i < 16; i++) {
1393 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1395 fprintf(stdout, "\n");
1400 /* Random error mutation */
1401 if (err_prob > 0.0) {
1402 int real_data_start = 0;
1403 /* Protect non-protocol data */
1404 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1405 real_data_start = find_dct2000_real_data(buf);
1407 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1408 if (rand() <= err_prob * RAND_MAX) {
1409 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1411 if (err_type < ERR_WT_BIT) {
1412 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1413 err_type = ERR_WT_TOTAL;
1415 err_type -= ERR_WT_BYTE;
1418 if (err_type < ERR_WT_BYTE) {
1419 buf[i] = rand() / (RAND_MAX / 255 + 1);
1420 err_type = ERR_WT_TOTAL;
1422 err_type -= ERR_WT_BYTE;
1425 if (err_type < ERR_WT_ALNUM) {
1426 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1427 err_type = ERR_WT_TOTAL;
1429 err_type -= ERR_WT_ALNUM;
1432 if (err_type < ERR_WT_FMT) {
1433 if ((unsigned int)i < phdr->caplen - 2)
1434 strncpy((char*) &buf[i], "%s", 2);
1435 err_type = ERR_WT_TOTAL;
1437 err_type -= ERR_WT_FMT;
1440 if (err_type < ERR_WT_AA) {
1441 for (j = i; j < (int) phdr->caplen; j++) {
1450 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1451 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1452 filename, wtap_strerror(err));
1464 /* Print a message noting that the read failed somewhere along the line. */
1466 "editcap: An error occurred while reading \"%s\": %s.\n",
1467 argv[optind], wtap_strerror(err));
1470 case WTAP_ERR_UNSUPPORTED:
1471 case WTAP_ERR_UNSUPPORTED_ENCAP:
1472 case WTAP_ERR_BAD_RECORD:
1473 fprintf(stderr, "(%s)\n", err_info);
1480 /* No valid packages found, open the outfile so we can write an empty header */
1482 filename = g_strdup(argv[optind+1]);
1484 pdh = wtap_dump_open(filename, out_file_type,
1485 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1487 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1488 wtap_strerror(err));
1493 if (!wtap_dump_close(pdh, &err)) {
1495 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1496 wtap_strerror(err));
1504 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1505 count - 1, plurality(count - 1, "", "s"),
1506 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1507 } else if (dup_detect_by_time) {
1508 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1509 count - 1, plurality(count - 1, "", "s"),
1510 duplicate_count, plurality(duplicate_count, "", "s"),
1511 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1517 /* Skip meta-information read from file to return offset of real
1519 static int find_dct2000_real_data(guint8 *buf)
1523 for (n=0; buf[n] != '\0'; n++); /* Context name */
1525 n++; /* Context port number */
1526 for (; buf[n] != '\0'; n++); /* Timestamp */
1528 for (; buf[n] != '\0'; n++); /* Protocol name */
1530 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1532 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1534 n += 2; /* Direction & encap */