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 guint32 read_count = 0;
834 int split_packet_count = 0;
835 int written_count = 0;
836 char *filename = NULL;
837 gboolean ts_okay = TRUE;
838 int secs_per_block = 0;
840 nstime_t block_start;
841 gchar *fprefix = NULL;
842 gchar *fsuffix = NULL;
845 char* init_progfile_dir_error;
849 arg_list_utf_16to8(argc, argv);
853 * Get credential information for later use.
855 init_process_policies();
858 /* Register wiretap plugins */
859 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
860 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
861 g_free(init_progfile_dir_error);
863 init_report_err(failure_message,NULL,NULL,NULL);
868 /* Process the options */
869 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
874 err_prob = strtod(optarg, &p);
875 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
876 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
880 srand( (unsigned int) (time(NULL) + getpid()) );
884 out_file_type = wtap_short_string_to_file_type(optarg);
885 if (out_file_type < 0) {
886 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
888 list_capture_types();
894 split_packet_count = strtol(optarg, &p, 10);
895 if (p == optarg || *p != '\0') {
896 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
900 if (split_packet_count <= 0) {
901 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
908 choplen = strtol(optarg, &p, 10);
909 if (p == optarg || *p != '\0') {
910 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
918 dup_detect_by_time = FALSE;
919 dup_window = DEFAULT_DUP_DEPTH;
924 dup_detect_by_time = FALSE;
925 dup_window = strtol(optarg, &p, 10);
926 if (p == optarg || *p != '\0') {
927 fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
931 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
932 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
933 dup_window, MAX_DUP_DEPTH);
940 dup_detect_by_time = TRUE;
941 dup_window = MAX_DUP_DEPTH;
942 set_rel_time(optarg);
945 case '?': /* Bad options if GNU getopt */
948 list_capture_types();
965 keep_em = !keep_em; /* Just invert */
969 snaplen = strtol(optarg, &p, 10);
970 if (p == optarg || *p != '\0') {
971 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
978 set_time_adjustment(optarg);
982 set_strict_time_adj(optarg);
983 do_strict_time_adjustment = TRUE;
987 out_frame_type = wtap_short_string_to_encap(optarg);
988 if (out_frame_type < 0) {
989 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
997 verbose = !verbose; /* Just invert */
1000 case 'i': /* break capture file based on time interval */
1001 secs_per_block = atoi(optarg);
1002 if(secs_per_block <= 0) {
1003 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1012 memset(&starttm,0,sizeof(struct tm));
1014 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1015 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1019 check_startstop = TRUE;
1020 starttm.tm_isdst = -1;
1022 starttime = mktime(&starttm);
1030 memset(&stoptm,0,sizeof(struct tm));
1032 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1033 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1036 check_startstop = TRUE;
1037 stoptm.tm_isdst = -1;
1038 stoptime = mktime(&stoptm);
1046 printf("Optind = %i, argc = %i\n", optind, argc);
1049 if ((argc - optind) < 1) {
1056 if (check_startstop && !stoptime) {
1058 /* XXX: will work until 2035 */
1059 memset(&stoptm,0,sizeof(struct tm));
1060 stoptm.tm_year = 135;
1061 stoptm.tm_mday = 31;
1064 stoptime = mktime(&stoptm);
1067 nstime_set_unset(&block_start);
1069 if (starttime > stoptime) {
1070 fprintf(stderr, "editcap: start time is after the stop time\n");
1074 if (split_packet_count > 0 && secs_per_block > 0) {
1075 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1076 fprintf(stderr, "editcap: at the same time\n");
1080 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1083 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1084 wtap_strerror(err));
1087 case WTAP_ERR_UNSUPPORTED:
1088 case WTAP_ERR_UNSUPPORTED_ENCAP:
1089 case WTAP_ERR_BAD_RECORD:
1090 fprintf(stderr, "(%s)\n", err_info);
1099 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1100 wtap_file_type_string(wtap_file_type(wth)));
1104 * Now, process the rest, if any ... we only write if there is an extra
1105 * argument or so ...
1108 if ((argc - optind) >= 2) {
1110 if (out_frame_type == -2)
1111 out_frame_type = wtap_file_encap(wth);
1113 for (i = optind + 2; i < argc; i++)
1114 if (add_selection(argv[i]) == FALSE)
1117 if (dup_detect || dup_detect_by_time) {
1118 for (i = 0; i < dup_window; i++) {
1119 memset(&fd_hash[i].digest, 0, 16);
1121 nstime_set_unset(&fd_hash[i].time);
1125 while (wtap_read(wth, &err, &err_info, &data_offset)) {
1128 phdr = wtap_phdr(wth);
1129 buf = wtap_buf_ptr(wth);
1131 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
1132 block_start.secs = phdr->ts.secs;
1133 block_start.nsecs = phdr->ts.nsecs;
1135 if (split_packet_count > 0 || secs_per_block > 0) {
1136 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1139 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1141 filename = g_strdup(argv[optind+1]);
1143 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1144 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1145 FALSE /* compressed */, &err);
1147 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1148 wtap_strerror(err));
1155 if (secs_per_block > 0) {
1156 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1157 (phdr->ts.secs - block_start.secs == secs_per_block &&
1158 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1160 if (!wtap_dump_close(pdh, &err)) {
1161 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1162 wtap_strerror(err));
1165 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1167 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1171 fprintf(stderr, "Continuing writing in file %s\n", filename);
1174 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1175 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1176 FALSE /* compressed */, &err);
1179 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1180 wtap_strerror(err));
1186 if (split_packet_count > 0) {
1188 /* time for the next file? */
1189 if (written_count > 0 &&
1190 written_count % split_packet_count == 0) {
1191 if (!wtap_dump_close(pdh, &err)) {
1192 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1193 wtap_strerror(err));
1198 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1202 fprintf(stderr, "Continuing writing in file %s\n", filename);
1205 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1206 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1207 FALSE /* compressed */, &err);
1209 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1210 wtap_strerror(err));
1216 if (check_startstop)
1217 ts_okay = check_timestamp(wth);
1219 if ( ts_okay && ((!selected(count) && !keep_em) || (selected(count) && keep_em)) ) {
1221 if (verbose && !dup_detect && !dup_detect_by_time)
1222 printf("Packet: %u\n", count);
1224 /* We simply write it, perhaps after truncating it; we could do other
1225 things, like modify it. */
1227 phdr = wtap_phdr(wth);
1229 if (snaplen != 0 && phdr->caplen > snaplen) {
1231 snap_phdr.caplen = snaplen;
1237 if (((signed int) phdr->caplen + choplen) > 0)
1238 snap_phdr.caplen += choplen;
1240 snap_phdr.caplen = 0;
1242 } else if (choplen > 0) {
1244 if (phdr->caplen > (unsigned int) choplen) {
1245 snap_phdr.caplen -= choplen;
1248 snap_phdr.caplen = 0;
1253 * Do we adjust timestamps to insure strict chronologically order?
1256 if (do_strict_time_adjustment) {
1257 if (previous_time.secs || previous_time.nsecs) {
1258 if (!strict_time_adj.is_negative) {
1262 current.secs = phdr->ts.secs;
1263 current.nsecs = phdr->ts.nsecs;
1265 nstime_delta(&delta, ¤t, &previous_time);
1267 if (delta.secs < 0 || delta.nsecs < 0)
1270 * A negative delta indicates that the current packet
1271 * has an absolute timestamp less than the previous packet
1272 * that it is being compared to. This is NOT a normal
1273 * situation since trace files usually have packets in
1274 * chronological order (oldest to newest).
1276 /* printf("++out of order, need to adjust this packet!\n"); */
1278 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1279 snap_phdr.ts.nsecs = previous_time.nsecs;
1280 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1282 snap_phdr.ts.secs++;
1283 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1285 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1291 * A negative strict time adjustment is requested.
1292 * Unconditionally set each timestamp to previous
1293 * packet's timestamp plus delta.
1296 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1297 snap_phdr.ts.nsecs = previous_time.nsecs;
1298 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1300 snap_phdr.ts.secs++;
1301 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1303 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1308 previous_time.secs = phdr->ts.secs;
1309 previous_time.nsecs = phdr->ts.nsecs;
1312 /* assume that if the frame's tv_sec is 0, then
1313 * the timestamp isn't supported */
1314 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1316 if (time_adj.is_negative)
1317 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1319 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1323 /* assume that if the frame's tv_sec is 0, then
1324 * the timestamp isn't supported */
1325 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1327 if (time_adj.is_negative) { /* subtract */
1328 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1329 snap_phdr.ts.secs--;
1330 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1332 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1334 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1336 snap_phdr.ts.secs++;
1337 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1339 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1345 /* suppress duplicates by packet window */
1347 if (is_duplicate(buf, phdr->caplen)) {
1349 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1350 for (i = 0; i < 16; i++) {
1351 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1353 fprintf(stdout, "\n");
1360 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1361 for (i = 0; i < 16; i++) {
1362 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1364 fprintf(stdout, "\n");
1369 /* suppress duplicates by time window */
1370 if (dup_detect_by_time) {
1373 current.secs = phdr->ts.secs;
1374 current.nsecs = phdr->ts.nsecs;
1376 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1378 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1379 for (i = 0; i < 16; i++) {
1380 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1382 fprintf(stdout, "\n");
1389 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1390 for (i = 0; i < 16; i++) {
1391 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1393 fprintf(stdout, "\n");
1398 /* Random error mutation */
1399 if (err_prob > 0.0) {
1400 int real_data_start = 0;
1401 /* Protect non-protocol data */
1402 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1403 real_data_start = find_dct2000_real_data(buf);
1405 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1406 if (rand() <= err_prob * RAND_MAX) {
1407 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1409 if (err_type < ERR_WT_BIT) {
1410 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1411 err_type = ERR_WT_TOTAL;
1413 err_type -= ERR_WT_BYTE;
1416 if (err_type < ERR_WT_BYTE) {
1417 buf[i] = rand() / (RAND_MAX / 255 + 1);
1418 err_type = ERR_WT_TOTAL;
1420 err_type -= ERR_WT_BYTE;
1423 if (err_type < ERR_WT_ALNUM) {
1424 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1425 err_type = ERR_WT_TOTAL;
1427 err_type -= ERR_WT_ALNUM;
1430 if (err_type < ERR_WT_FMT) {
1431 if ((unsigned int)i < phdr->caplen - 2)
1432 g_strlcpy((char*) &buf[i], "%s", 2);
1433 err_type = ERR_WT_TOTAL;
1435 err_type -= ERR_WT_FMT;
1438 if (err_type < ERR_WT_AA) {
1439 for (j = i; j < (int) phdr->caplen; j++) {
1448 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1451 case WTAP_ERR_UNSUPPORTED_ENCAP:
1453 * This is a problem with the particular frame we're writing;
1454 * note that, and give the frame number.
1456 fprintf(stderr, "editcap: Frame %u of \"%s\" has a network type that can't be saved in a file with that format\n.",
1457 read_count, argv[optind]);
1461 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1462 filename, wtap_strerror(err));
1476 /* Print a message noting that the read failed somewhere along the line. */
1478 "editcap: An error occurred while reading \"%s\": %s.\n",
1479 argv[optind], wtap_strerror(err));
1482 case WTAP_ERR_UNSUPPORTED:
1483 case WTAP_ERR_UNSUPPORTED_ENCAP:
1484 case WTAP_ERR_BAD_RECORD:
1485 fprintf(stderr, "(%s)\n", err_info);
1492 /* No valid packages found, open the outfile so we can write an empty header */
1494 filename = g_strdup(argv[optind+1]);
1496 pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1497 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1498 FALSE /* compressed */, &err);
1500 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1501 wtap_strerror(err));
1506 if (!wtap_dump_close(pdh, &err)) {
1508 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1509 wtap_strerror(err));
1517 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1518 count - 1, plurality(count - 1, "", "s"),
1519 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1520 } else if (dup_detect_by_time) {
1521 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1522 count - 1, plurality(count - 1, "", "s"),
1523 duplicate_count, plurality(duplicate_count, "", "s"),
1524 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1530 /* Skip meta-information read from file to return offset of real
1532 static int find_dct2000_real_data(guint8 *buf)
1536 for (n=0; buf[n] != '\0'; n++); /* Context name */
1538 n++; /* Context port number */
1539 for (; buf[n] != '\0'; n++); /* Timestamp */
1541 for (; buf[n] != '\0'; n++); /* Protocol name */
1543 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1545 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1547 n += 2; /* Direction & encap */