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"
52 #include <wsutil/unicode-utils.h>
53 #include <process.h> /* getpid */
54 #ifdef HAVE_WINSOCK2_H
59 #ifdef NEED_STRPTIME_H
60 # include "wsutil/strptime.h"
63 #include "epan/crypt/crypt-md5.h"
64 #include "epan/plugins.h"
65 #include "epan/report_err.h"
66 #include "epan/filesystem.h"
67 #include <wsutil/privileges.h>
68 #include "epan/nstime.h"
70 #include "svnversion.h"
73 * Some globals so we can pass things to various routines
85 * Duplicate frame detection
87 typedef struct _fd_hash_t {
88 md5_byte_t digest[16];
93 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
94 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
96 fd_hash_t fd_hash[MAX_DUP_DEPTH];
97 int dup_window = DEFAULT_DUP_DEPTH;
98 int cur_dup_entry = 0;
100 #define ONE_MILLION 1000000
101 #define ONE_BILLION 1000000000
103 /* Weights of different errors we can introduce */
104 /* We should probably make these command-line arguments */
105 /* XXX - Should we add a bit-level error? */
106 #define ERR_WT_BIT 5 /* Flip a random bit */
107 #define ERR_WT_BYTE 5 /* Substitute a random byte */
108 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
109 #define ERR_WT_FMT 2 /* Substitute "%s" */
110 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
111 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
113 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
114 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
117 struct time_adjustment {
122 #define MAX_SELECTIONS 512
123 static struct select_item selectfrm[MAX_SELECTIONS];
124 static int max_selected = -1;
125 static int keep_em = 0;
126 static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */
127 static int out_frame_type = -2; /* Leave frame type alone */
128 static int verbose = 0; /* Not so verbose */
129 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
130 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
131 static double err_prob = 0.0;
132 static time_t starttime = 0;
133 static time_t stoptime = 0;
134 static gboolean check_startstop = FALSE;
135 static gboolean dup_detect = FALSE;
136 static gboolean dup_detect_by_time = FALSE;
138 static int do_strict_time_adjustment = FALSE;
139 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
140 static nstime_t previous_time = {0, 0}; /* previous time */
142 static int find_dct2000_real_data(guint8 *buf);
145 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
148 gchar *buf = g_malloc(16);
151 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
152 /* XXX - find the exact value that still does work */
153 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
154 if(abs_time->secs > 2000000000) {
158 tmp = localtime(&abs_time->secs);
160 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
174 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time_val,
175 gchar *fprefix, gchar *fsuffix)
181 timestr = abs_time_to_str_with_sec_resolution(time_val);
182 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
183 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
190 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
192 char *pfx, *last_pathsep;
195 save_file = g_strdup(fname);
196 if (save_file == NULL) {
197 fprintf(stderr, "editcap: Out of memory\n");
201 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
202 pfx = strrchr(save_file,'.');
203 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
204 /* The pathname has a "." in it, and it's in the last component
205 of the pathname (because there is either only one component,
206 i.e. last_pathsep is null as there are no path separators,
207 or the "." is after the path separator before the last
210 Treat it as a separator between the rest of the file name and
211 the file name suffix, and arrange that the names given to the
212 ring buffer files have the specified suffix, i.e. put the
213 changing part of the name *before* the suffix. */
215 *fprefix = g_strdup(save_file);
216 pfx[0] = '.'; /* restore capfile_name */
217 *fsuffix = g_strdup(pfx);
219 /* Either there's no "." in the pathname, or it's in a directory
220 component, so the last component has no suffix. */
221 *fprefix = g_strdup(save_file);
228 /* Add a selection item, a simple parser for now */
230 add_selection(char *sel)
235 if (++max_selected >= MAX_SELECTIONS) {
236 /* Let the user know we stopped selecting */
237 printf("Out of room for packet selections!\n");
241 printf("Add_Selected: %s\n", sel);
243 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
245 printf("Not inclusive ...");
247 selectfrm[max_selected].inclusive = 0;
248 selectfrm[max_selected].first = atoi(sel);
250 printf(" %i\n", selectfrm[max_selected].first);
255 printf("Inclusive ...");
258 selectfrm[max_selected].inclusive = 1;
259 selectfrm[max_selected].first = atoi(sel);
260 selectfrm[max_selected].second = atoi(next);
262 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
269 /* Was the packet selected? */
276 for (i = 0; i<= max_selected; i++) {
278 if (selectfrm[i].inclusive) {
279 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
283 if (recno == selectfrm[i].first)
292 /* is the packet in the selected timeframe */
294 check_timestamp(wtap *wth)
296 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
298 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime );
302 set_time_adjustment(char *optarg_str_p)
311 /* skip leading whitespace */
312 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
316 /* check for a negative adjustment */
317 if (*optarg_str_p == '-') {
318 time_adj.is_negative = 1;
322 /* collect whole number of seconds, if any */
323 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
327 val = strtol(optarg_str_p, &frac, 10);
328 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
329 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
333 if (val < 0) { /* implies '--' since we caught '-' above */
334 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
339 time_adj.tv.tv_sec = val;
341 /* now collect the partial seconds, if any */
342 if (*frac != '\0') { /* chars left, so get fractional part */
343 val = strtol(&(frac[1]), &end, 10);
344 /* if more than 6 fractional digits truncate to 6 */
345 if((end - &(frac[1])) > 6) {
346 frac[7] = 't'; /* 't' for truncate */
347 val = strtol(&(frac[1]), &end, 10);
349 if (*frac != '.' || end == NULL || end == frac
350 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
351 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
357 return; /* no fractional digits */
360 /* adjust fractional portion from fractional to numerator
361 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
362 if (frac && end) { /* both are valid */
363 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
364 while(frac_digits < 6) { /* this is frac of 10^6 */
369 time_adj.tv.tv_usec = val;
373 set_strict_time_adj(char *optarg_str_p)
382 /* skip leading whitespace */
383 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
388 * check for a negative adjustment
389 * A negative strict adjustment value is a flag
390 * to adjust all frames by the specifed delta time.
392 if (*optarg_str_p == '-') {
393 strict_time_adj.is_negative = 1;
397 /* collect whole number of seconds, if any */
398 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
402 val = strtol(optarg_str_p, &frac, 10);
403 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
404 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
408 if (val < 0) { /* implies '--' since we caught '-' above */
409 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
414 strict_time_adj.tv.tv_sec = val;
416 /* now collect the partial seconds, if any */
417 if (*frac != '\0') { /* chars left, so get fractional part */
418 val = strtol(&(frac[1]), &end, 10);
419 /* if more than 6 fractional digits truncate to 6 */
420 if((end - &(frac[1])) > 6) {
421 frac[7] = 't'; /* 't' for truncate */
422 val = strtol(&(frac[1]), &end, 10);
424 if (*frac != '.' || end == NULL || end == frac
425 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
426 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
432 return; /* no fractional digits */
435 /* adjust fractional portion from fractional to numerator
436 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
437 if (frac && end) { /* both are valid */
438 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
439 while(frac_digits < 6) { /* this is frac of 10^6 */
444 strict_time_adj.tv.tv_usec = val;
448 set_rel_time(char *optarg_str_p)
457 /* skip leading whitespace */
458 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
462 /* ignore negative adjustment */
463 if (*optarg_str_p == '-') {
467 /* collect whole number of seconds, if any */
468 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
472 val = strtol(optarg_str_p, &frac, 10);
473 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
474 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
478 if (val < 0) { /* implies '--' since we caught '-' above */
479 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
484 relative_time_window.secs = val;
486 /* now collect the partial seconds, if any */
487 if (*frac != '\0') { /* chars left, so get fractional part */
488 val = strtol(&(frac[1]), &end, 10);
489 /* if more than 9 fractional digits truncate to 9 */
490 if((end - &(frac[1])) > 9) {
491 frac[10] = 't'; /* 't' for truncate */
492 val = strtol(&(frac[1]), &end, 10);
494 if (*frac != '.' || end == NULL || end == frac
495 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
496 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
502 return; /* no fractional digits */
505 /* adjust fractional portion from fractional to numerator
506 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
507 if (frac && end) { /* both are valid */
508 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
509 while(frac_digits < 9) { /* this is frac of 10^9 */
514 relative_time_window.nsecs = val;
518 is_duplicate(guint8* fd, guint32 len) {
523 if (cur_dup_entry >= dup_window)
526 /* Calculate our digest */
528 md5_append(&ms, fd, len);
529 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
531 fd_hash[cur_dup_entry].len = len;
533 /* Look for duplicates */
534 for (i = 0; i < dup_window; i++) {
535 if (i == cur_dup_entry)
538 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
539 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
548 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
553 if (cur_dup_entry >= dup_window)
556 /* Calculate our digest */
558 md5_append(&ms, fd, len);
559 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
561 fd_hash[cur_dup_entry].len = len;
562 fd_hash[cur_dup_entry].time.secs = current->secs;
563 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
566 * Look for relative time related duplicates.
567 * This is hopefully a reasonably efficient mechanism for
568 * finding duplicates by rel time in the fd_hash[] cache.
569 * We check starting from the most recently added hash
570 * entries and work backwards towards older packets.
571 * This approach allows the dup test to be terminated
572 * when the relative time of a cached entry is found to
573 * be beyond the dup time window.
575 * Of course this assumes that the input trace file is
576 * "well-formed" in the sense that the packet timestamps are
577 * in strict chronologically increasing order (which is NOT
578 * always the case!!).
580 * The fd_hash[] table was deliberatly created large (1,000,000).
581 * Looking for time related duplicates in large trace files with
582 * non-fractional dup time window values can potentially take
583 * a long time to complete.
586 for (i = cur_dup_entry - 1;; i--) {
594 if (i == cur_dup_entry) {
596 * We've decremented back to where we started.
602 if (nstime_is_unset(&(fd_hash[i].time))) {
604 * We've decremented to an unused fd_hash[] entry.
610 nstime_delta(&delta, current, &fd_hash[i].time);
612 if(delta.secs < 0 || delta.nsecs < 0)
615 * A negative delta implies that the current packet
616 * has an absolute timestamp less than the cached packet
617 * that it is being compared to. This is NOT a normal
618 * situation since trace files usually have packets in
619 * chronological order (oldest to newest).
621 * There are several possible ways to deal with this:
622 * 1. 'continue' dup checking with the next cached frame.
623 * 2. 'break' from looking for a duplicate of the current frame.
624 * 3. Take the absolute value of the delta and see if that
625 * falls within the specifed dup time window.
627 * Currently this code does option 1. But it would pretty
628 * easy to add yet-another-editcap-option to select one of
629 * the other behaviors for dealing with out-of-sequence
635 cmp = nstime_cmp(&delta, &relative_time_window);
639 * The delta time indicates that we are now looking at
640 * cached packets beyond the specified dup time window.
644 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
645 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
654 usage(gboolean is_error)
663 fprintf(output, "Editcap %s"
665 " (" SVNVERSION " from " SVNPATH ")"
668 fprintf(output, "Edit and/or translate the format of capture files.\n");
669 fprintf(output, "See http://www.wireshark.org for more information.\n");
670 fprintf(output, "\n");
671 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
672 fprintf(output, "\n");
673 fprintf(output, "<infile> and <outfile> must both be present.\n");
674 fprintf(output, "A single packet or a range of packets can be selected.\n");
675 fprintf(output, "\n");
676 fprintf(output, "Packet selection:\n");
677 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
678 fprintf(output, " -A <start time> only output packets whose timestamp is after (or equal\n");
679 fprintf(output, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
680 fprintf(output, " -B <stop time> only output packets whose timestamp is before the\n");
681 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
682 fprintf(output, "\n");
683 fprintf(output, "Duplicate packet removal:\n");
684 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
685 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
686 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
687 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
688 fprintf(output, " useful to print MD5 hashes.\n");
689 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
690 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
691 fprintf(output, " A <dup time window> is specified in relative seconds\n");
692 fprintf(output, " (e.g. 0.000001).\n");
693 fprintf(output, "\n");
694 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
695 fprintf(output, " other editcap options except -v may not always work as expected.\n");
696 fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n");
697 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
698 fprintf(output, "\n");
699 fprintf(output, "Packet manipulation:\n");
700 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
701 fprintf(output, " -C <choplen> chop each packet by <choplen> bytes. Positive values\n");
702 fprintf(output, " chop at the packet beginning, negative values at the\n");
703 fprintf(output, " packet end.\n");
704 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
705 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
706 fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
707 fprintf(output, " strict chronological increasing order. The <strict\n");
708 fprintf(output, " adjustment> is specified in relative seconds with\n");
709 fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n");
710 fprintf(output, " A negative adjustment value will modify timestamps so\n");
711 fprintf(output, " that each packet's delta time is the absolute value\n");
712 fprintf(output, " of the adjustment specified. A value of -0 will set\n");
713 fprintf(output, " all packets to the timestamp of the first packet.\n");
714 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
715 fprintf(output, " that a particular packet byte will be randomly changed.\n");
716 fprintf(output, "\n");
717 fprintf(output, "Output File(s):\n");
718 fprintf(output, " -c <packets per file> split the packet output to different files\n");
719 fprintf(output, " based on uniform packet counts\n");
720 fprintf(output, " with a maximum of <packets per file> each.\n");
721 fprintf(output, " -i <seconds per file> split the packet output to different files\n");
722 fprintf(output, " based on uniform time intervals\n");
723 fprintf(output, " with a maximum of <seconds per file> each.\n");
724 fprintf(output, " -F <capture type> set the output file type; default is libpcap.\n");
725 fprintf(output, " an empty \"-F\" option will list the file types.\n");
726 fprintf(output, " -T <encap type> set the output file encapsulation type;\n");
727 fprintf(output, " default is the same as the input file.\n");
728 fprintf(output, " an empty \"-T\" option will list the encapsulation types.\n");
729 fprintf(output, "\n");
730 fprintf(output, "Miscellaneous:\n");
731 fprintf(output, " -h display this help and exit.\n");
732 fprintf(output, " -v verbose output.\n");
733 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
734 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
735 fprintf(output, " and MD5 hashes are printed to standard-out.\n");
736 fprintf(output, "\n");
740 const char *sstr; /* The short string */
741 const char *lstr; /* The long string */
745 string_compare(gconstpointer a, gconstpointer b)
747 return strcmp(((struct string_elem *)a)->sstr,
748 ((struct string_elem *)b)->sstr);
752 string_elem_print(gpointer data, gpointer not_used _U_)
754 fprintf(stderr, " %s - %s\n",
755 ((struct string_elem *)data)->sstr,
756 ((struct string_elem *)data)->lstr);
760 list_capture_types(void) {
762 struct string_elem *captypes;
765 captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES);
766 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
767 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
768 if (wtap_dump_can_open(i)) {
769 captypes[i].sstr = wtap_file_type_short_string(i);
770 captypes[i].lstr = wtap_file_type_string(i);
771 list = g_slist_insert_sorted(list, &captypes[i], string_compare);
774 g_slist_foreach(list, string_elem_print, NULL);
780 list_encap_types(void) {
782 struct string_elem *encaps;
785 encaps = g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
786 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
787 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
788 encaps[i].sstr = wtap_encap_short_string(i);
789 if (encaps[i].sstr != NULL) {
790 encaps[i].lstr = wtap_encap_string(i);
791 list = g_slist_insert_sorted(list, &encaps[i], string_compare);
794 g_slist_foreach(list, string_elem_print, NULL);
801 * Don't report failures to load plugins because most (non-wiretap) plugins
802 * *should* fail to load (because we're not linked against libwireshark and
803 * dissector plugins need libwireshark).
806 failure_message(const char *msg_format _U_, va_list ap _U_)
813 main(int argc, char *argv[])
821 guint32 snaplen = 0; /* No limit */
822 int choplen = 0; /* No chop */
823 wtap_dumper *pdh = NULL;
825 unsigned duplicate_count = 0;
827 struct wtap_pkthdr snap_phdr;
828 const struct wtap_pkthdr *phdr;
831 int split_packet_count = 0;
832 int written_count = 0;
833 char *filename = NULL;
835 int secs_per_block = 0;
837 nstime_t block_start;
838 gchar *fprefix = NULL;
839 gchar *fsuffix = NULL;
842 char* init_progfile_dir_error;
846 arg_list_utf_16to8(argc, argv);
850 * Get credential information for later use.
852 init_process_policies();
855 /* Register wiretap plugins */
856 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
857 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
858 g_free(init_progfile_dir_error);
860 init_report_err(failure_message,NULL,NULL,NULL);
865 /* Process the options */
866 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
871 err_prob = strtod(optarg, &p);
872 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
873 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
877 srand( (unsigned int) (time(NULL) + getpid()) );
881 out_file_type = wtap_short_string_to_file_type(optarg);
882 if (out_file_type < 0) {
883 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
885 list_capture_types();
891 split_packet_count = strtol(optarg, &p, 10);
892 if (p == optarg || *p != '\0') {
893 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
897 if (split_packet_count <= 0) {
898 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
905 choplen = strtol(optarg, &p, 10);
906 if (p == optarg || *p != '\0') {
907 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
915 dup_detect_by_time = FALSE;
916 dup_window = DEFAULT_DUP_DEPTH;
921 dup_detect_by_time = FALSE;
922 dup_window = strtol(optarg, &p, 10);
923 if (p == optarg || *p != '\0') {
924 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
928 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
929 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
930 dup_window, MAX_DUP_DEPTH);
937 dup_detect_by_time = TRUE;
938 dup_window = MAX_DUP_DEPTH;
939 set_rel_time(optarg);
942 case '?': /* Bad options if GNU getopt */
945 list_capture_types();
962 keep_em = !keep_em; /* Just invert */
966 snaplen = strtol(optarg, &p, 10);
967 if (p == optarg || *p != '\0') {
968 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
975 set_time_adjustment(optarg);
979 set_strict_time_adj(optarg);
980 do_strict_time_adjustment = TRUE;
984 out_frame_type = wtap_short_string_to_encap(optarg);
985 if (out_frame_type < 0) {
986 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
994 verbose = !verbose; /* Just invert */
997 case 'i': /* break capture file based on time interval */
998 secs_per_block = atoi(optarg);
999 if(secs_per_block <= 0) {
1000 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1009 memset(&starttm,0,sizeof(struct tm));
1011 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1012 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1016 check_startstop = TRUE;
1017 starttm.tm_isdst = -1;
1019 starttime = mktime(&starttm);
1027 memset(&stoptm,0,sizeof(struct tm));
1029 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1030 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1033 check_startstop = TRUE;
1034 stoptm.tm_isdst = -1;
1035 stoptime = mktime(&stoptm);
1043 printf("Optind = %i, argc = %i\n", optind, argc);
1046 if ((argc - optind) < 1) {
1053 if (check_startstop && !stoptime) {
1055 /* XXX: will work until 2035 */
1056 memset(&stoptm,0,sizeof(struct tm));
1057 stoptm.tm_year = 135;
1058 stoptm.tm_mday = 31;
1061 stoptime = mktime(&stoptm);
1064 nstime_set_unset(&block_start);
1066 if (starttime > stoptime) {
1067 fprintf(stderr, "editcap: start time is after the stop time\n");
1071 if (split_packet_count > 0 && secs_per_block > 0) {
1072 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1073 fprintf(stderr, "editcap: at the same time\n");
1077 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1080 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1081 wtap_strerror(err));
1084 case WTAP_ERR_UNSUPPORTED:
1085 case WTAP_ERR_UNSUPPORTED_ENCAP:
1086 case WTAP_ERR_BAD_RECORD:
1087 fprintf(stderr, "(%s)\n", err_info);
1096 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1097 wtap_file_type_string(wtap_file_type(wth)));
1101 * Now, process the rest, if any ... we only write if there is an extra
1102 * argument or so ...
1105 if ((argc - optind) >= 2) {
1107 if (out_frame_type == -2)
1108 out_frame_type = wtap_file_encap(wth);
1110 for (i = optind + 2; i < argc; i++)
1111 if (add_selection(argv[i]) == FALSE)
1114 if (dup_detect || dup_detect_by_time) {
1115 for (i = 0; i < dup_window; i++) {
1116 memset(&fd_hash[i].digest, 0, 16);
1118 nstime_set_unset(&fd_hash[i].time);
1122 while (wtap_read(wth, &err, &err_info, &data_offset)) {
1123 phdr = wtap_phdr(wth);
1124 buf = wtap_buf_ptr(wth);
1126 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
1127 block_start.secs = phdr->ts.secs;
1128 block_start.nsecs = phdr->ts.nsecs;
1130 if (split_packet_count > 0 || secs_per_block > 0) {
1131 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1134 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1136 filename = g_strdup(argv[optind+1]);
1138 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1139 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1140 FALSE /* compressed */, &err);
1142 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1143 wtap_strerror(err));
1150 if (secs_per_block > 0) {
1151 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1152 (phdr->ts.secs - block_start.secs == secs_per_block &&
1153 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1155 if (!wtap_dump_close(pdh, &err)) {
1156 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1157 wtap_strerror(err));
1160 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1162 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1166 fprintf(stderr, "Continuing writing in file %s\n", filename);
1169 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1170 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1171 FALSE /* compressed */, &err);
1174 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1175 wtap_strerror(err));
1181 if (split_packet_count > 0) {
1183 /* time for the next file? */
1184 if (written_count > 0 &&
1185 written_count % split_packet_count == 0) {
1186 if (!wtap_dump_close(pdh, &err)) {
1187 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1188 wtap_strerror(err));
1193 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1197 fprintf(stderr, "Continuing writing in file %s\n", filename);
1200 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1201 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1202 FALSE /* compressed */, &err);
1204 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1205 wtap_strerror(err));
1211 check_ts = check_timestamp(wth);
1213 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1214 (selected(count) && keep_em)) ) {
1216 if (verbose && !dup_detect && !dup_detect_by_time)
1217 printf("Packet: %u\n", count);
1219 /* We simply write it, perhaps after truncating it; we could do other
1220 things, like modify it. */
1222 phdr = wtap_phdr(wth);
1224 if (snaplen != 0 && phdr->caplen > snaplen) {
1226 snap_phdr.caplen = snaplen;
1232 if (((signed int) phdr->caplen + choplen) > 0)
1233 snap_phdr.caplen += choplen;
1235 snap_phdr.caplen = 0;
1237 } else if (choplen > 0) {
1239 if (phdr->caplen > (unsigned int) choplen) {
1240 snap_phdr.caplen -= choplen;
1243 snap_phdr.caplen = 0;
1248 * Do we adjust timestamps to insure strict chronologically order?
1251 if (do_strict_time_adjustment) {
1252 if (previous_time.secs || previous_time.nsecs) {
1253 if (!strict_time_adj.is_negative) {
1257 current.secs = phdr->ts.secs;
1258 current.nsecs = phdr->ts.nsecs;
1260 nstime_delta(&delta, ¤t, &previous_time);
1262 if (delta.secs < 0 || delta.nsecs < 0)
1265 * A negative delta indicates that the current packet
1266 * has an absolute timestamp less than the previous packet
1267 * that it is being compared to. This is NOT a normal
1268 * situation since trace files usually have packets in
1269 * chronological order (oldest to newest).
1271 /* printf("++out of order, need to adjust this packet!\n"); */
1273 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1274 snap_phdr.ts.nsecs = previous_time.nsecs;
1275 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1277 snap_phdr.ts.secs++;
1278 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1280 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1286 * A negative strict time adjustment is requested.
1287 * Unconditionally set each timestamp to previous
1288 * packet's timestamp plus delta.
1291 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1292 snap_phdr.ts.nsecs = previous_time.nsecs;
1293 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1295 snap_phdr.ts.secs++;
1296 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1298 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1303 previous_time.secs = phdr->ts.secs;
1304 previous_time.nsecs = phdr->ts.nsecs;
1307 /* assume that if the frame's tv_sec is 0, then
1308 * the timestamp isn't supported */
1309 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1311 if (time_adj.is_negative)
1312 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1314 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1318 /* assume that if the frame's tv_sec is 0, then
1319 * the timestamp isn't supported */
1320 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1322 if (time_adj.is_negative) { /* subtract */
1323 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1324 snap_phdr.ts.secs--;
1325 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1327 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1329 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1331 snap_phdr.ts.secs++;
1332 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1334 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1340 /* suppress duplicates by packet window */
1342 if (is_duplicate(buf, phdr->caplen)) {
1344 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1345 for (i = 0; i < 16; i++) {
1346 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1348 fprintf(stdout, "\n");
1355 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1356 for (i = 0; i < 16; i++) {
1357 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1359 fprintf(stdout, "\n");
1364 /* suppress duplicates by time window */
1365 if (dup_detect_by_time) {
1368 current.secs = phdr->ts.secs;
1369 current.nsecs = phdr->ts.nsecs;
1371 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1373 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1374 for (i = 0; i < 16; i++) {
1375 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1377 fprintf(stdout, "\n");
1384 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1385 for (i = 0; i < 16; i++) {
1386 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1388 fprintf(stdout, "\n");
1393 /* Random error mutation */
1394 if (err_prob > 0.0) {
1395 int real_data_start = 0;
1396 /* Protect non-protocol data */
1397 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1398 real_data_start = find_dct2000_real_data(buf);
1400 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1401 if (rand() <= err_prob * RAND_MAX) {
1402 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1404 if (err_type < ERR_WT_BIT) {
1405 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1406 err_type = ERR_WT_TOTAL;
1408 err_type -= ERR_WT_BYTE;
1411 if (err_type < ERR_WT_BYTE) {
1412 buf[i] = rand() / (RAND_MAX / 255 + 1);
1413 err_type = ERR_WT_TOTAL;
1415 err_type -= ERR_WT_BYTE;
1418 if (err_type < ERR_WT_ALNUM) {
1419 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1420 err_type = ERR_WT_TOTAL;
1422 err_type -= ERR_WT_ALNUM;
1425 if (err_type < ERR_WT_FMT) {
1426 if ((unsigned int)i < phdr->caplen - 2)
1427 strncpy((char*) &buf[i], "%s", 2);
1428 err_type = ERR_WT_TOTAL;
1430 err_type -= ERR_WT_FMT;
1433 if (err_type < ERR_WT_AA) {
1434 for (j = i; j < (int) phdr->caplen; j++) {
1443 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1444 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1445 filename, wtap_strerror(err));
1457 /* Print a message noting that the read failed somewhere along the line. */
1459 "editcap: An error occurred while reading \"%s\": %s.\n",
1460 argv[optind], wtap_strerror(err));
1463 case WTAP_ERR_UNSUPPORTED:
1464 case WTAP_ERR_UNSUPPORTED_ENCAP:
1465 case WTAP_ERR_BAD_RECORD:
1466 fprintf(stderr, "(%s)\n", err_info);
1473 /* No valid packages found, open the outfile so we can write an empty header */
1475 filename = g_strdup(argv[optind+1]);
1477 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1478 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1479 FALSE /* compressed */, &err);
1481 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1482 wtap_strerror(err));
1487 if (!wtap_dump_close(pdh, &err)) {
1489 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1490 wtap_strerror(err));
1498 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1499 count - 1, plurality(count - 1, "", "s"),
1500 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1501 } else if (dup_detect_by_time) {
1502 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1503 count - 1, plurality(count - 1, "", "s"),
1504 duplicate_count, plurality(duplicate_count, "", "s"),
1505 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1511 /* Skip meta-information read from file to return offset of real
1513 static int find_dct2000_real_data(guint8 *buf)
1517 for (n=0; buf[n] != '\0'; n++); /* Context name */
1519 n++; /* Context port number */
1520 for (; buf[n] != '\0'; n++); /* Timestamp */
1522 for (; buf[n] != '\0'; n++); /* Protocol name */
1524 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1526 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1528 n += 2; /* Direction & encap */