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
46 #include "wsutil/wsgetopt.h"
50 #include <wsutil/unicode-utils.h>
51 #include <process.h> /* getpid */
52 #ifdef HAVE_WINSOCK2_H
57 #ifdef NEED_STRPTIME_H
58 # include "wsutil/strptime.h"
61 #include "epan/crypt/crypt-md5.h"
62 #include "epan/plugins.h"
63 #include "epan/report_err.h"
64 #include "epan/filesystem.h"
65 #include <wsutil/privileges.h>
66 #include "epan/nstime.h"
68 #include "svnversion.h"
71 * Some globals so we can pass things to various routines
83 * Duplicate frame detection
85 typedef struct _fd_hash_t {
86 md5_byte_t digest[16];
91 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
92 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
94 fd_hash_t fd_hash[MAX_DUP_DEPTH];
95 int dup_window = DEFAULT_DUP_DEPTH;
96 int cur_dup_entry = 0;
98 #define ONE_MILLION 1000000
99 #define ONE_BILLION 1000000000
101 /* Weights of different errors we can introduce */
102 /* We should probably make these command-line arguments */
103 /* XXX - Should we add a bit-level error? */
104 #define ERR_WT_BIT 5 /* Flip a random bit */
105 #define ERR_WT_BYTE 5 /* Substitute a random byte */
106 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
107 #define ERR_WT_FMT 2 /* Substitute "%s" */
108 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
109 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
111 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
112 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
115 struct time_adjustment {
120 #define MAX_SELECTIONS 512
121 static struct select_item selectfrm[MAX_SELECTIONS];
122 static int max_selected = -1;
123 static int keep_em = 0;
124 #ifdef PCAP_NG_DEFAULT
125 static int out_file_type = WTAP_FILE_PCAPNG; /* default to pcapng */
127 static int out_file_type = WTAP_FILE_PCAP; /* default to pcap */
129 static int out_frame_type = -2; /* Leave frame type alone */
130 static int verbose = 0; /* Not so verbose */
131 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
132 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
133 static double err_prob = 0.0;
134 static time_t starttime = 0;
135 static time_t stoptime = 0;
136 static gboolean check_startstop = FALSE;
137 static gboolean dup_detect = FALSE;
138 static gboolean dup_detect_by_time = FALSE;
140 static int do_strict_time_adjustment = FALSE;
141 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
142 static nstime_t previous_time = {0, 0}; /* previous time */
144 static int find_dct2000_real_data(guint8 *buf);
147 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
150 gchar *buf = g_malloc(16);
153 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
154 /* XXX - find the exact value that still does work */
155 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
156 if(abs_time->secs > 2000000000) {
160 tmp = localtime(&abs_time->secs);
162 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
176 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time_val,
177 gchar *fprefix, gchar *fsuffix)
183 timestr = abs_time_to_str_with_sec_resolution(time_val);
184 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
185 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
192 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
194 char *pfx, *last_pathsep;
197 save_file = g_strdup(fname);
198 if (save_file == NULL) {
199 fprintf(stderr, "editcap: Out of memory\n");
203 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
204 pfx = strrchr(save_file,'.');
205 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
206 /* The pathname has a "." in it, and it's in the last component
207 of the pathname (because there is either only one component,
208 i.e. last_pathsep is null as there are no path separators,
209 or the "." is after the path separator before the last
212 Treat it as a separator between the rest of the file name and
213 the file name suffix, and arrange that the names given to the
214 ring buffer files have the specified suffix, i.e. put the
215 changing part of the name *before* the suffix. */
217 *fprefix = g_strdup(save_file);
218 pfx[0] = '.'; /* restore capfile_name */
219 *fsuffix = g_strdup(pfx);
221 /* Either there's no "." in the pathname, or it's in a directory
222 component, so the last component has no suffix. */
223 *fprefix = g_strdup(save_file);
230 /* Add a selection item, a simple parser for now */
232 add_selection(char *sel)
237 if (++max_selected >= MAX_SELECTIONS) {
238 /* Let the user know we stopped selecting */
239 printf("Out of room for packet selections!\n");
243 printf("Add_Selected: %s\n", sel);
245 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
247 printf("Not inclusive ...");
249 selectfrm[max_selected].inclusive = 0;
250 selectfrm[max_selected].first = atoi(sel);
252 printf(" %i\n", selectfrm[max_selected].first);
257 printf("Inclusive ...");
260 selectfrm[max_selected].inclusive = 1;
261 selectfrm[max_selected].first = atoi(sel);
262 selectfrm[max_selected].second = atoi(next);
264 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
271 /* Was the packet selected? */
278 for (i = 0; i<= max_selected; i++) {
280 if (selectfrm[i].inclusive) {
281 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
285 if (recno == selectfrm[i].first)
294 /* is the packet in the selected timeframe */
296 check_timestamp(wtap *wth)
298 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
300 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime );
304 set_time_adjustment(char *optarg_str_p)
313 /* skip leading whitespace */
314 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
318 /* check for a negative adjustment */
319 if (*optarg_str_p == '-') {
320 time_adj.is_negative = 1;
324 /* collect whole number of seconds, if any */
325 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
329 val = strtol(optarg_str_p, &frac, 10);
330 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
331 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
335 if (val < 0) { /* implies '--' since we caught '-' above */
336 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
341 time_adj.tv.tv_sec = val;
343 /* now collect the partial seconds, if any */
344 if (*frac != '\0') { /* chars left, so get fractional part */
345 val = strtol(&(frac[1]), &end, 10);
346 /* if more than 6 fractional digits truncate to 6 */
347 if((end - &(frac[1])) > 6) {
348 frac[7] = 't'; /* 't' for truncate */
349 val = strtol(&(frac[1]), &end, 10);
351 if (*frac != '.' || end == NULL || end == frac
352 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
353 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
359 return; /* no fractional digits */
362 /* adjust fractional portion from fractional to numerator
363 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
364 if (frac && end) { /* both are valid */
365 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
366 while(frac_digits < 6) { /* this is frac of 10^6 */
371 time_adj.tv.tv_usec = val;
375 set_strict_time_adj(char *optarg_str_p)
384 /* skip leading whitespace */
385 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
390 * check for a negative adjustment
391 * A negative strict adjustment value is a flag
392 * to adjust all frames by the specifed delta time.
394 if (*optarg_str_p == '-') {
395 strict_time_adj.is_negative = 1;
399 /* collect whole number of seconds, if any */
400 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
404 val = strtol(optarg_str_p, &frac, 10);
405 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
406 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
410 if (val < 0) { /* implies '--' since we caught '-' above */
411 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
416 strict_time_adj.tv.tv_sec = val;
418 /* now collect the partial seconds, if any */
419 if (*frac != '\0') { /* chars left, so get fractional part */
420 val = strtol(&(frac[1]), &end, 10);
421 /* if more than 6 fractional digits truncate to 6 */
422 if((end - &(frac[1])) > 6) {
423 frac[7] = 't'; /* 't' for truncate */
424 val = strtol(&(frac[1]), &end, 10);
426 if (*frac != '.' || end == NULL || end == frac
427 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
428 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
434 return; /* no fractional digits */
437 /* adjust fractional portion from fractional to numerator
438 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
439 if (frac && end) { /* both are valid */
440 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
441 while(frac_digits < 6) { /* this is frac of 10^6 */
446 strict_time_adj.tv.tv_usec = val;
450 set_rel_time(char *optarg_str_p)
459 /* skip leading whitespace */
460 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
464 /* ignore negative adjustment */
465 if (*optarg_str_p == '-') {
469 /* collect whole number of seconds, if any */
470 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
474 val = strtol(optarg_str_p, &frac, 10);
475 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
476 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
480 if (val < 0) { /* implies '--' since we caught '-' above */
481 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
486 relative_time_window.secs = val;
488 /* now collect the partial seconds, if any */
489 if (*frac != '\0') { /* chars left, so get fractional part */
490 val = strtol(&(frac[1]), &end, 10);
491 /* if more than 9 fractional digits truncate to 9 */
492 if((end - &(frac[1])) > 9) {
493 frac[10] = 't'; /* 't' for truncate */
494 val = strtol(&(frac[1]), &end, 10);
496 if (*frac != '.' || end == NULL || end == frac
497 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
498 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
504 return; /* no fractional digits */
507 /* adjust fractional portion from fractional to numerator
508 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
509 if (frac && end) { /* both are valid */
510 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
511 while(frac_digits < 9) { /* this is frac of 10^9 */
516 relative_time_window.nsecs = val;
520 is_duplicate(guint8* fd, guint32 len) {
525 if (cur_dup_entry >= dup_window)
528 /* Calculate our digest */
530 md5_append(&ms, fd, len);
531 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
533 fd_hash[cur_dup_entry].len = len;
535 /* Look for duplicates */
536 for (i = 0; i < dup_window; i++) {
537 if (i == cur_dup_entry)
540 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
541 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
550 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
555 if (cur_dup_entry >= dup_window)
558 /* Calculate our digest */
560 md5_append(&ms, fd, len);
561 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
563 fd_hash[cur_dup_entry].len = len;
564 fd_hash[cur_dup_entry].time.secs = current->secs;
565 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
568 * Look for relative time related duplicates.
569 * This is hopefully a reasonably efficient mechanism for
570 * finding duplicates by rel time in the fd_hash[] cache.
571 * We check starting from the most recently added hash
572 * entries and work backwards towards older packets.
573 * This approach allows the dup test to be terminated
574 * when the relative time of a cached entry is found to
575 * be beyond the dup time window.
577 * Of course this assumes that the input trace file is
578 * "well-formed" in the sense that the packet timestamps are
579 * in strict chronologically increasing order (which is NOT
580 * always the case!!).
582 * The fd_hash[] table was deliberatly created large (1,000,000).
583 * Looking for time related duplicates in large trace files with
584 * non-fractional dup time window values can potentially take
585 * a long time to complete.
588 for (i = cur_dup_entry - 1;; i--) {
596 if (i == cur_dup_entry) {
598 * We've decremented back to where we started.
604 if (nstime_is_unset(&(fd_hash[i].time))) {
606 * We've decremented to an unused fd_hash[] entry.
612 nstime_delta(&delta, current, &fd_hash[i].time);
614 if(delta.secs < 0 || delta.nsecs < 0)
617 * A negative delta implies that the current packet
618 * has an absolute timestamp less than the cached packet
619 * that it is being compared to. This is NOT a normal
620 * situation since trace files usually have packets in
621 * chronological order (oldest to newest).
623 * There are several possible ways to deal with this:
624 * 1. 'continue' dup checking with the next cached frame.
625 * 2. 'break' from looking for a duplicate of the current frame.
626 * 3. Take the absolute value of the delta and see if that
627 * falls within the specifed dup time window.
629 * Currently this code does option 1. But it would pretty
630 * easy to add yet-another-editcap-option to select one of
631 * the other behaviors for dealing with out-of-sequence
637 cmp = nstime_cmp(&delta, &relative_time_window);
641 * The delta time indicates that we are now looking at
642 * cached packets beyond the specified dup time window.
646 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
647 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
656 usage(gboolean is_error)
665 fprintf(output, "Editcap %s"
667 " (" SVNVERSION " from " SVNPATH ")"
670 fprintf(output, "Edit and/or translate the format of capture files.\n");
671 fprintf(output, "See http://www.wireshark.org for more information.\n");
672 fprintf(output, "\n");
673 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
674 fprintf(output, "\n");
675 fprintf(output, "<infile> and <outfile> must both be present.\n");
676 fprintf(output, "A single packet or a range of packets can be selected.\n");
677 fprintf(output, "\n");
678 fprintf(output, "Packet selection:\n");
679 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
680 fprintf(output, " -A <start time> only output packets whose timestamp is after (or equal\n");
681 fprintf(output, " to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
682 fprintf(output, " -B <stop time> only output packets whose timestamp is before the\n");
683 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
684 fprintf(output, "\n");
685 fprintf(output, "Duplicate packet removal:\n");
686 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
687 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
688 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
689 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
690 fprintf(output, " useful to print MD5 hashes.\n");
691 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
692 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
693 fprintf(output, " A <dup time window> is specified in relative seconds\n");
694 fprintf(output, " (e.g. 0.000001).\n");
695 fprintf(output, "\n");
696 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
697 fprintf(output, " other editcap options except -v may not always work as expected.\n");
698 fprintf(output, " Specifically the -r, -t or -S options will very likely NOT have the\n");
699 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
700 fprintf(output, "\n");
701 fprintf(output, "Packet manipulation:\n");
702 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
703 fprintf(output, " -C <choplen> chop each packet by <choplen> bytes. Positive values\n");
704 fprintf(output, " chop at the packet beginning, negative values at the\n");
705 fprintf(output, " packet end.\n");
706 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
707 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
708 fprintf(output, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
709 fprintf(output, " strict chronological increasing order. The <strict\n");
710 fprintf(output, " adjustment> is specified in relative seconds with\n");
711 fprintf(output, " values of 0 or 0.000001 being the most reasonable.\n");
712 fprintf(output, " A negative adjustment value will modify timestamps so\n");
713 fprintf(output, " that each packet's delta time is the absolute value\n");
714 fprintf(output, " of the adjustment specified. A value of -0 will set\n");
715 fprintf(output, " all packets to the timestamp of the first packet.\n");
716 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
717 fprintf(output, " that a particular packet byte will be randomly changed.\n");
718 fprintf(output, "\n");
719 fprintf(output, "Output File(s):\n");
720 fprintf(output, " -c <packets per file> split the packet output to different files\n");
721 fprintf(output, " based on uniform packet counts\n");
722 fprintf(output, " with a maximum of <packets per file> each.\n");
723 fprintf(output, " -i <seconds per file> split the packet output to different files\n");
724 fprintf(output, " based on uniform time intervals\n");
725 fprintf(output, " with a maximum of <seconds per file> each.\n");
726 fprintf(output, " -F <capture type> set the output file type; default is libpcap.\n");
727 fprintf(output, " an empty \"-F\" option will list the file types.\n");
728 fprintf(output, " -T <encap type> set the output file encapsulation type;\n");
729 fprintf(output, " default is the same as the input file.\n");
730 fprintf(output, " an empty \"-T\" option will list the encapsulation types.\n");
731 fprintf(output, "\n");
732 fprintf(output, "Miscellaneous:\n");
733 fprintf(output, " -h display this help and exit.\n");
734 fprintf(output, " -v verbose output.\n");
735 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
736 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
737 fprintf(output, " and MD5 hashes are printed to standard-out.\n");
738 fprintf(output, "\n");
742 const char *sstr; /* The short string */
743 const char *lstr; /* The long string */
747 string_compare(gconstpointer a, gconstpointer b)
749 return strcmp(((const struct string_elem *)a)->sstr,
750 ((const struct string_elem *)b)->sstr);
754 string_elem_print(gpointer data, gpointer not_used _U_)
756 fprintf(stderr, " %s - %s\n",
757 ((struct string_elem *)data)->sstr,
758 ((struct string_elem *)data)->lstr);
762 list_capture_types(void) {
764 struct string_elem *captypes;
767 captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES);
768 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
769 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
770 if (wtap_dump_can_open(i)) {
771 captypes[i].sstr = wtap_file_type_short_string(i);
772 captypes[i].lstr = wtap_file_type_string(i);
773 list = g_slist_insert_sorted(list, &captypes[i], string_compare);
776 g_slist_foreach(list, string_elem_print, NULL);
782 list_encap_types(void) {
784 struct string_elem *encaps;
787 encaps = g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
788 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
789 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
790 encaps[i].sstr = wtap_encap_short_string(i);
791 if (encaps[i].sstr != NULL) {
792 encaps[i].lstr = wtap_encap_string(i);
793 list = g_slist_insert_sorted(list, &encaps[i], string_compare);
796 g_slist_foreach(list, string_elem_print, NULL);
803 * Don't report failures to load plugins because most (non-wiretap) plugins
804 * *should* fail to load (because we're not linked against libwireshark and
805 * dissector plugins need libwireshark).
808 failure_message(const char *msg_format _U_, va_list ap _U_)
815 main(int argc, char *argv[])
823 guint32 snaplen = 0; /* No limit */
824 int choplen = 0; /* No chop */
825 wtap_dumper *pdh = NULL;
827 unsigned duplicate_count = 0;
829 struct wtap_pkthdr snap_phdr;
830 const struct wtap_pkthdr *phdr;
833 int split_packet_count = 0;
834 int written_count = 0;
835 char *filename = NULL;
836 gboolean ts_okay = TRUE;
837 int secs_per_block = 0;
839 nstime_t block_start;
840 gchar *fprefix = NULL;
841 gchar *fsuffix = NULL;
844 char* init_progfile_dir_error;
848 arg_list_utf_16to8(argc, argv);
852 * Get credential information for later use.
854 init_process_policies();
857 /* Register wiretap plugins */
858 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
859 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
860 g_free(init_progfile_dir_error);
862 init_report_err(failure_message,NULL,NULL,NULL);
867 /* Process the options */
868 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
873 err_prob = strtod(optarg, &p);
874 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
875 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
879 srand( (unsigned int) (time(NULL) + getpid()) );
883 out_file_type = wtap_short_string_to_file_type(optarg);
884 if (out_file_type < 0) {
885 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
887 list_capture_types();
893 split_packet_count = strtol(optarg, &p, 10);
894 if (p == optarg || *p != '\0') {
895 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
899 if (split_packet_count <= 0) {
900 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
907 choplen = strtol(optarg, &p, 10);
908 if (p == optarg || *p != '\0') {
909 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
917 dup_detect_by_time = FALSE;
918 dup_window = DEFAULT_DUP_DEPTH;
923 dup_detect_by_time = FALSE;
924 dup_window = strtol(optarg, &p, 10);
925 if (p == optarg || *p != '\0') {
926 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
930 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
931 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
932 dup_window, MAX_DUP_DEPTH);
939 dup_detect_by_time = TRUE;
940 dup_window = MAX_DUP_DEPTH;
941 set_rel_time(optarg);
944 case '?': /* Bad options if GNU getopt */
947 list_capture_types();
964 keep_em = !keep_em; /* Just invert */
968 snaplen = strtol(optarg, &p, 10);
969 if (p == optarg || *p != '\0') {
970 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
977 set_time_adjustment(optarg);
981 set_strict_time_adj(optarg);
982 do_strict_time_adjustment = TRUE;
986 out_frame_type = wtap_short_string_to_encap(optarg);
987 if (out_frame_type < 0) {
988 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
996 verbose = !verbose; /* Just invert */
999 case 'i': /* break capture file based on time interval */
1000 secs_per_block = atoi(optarg);
1001 if(secs_per_block <= 0) {
1002 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1011 memset(&starttm,0,sizeof(struct tm));
1013 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1014 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1018 check_startstop = TRUE;
1019 starttm.tm_isdst = -1;
1021 starttime = mktime(&starttm);
1029 memset(&stoptm,0,sizeof(struct tm));
1031 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1032 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1035 check_startstop = TRUE;
1036 stoptm.tm_isdst = -1;
1037 stoptime = mktime(&stoptm);
1045 printf("Optind = %i, argc = %i\n", optind, argc);
1048 if ((argc - optind) < 1) {
1055 if (check_startstop && !stoptime) {
1057 /* XXX: will work until 2035 */
1058 memset(&stoptm,0,sizeof(struct tm));
1059 stoptm.tm_year = 135;
1060 stoptm.tm_mday = 31;
1063 stoptime = mktime(&stoptm);
1066 nstime_set_unset(&block_start);
1068 if (starttime > stoptime) {
1069 fprintf(stderr, "editcap: start time is after the stop time\n");
1073 if (split_packet_count > 0 && secs_per_block > 0) {
1074 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1075 fprintf(stderr, "editcap: at the same time\n");
1079 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1082 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1083 wtap_strerror(err));
1086 case WTAP_ERR_UNSUPPORTED:
1087 case WTAP_ERR_UNSUPPORTED_ENCAP:
1088 case WTAP_ERR_BAD_RECORD:
1089 fprintf(stderr, "(%s)\n", err_info);
1098 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1099 wtap_file_type_string(wtap_file_type(wth)));
1103 * Now, process the rest, if any ... we only write if there is an extra
1104 * argument or so ...
1107 if ((argc - optind) >= 2) {
1109 if (out_frame_type == -2)
1110 out_frame_type = wtap_file_encap(wth);
1112 for (i = optind + 2; i < argc; i++)
1113 if (add_selection(argv[i]) == FALSE)
1116 if (dup_detect || dup_detect_by_time) {
1117 for (i = 0; i < dup_window; i++) {
1118 memset(&fd_hash[i].digest, 0, 16);
1120 nstime_set_unset(&fd_hash[i].time);
1124 while (wtap_read(wth, &err, &err_info, &data_offset)) {
1125 phdr = wtap_phdr(wth);
1126 buf = wtap_buf_ptr(wth);
1128 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
1129 block_start.secs = phdr->ts.secs;
1130 block_start.nsecs = phdr->ts.nsecs;
1132 if (split_packet_count > 0 || secs_per_block > 0) {
1133 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1136 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1138 filename = g_strdup(argv[optind+1]);
1140 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1141 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1142 FALSE /* compressed */, &err);
1144 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1145 wtap_strerror(err));
1152 if (secs_per_block > 0) {
1153 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1154 (phdr->ts.secs - block_start.secs == secs_per_block &&
1155 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1157 if (!wtap_dump_close(pdh, &err)) {
1158 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1159 wtap_strerror(err));
1162 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1164 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1168 fprintf(stderr, "Continuing writing in file %s\n", filename);
1171 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1172 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1173 FALSE /* compressed */, &err);
1176 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1177 wtap_strerror(err));
1183 if (split_packet_count > 0) {
1185 /* time for the next file? */
1186 if (written_count > 0 &&
1187 written_count % split_packet_count == 0) {
1188 if (!wtap_dump_close(pdh, &err)) {
1189 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1190 wtap_strerror(err));
1195 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1199 fprintf(stderr, "Continuing writing in file %s\n", filename);
1202 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1203 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1204 FALSE /* compressed */, &err);
1206 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1207 wtap_strerror(err));
1213 if (check_startstop)
1214 ts_okay = check_timestamp(wth);
1216 if ( ts_okay && ((!selected(count) && !keep_em) || (selected(count) && keep_em)) ) {
1218 if (verbose && !dup_detect && !dup_detect_by_time)
1219 printf("Packet: %u\n", count);
1221 /* We simply write it, perhaps after truncating it; we could do other
1222 things, like modify it. */
1224 phdr = wtap_phdr(wth);
1226 if (snaplen != 0 && phdr->caplen > snaplen) {
1228 snap_phdr.caplen = snaplen;
1234 if (((signed int) phdr->caplen + choplen) > 0)
1235 snap_phdr.caplen += choplen;
1237 snap_phdr.caplen = 0;
1239 } else if (choplen > 0) {
1241 if (phdr->caplen > (unsigned int) choplen) {
1242 snap_phdr.caplen -= choplen;
1245 snap_phdr.caplen = 0;
1250 * Do we adjust timestamps to insure strict chronologically order?
1253 if (do_strict_time_adjustment) {
1254 if (previous_time.secs || previous_time.nsecs) {
1255 if (!strict_time_adj.is_negative) {
1259 current.secs = phdr->ts.secs;
1260 current.nsecs = phdr->ts.nsecs;
1262 nstime_delta(&delta, ¤t, &previous_time);
1264 if (delta.secs < 0 || delta.nsecs < 0)
1267 * A negative delta indicates that the current packet
1268 * has an absolute timestamp less than the previous packet
1269 * that it is being compared to. This is NOT a normal
1270 * situation since trace files usually have packets in
1271 * chronological order (oldest to newest).
1273 /* printf("++out of order, need to adjust this packet!\n"); */
1275 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1276 snap_phdr.ts.nsecs = previous_time.nsecs;
1277 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1279 snap_phdr.ts.secs++;
1280 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1282 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1288 * A negative strict time adjustment is requested.
1289 * Unconditionally set each timestamp to previous
1290 * packet's timestamp plus delta.
1293 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1294 snap_phdr.ts.nsecs = previous_time.nsecs;
1295 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1297 snap_phdr.ts.secs++;
1298 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1300 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1305 previous_time.secs = phdr->ts.secs;
1306 previous_time.nsecs = phdr->ts.nsecs;
1309 /* assume that if the frame's tv_sec is 0, then
1310 * the timestamp isn't supported */
1311 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1313 if (time_adj.is_negative)
1314 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1316 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1320 /* assume that if the frame's tv_sec is 0, then
1321 * the timestamp isn't supported */
1322 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1324 if (time_adj.is_negative) { /* subtract */
1325 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1326 snap_phdr.ts.secs--;
1327 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1329 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1331 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1333 snap_phdr.ts.secs++;
1334 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1336 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1342 /* suppress duplicates by packet window */
1344 if (is_duplicate(buf, phdr->caplen)) {
1346 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1347 for (i = 0; i < 16; i++) {
1348 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1350 fprintf(stdout, "\n");
1357 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1358 for (i = 0; i < 16; i++) {
1359 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1361 fprintf(stdout, "\n");
1366 /* suppress duplicates by time window */
1367 if (dup_detect_by_time) {
1370 current.secs = phdr->ts.secs;
1371 current.nsecs = phdr->ts.nsecs;
1373 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1375 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1376 for (i = 0; i < 16; i++) {
1377 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1379 fprintf(stdout, "\n");
1386 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1387 for (i = 0; i < 16; i++) {
1388 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1390 fprintf(stdout, "\n");
1395 /* Random error mutation */
1396 if (err_prob > 0.0) {
1397 int real_data_start = 0;
1398 /* Protect non-protocol data */
1399 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1400 real_data_start = find_dct2000_real_data(buf);
1402 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1403 if (rand() <= err_prob * RAND_MAX) {
1404 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1406 if (err_type < ERR_WT_BIT) {
1407 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1408 err_type = ERR_WT_TOTAL;
1410 err_type -= ERR_WT_BYTE;
1413 if (err_type < ERR_WT_BYTE) {
1414 buf[i] = rand() / (RAND_MAX / 255 + 1);
1415 err_type = ERR_WT_TOTAL;
1417 err_type -= ERR_WT_BYTE;
1420 if (err_type < ERR_WT_ALNUM) {
1421 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1422 err_type = ERR_WT_TOTAL;
1424 err_type -= ERR_WT_ALNUM;
1427 if (err_type < ERR_WT_FMT) {
1428 if ((unsigned int)i < phdr->caplen - 2)
1429 g_strlcpy((char*) &buf[i], "%s", 2);
1430 err_type = ERR_WT_TOTAL;
1432 err_type -= ERR_WT_FMT;
1435 if (err_type < ERR_WT_AA) {
1436 for (j = i; j < (int) phdr->caplen; j++) {
1445 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1446 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1447 filename, wtap_strerror(err));
1459 /* Print a message noting that the read failed somewhere along the line. */
1461 "editcap: An error occurred while reading \"%s\": %s.\n",
1462 argv[optind], wtap_strerror(err));
1465 case WTAP_ERR_UNSUPPORTED:
1466 case WTAP_ERR_UNSUPPORTED_ENCAP:
1467 case WTAP_ERR_BAD_RECORD:
1468 fprintf(stderr, "(%s)\n", err_info);
1475 /* No valid packages found, open the outfile so we can write an empty header */
1477 filename = g_strdup(argv[optind+1]);
1479 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1480 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1481 FALSE /* compressed */, &err);
1483 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1484 wtap_strerror(err));
1489 if (!wtap_dump_close(pdh, &err)) {
1491 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1492 wtap_strerror(err));
1500 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1501 count - 1, plurality(count - 1, "", "s"),
1502 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1503 } else if (dup_detect_by_time) {
1504 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1505 count - 1, plurality(count - 1, "", "s"),
1506 duplicate_count, plurality(duplicate_count, "", "s"),
1507 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1513 /* Skip meta-information read from file to return offset of real
1515 static int find_dct2000_real_data(guint8 *buf)
1519 for (n=0; buf[n] != '\0'; n++); /* Context name */
1521 n++; /* Context port number */
1522 for (; buf[n] != '\0'; n++); /* Timestamp */
1524 for (; buf[n] != '\0'; n++); /* Protocol name */
1526 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1528 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1530 n += 2; /* Direction & encap */