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 <process.h> /* getpid */
53 #ifdef HAVE_WINSOCK2_H
58 #ifdef NEED_STRPTIME_H
59 # include "wsutil/strptime.h"
62 #include "epan/crypt/crypt-md5.h"
63 #include "epan/plugins.h"
64 #include "epan/report_err.h"
65 #include "epan/filesystem.h"
66 #include <wsutil/privileges.h>
67 #include "epan/nstime.h"
69 #include "svnversion.h"
72 * Some globals so we can pass things to various routines
84 * Duplicate frame detection
86 typedef struct _fd_hash_t {
87 md5_byte_t digest[16];
92 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
93 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
95 fd_hash_t fd_hash[MAX_DUP_DEPTH];
96 int dup_window = DEFAULT_DUP_DEPTH;
97 int cur_dup_entry = 0;
99 #define ONE_MILLION 1000000
100 #define ONE_BILLION 1000000000
102 /* Weights of different errors we can introduce */
103 /* We should probably make these command-line arguments */
104 /* XXX - Should we add a bit-level error? */
105 #define ERR_WT_BIT 5 /* Flip a random bit */
106 #define ERR_WT_BYTE 5 /* Substitute a random byte */
107 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
108 #define ERR_WT_FMT 2 /* Substitute "%s" */
109 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
110 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
112 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
113 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
116 struct time_adjustment {
121 #define MAX_SELECTIONS 512
122 static struct select_item selectfrm[MAX_SELECTIONS];
123 static int max_selected = -1;
124 static int keep_em = 0;
125 static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */
126 static int out_frame_type = -2; /* Leave frame type alone */
127 static int verbose = 0; /* Not so verbose */
128 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
129 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
130 static double err_prob = 0.0;
131 static time_t starttime = 0;
132 static time_t stoptime = 0;
133 static gboolean check_startstop = FALSE;
134 static gboolean dup_detect = FALSE;
135 static gboolean dup_detect_by_time = FALSE;
137 static int do_strict_time_adjustment = FALSE;
138 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
139 static nstime_t previous_time = {0, 0}; /* previous time */
141 static int find_dct2000_real_data(guint8 *buf);
144 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
147 gchar *buf = g_malloc(16);
150 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
151 /* XXX - find the exact value that still does work */
152 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
153 if(abs_time->secs > 2000000000) {
157 tmp = localtime(&abs_time->secs);
159 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
173 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time_val,
174 gchar *fprefix, gchar *fsuffix)
180 timestr = abs_time_to_str_with_sec_resolution(time_val);
181 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
182 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
189 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
191 char *pfx, *last_pathsep;
194 save_file = g_strdup(fname);
195 if (save_file == NULL) {
196 fprintf(stderr, "editcap: Out of memory\n");
200 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
201 pfx = strrchr(save_file,'.');
202 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
203 /* The pathname has a "." in it, and it's in the last component
204 of the pathname (because there is either only one component,
205 i.e. last_pathsep is null as there are no path separators,
206 or the "." is after the path separator before the last
209 Treat it as a separator between the rest of the file name and
210 the file name suffix, and arrange that the names given to the
211 ring buffer files have the specified suffix, i.e. put the
212 changing part of the name *before* the suffix. */
214 *fprefix = g_strdup(save_file);
215 pfx[0] = '.'; /* restore capfile_name */
216 *fsuffix = g_strdup(pfx);
218 /* Either there's no "." in the pathname, or it's in a directory
219 component, so the last component has no suffix. */
220 *fprefix = g_strdup(save_file);
227 /* Add a selection item, a simple parser for now */
229 add_selection(char *sel)
234 if (++max_selected >= MAX_SELECTIONS) {
235 /* Let the user know we stopped selecting */
236 printf("Out of room for packet selections!\n");
240 printf("Add_Selected: %s\n", sel);
242 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
244 printf("Not inclusive ...");
246 selectfrm[max_selected].inclusive = 0;
247 selectfrm[max_selected].first = atoi(sel);
249 printf(" %i\n", selectfrm[max_selected].first);
254 printf("Inclusive ...");
257 selectfrm[max_selected].inclusive = 1;
258 selectfrm[max_selected].first = atoi(sel);
259 selectfrm[max_selected].second = atoi(next);
261 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
268 /* Was the packet selected? */
275 for (i = 0; i<= max_selected; i++) {
277 if (selectfrm[i].inclusive) {
278 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
282 if (recno == selectfrm[i].first)
291 /* is the packet in the selected timeframe */
293 check_timestamp(wtap *wth)
295 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
297 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs <= stoptime );
301 set_time_adjustment(char *optarg_str_p)
310 /* skip leading whitespace */
311 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
315 /* check for a negative adjustment */
316 if (*optarg_str_p == '-') {
317 time_adj.is_negative = 1;
321 /* collect whole number of seconds, if any */
322 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
326 val = strtol(optarg_str_p, &frac, 10);
327 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
328 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
332 if (val < 0) { /* implies '--' since we caught '-' above */
333 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
338 time_adj.tv.tv_sec = val;
340 /* now collect the partial seconds, if any */
341 if (*frac != '\0') { /* chars left, so get fractional part */
342 val = strtol(&(frac[1]), &end, 10);
343 /* if more than 6 fractional digits truncate to 6 */
344 if((end - &(frac[1])) > 6) {
345 frac[7] = 't'; /* 't' for truncate */
346 val = strtol(&(frac[1]), &end, 10);
348 if (*frac != '.' || end == NULL || end == frac
349 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
350 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
356 return; /* no fractional digits */
359 /* adjust fractional portion from fractional to numerator
360 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
361 if (frac && end) { /* both are valid */
362 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
363 while(frac_digits < 6) { /* this is frac of 10^6 */
368 time_adj.tv.tv_usec = val;
372 set_strict_time_adj(char *optarg)
381 /* skip leading whitespace */
382 while (*optarg == ' ' || *optarg == '\t') {
387 * check for a negative adjustment
388 * A negative strict adjustment value is a flag
389 * to adjust all frames by the specifed delta time.
391 if (*optarg == '-') {
392 strict_time_adj.is_negative = 1;
396 /* collect whole number of seconds, if any */
397 if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */
401 val = strtol(optarg, &frac, 10);
402 if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
403 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
407 if (val < 0) { /* implies '--' since we caught '-' above */
408 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
413 strict_time_adj.tv.tv_sec = val;
415 /* now collect the partial seconds, if any */
416 if (*frac != '\0') { /* chars left, so get fractional part */
417 val = strtol(&(frac[1]), &end, 10);
418 /* if more than 6 fractional digits truncate to 6 */
419 if((end - &(frac[1])) > 6) {
420 frac[7] = 't'; /* 't' for truncate */
421 val = strtol(&(frac[1]), &end, 10);
423 if (*frac != '.' || end == NULL || end == frac
424 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
425 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
431 return; /* no fractional digits */
434 /* adjust fractional portion from fractional to numerator
435 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
436 if (frac && end) { /* both are valid */
437 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
438 while(frac_digits < 6) { /* this is frac of 10^6 */
443 strict_time_adj.tv.tv_usec = val;
447 set_rel_time(char *optarg_str_p)
456 /* skip leading whitespace */
457 while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
461 /* ignore negative adjustment */
462 if (*optarg_str_p == '-') {
466 /* collect whole number of seconds, if any */
467 if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */
471 val = strtol(optarg_str_p, &frac, 10);
472 if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
473 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
477 if (val < 0) { /* implies '--' since we caught '-' above */
478 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
483 relative_time_window.secs = val;
485 /* now collect the partial seconds, if any */
486 if (*frac != '\0') { /* chars left, so get fractional part */
487 val = strtol(&(frac[1]), &end, 10);
488 /* if more than 9 fractional digits truncate to 9 */
489 if((end - &(frac[1])) > 9) {
490 frac[10] = 't'; /* 't' for truncate */
491 val = strtol(&(frac[1]), &end, 10);
493 if (*frac != '.' || end == NULL || end == frac
494 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
495 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
501 return; /* no fractional digits */
504 /* adjust fractional portion from fractional to numerator
505 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
506 if (frac && end) { /* both are valid */
507 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
508 while(frac_digits < 9) { /* this is frac of 10^9 */
513 relative_time_window.nsecs = val;
517 is_duplicate(guint8* fd, guint32 len) {
522 if (cur_dup_entry >= dup_window)
525 /* Calculate our digest */
527 md5_append(&ms, fd, len);
528 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
530 fd_hash[cur_dup_entry].len = len;
532 /* Look for duplicates */
533 for (i = 0; i < dup_window; i++) {
534 if (i == cur_dup_entry)
537 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
538 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
547 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
552 if (cur_dup_entry >= dup_window)
555 /* Calculate our digest */
557 md5_append(&ms, fd, len);
558 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
560 fd_hash[cur_dup_entry].len = len;
561 fd_hash[cur_dup_entry].time.secs = current->secs;
562 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
565 * Look for relative time related duplicates.
566 * This is hopefully a reasonably efficient mechanism for
567 * finding duplicates by rel time in the fd_hash[] cache.
568 * We check starting from the most recently added hash
569 * entries and work backwards towards older packets.
570 * This approach allows the dup test to be terminated
571 * when the relative time of a cached entry is found to
572 * be beyond the dup time window.
574 * Of course this assumes that the input trace file is
575 * "well-formed" in the sense that the packet timestamps are
576 * in strict chronologically increasing order (which is NOT
577 * always the case!!).
579 * The fd_hash[] table was deliberatly created large (1,000,000).
580 * Looking for time related duplicates in large trace files with
581 * non-fractional dup time window values can potentially take
582 * a long time to complete.
585 for (i = cur_dup_entry - 1;; i--) {
593 if (i == cur_dup_entry) {
595 * We've decremented back to where we started.
601 if (nstime_is_unset(&(fd_hash[i].time))) {
603 * We've decremented to an unused fd_hash[] entry.
609 nstime_delta(&delta, current, &fd_hash[i].time);
611 if(delta.secs < 0 || delta.nsecs < 0)
614 * A negative delta implies that the current packet
615 * has an absolute timestamp less than the cached packet
616 * that it is being compared to. This is NOT a normal
617 * situation since trace files usually have packets in
618 * chronological order (oldest to newest).
620 * There are several possible ways to deal with this:
621 * 1. 'continue' dup checking with the next cached frame.
622 * 2. 'break' from looking for a duplicate of the current frame.
623 * 3. Take the absolute value of the delta and see if that
624 * falls within the specifed dup time window.
626 * Currently this code does option 1. But it would pretty
627 * easy to add yet-another-editcap-option to select one of
628 * the other behaviors for dealing with out-of-sequence
634 cmp = nstime_cmp(&delta, &relative_time_window);
638 * The delta time indicates that we are now looking at
639 * cached packets beyond the specified dup time window.
643 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
644 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
653 usage(gboolean is_error)
662 fprintf(output, "Editcap %s"
664 " (" SVNVERSION " from " SVNPATH ")"
667 fprintf(output, "Edit and/or translate the format of capture files.\n");
668 fprintf(output, "See http://www.wireshark.org for more information.\n");
669 fprintf(output, "\n");
670 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
671 fprintf(output, "\n");
672 fprintf(output, "<infile> and <outfile> must both be present.\n");
673 fprintf(output, "A single packet or a range of packets can be selected.\n");
674 fprintf(output, "\n");
675 fprintf(output, "Packet selection:\n");
676 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
677 fprintf(output, " -A <start time> don't output packets whose timestamp is before the\n");
678 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
679 fprintf(output, " -B <stop time> don't output packets whose timestamp is after the\n");
680 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
681 fprintf(output, "\n");
682 fprintf(output, "Duplicate packet removal:\n");
683 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
684 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
685 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
686 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
687 fprintf(output, " useful to print MD5 hashes.\n");
688 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
689 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
690 fprintf(output, " A <dup time window> is specified in relative seconds\n");
691 fprintf(output, " (e.g. 0.000001).\n");
692 fprintf(output, "\n");
693 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
694 fprintf(output, " other editcap options except -v may not always work as expected.\n");
695 fprintf(stderr, " Specifically the -r, -t or -S options will very likely NOT have the\n");
696 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
697 fprintf(output, "\n");
698 fprintf(output, "Packet manipulation:\n");
699 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
700 fprintf(output, " -C <choplen> chop each packet at the end by <choplen> bytes.\n");
701 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
702 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
703 fprintf(stderr, " -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
704 fprintf(stderr, " strict chronological increasing order. The <strict\n");
705 fprintf(stderr, " adjustment> is specified in relative seconds with\n");
706 fprintf(stderr, " values of 0 or 0.000001 being the most reasonable.\n");
707 fprintf(stderr, " A negative adjustment value will modify timestamps so\n");
708 fprintf(stderr, " that each packet's delta time is the absolute value\n");
709 fprintf(stderr, " of the adjustment specified. A value of -0 will set\n");
710 fprintf(stderr, " all packets to the timestamp of the first packet.\n");
711 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
712 fprintf(output, " that a particular packet byte will be randomly changed.\n");
713 fprintf(output, "\n");
714 fprintf(output, "Output File(s):\n");
715 fprintf(output, " -c <packets per file> split the packet output to different files\n");
716 fprintf(output, " based on uniform packet counts\n");
717 fprintf(output, " with a maximum of <packets per file> each.\n");
718 fprintf(output, " -i <seconds per file> split the packet output to different files\n");
719 fprintf(output, " based on uniform time intervals\n");
720 fprintf(output, " with a maximum of <seconds per file> each.\n");
721 fprintf(output, " -F <capture type> set the output file type; default is libpcap.\n");
722 fprintf(output, " an empty \"-F\" option will list the file types.\n");
723 fprintf(output, " -T <encap type> set the output file encapsulation type;\n");
724 fprintf(output, " default is the same as the input file.\n");
725 fprintf(output, " an empty \"-T\" option will list the encapsulation types.\n");
726 fprintf(output, "\n");
727 fprintf(output, "Miscellaneous:\n");
728 fprintf(output, " -h display this help and exit.\n");
729 fprintf(output, " -v verbose output.\n");
730 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
731 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
732 fprintf(output, " and MD5 hashes are printed to standard-out.\n");
733 fprintf(output, "\n");
737 list_capture_types(void) {
740 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
741 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
742 if (wtap_dump_can_open(i))
743 fprintf(stderr, " %s - %s\n",
744 wtap_file_type_short_string(i), wtap_file_type_string(i));
749 list_encap_types(void) {
753 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
754 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
755 string = wtap_encap_short_string(i);
757 fprintf(stderr, " %s - %s\n",
758 string, wtap_encap_string(i));
764 * Don't report failures to load plugins because most (non-wiretap) plugins
765 * *should* fail to load (because we're not linked against libwireshark and
766 * dissector plugins need libwireshark).
769 failure_message(const char *msg_format _U_, va_list ap _U_)
776 main(int argc, char *argv[])
783 unsigned int snaplen = 0; /* No limit */
784 unsigned int choplen = 0; /* No chop */
785 wtap_dumper *pdh = NULL;
787 unsigned duplicate_count = 0;
789 struct wtap_pkthdr snap_phdr;
790 const struct wtap_pkthdr *phdr;
793 int split_packet_count = 0;
794 int written_count = 0;
795 char *filename = NULL;
797 int secs_per_block = 0;
799 nstime_t block_start;
800 gchar *fprefix = NULL;
801 gchar *fsuffix = NULL;
804 char* init_progfile_dir_error;
808 * Get credential information for later use.
810 get_credential_info();
813 /* Register wiretap plugins */
814 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
815 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
816 g_free(init_progfile_dir_error);
818 init_report_err(failure_message,NULL,NULL,NULL);
823 /* Process the options */
824 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
829 err_prob = strtod(optarg, &p);
830 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
831 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
835 srand( (unsigned int) (time(NULL) + getpid()) );
839 out_file_type = wtap_short_string_to_file_type(optarg);
840 if (out_file_type < 0) {
841 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
843 list_capture_types();
849 split_packet_count = strtol(optarg, &p, 10);
850 if (p == optarg || *p != '\0') {
851 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
855 if (split_packet_count <= 0) {
856 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
863 choplen = strtol(optarg, &p, 10);
864 if (p == optarg || *p != '\0') {
865 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
873 dup_detect_by_time = FALSE;
874 dup_window = DEFAULT_DUP_DEPTH;
879 dup_detect_by_time = FALSE;
880 dup_window = strtol(optarg, &p, 10);
881 if (p == optarg || *p != '\0') {
882 fprintf(stderr, "editcap: \"%s\" isn't a valid dupicate window value\n",
886 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
887 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
888 dup_window, MAX_DUP_DEPTH);
895 dup_detect_by_time = TRUE;
896 dup_window = MAX_DUP_DEPTH;
897 set_rel_time(optarg);
900 case '?': /* Bad options if GNU getopt */
903 list_capture_types();
920 keep_em = !keep_em; /* Just invert */
924 snaplen = strtol(optarg, &p, 10);
925 if (p == optarg || *p != '\0') {
926 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
933 set_time_adjustment(optarg);
937 set_strict_time_adj(optarg);
938 do_strict_time_adjustment = TRUE;
942 out_frame_type = wtap_short_string_to_encap(optarg);
943 if (out_frame_type < 0) {
944 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
952 verbose = !verbose; /* Just invert */
955 case 'i': /* break capture file based on time interval */
956 secs_per_block = atoi(optarg);
957 if(secs_per_block <= 0) {
958 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
967 memset(&starttm,0,sizeof(struct tm));
969 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
970 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
974 check_startstop = TRUE;
975 starttm.tm_isdst = -1;
977 starttime = mktime(&starttm);
985 memset(&stoptm,0,sizeof(struct tm));
987 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
988 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
991 check_startstop = TRUE;
992 stoptm.tm_isdst = -1;
993 stoptime = mktime(&stoptm);
1001 printf("Optind = %i, argc = %i\n", optind, argc);
1004 if ((argc - optind) < 1) {
1011 if (check_startstop && !stoptime) {
1013 /* XXX: will work until 2035 */
1014 memset(&stoptm,0,sizeof(struct tm));
1015 stoptm.tm_year = 135;
1016 stoptm.tm_mday = 31;
1019 stoptime = mktime(&stoptm);
1022 nstime_set_unset(&block_start);
1024 if (starttime > stoptime) {
1025 fprintf(stderr, "editcap: start time is after the stop time\n");
1029 if (split_packet_count > 0 && secs_per_block > 0) {
1030 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1031 fprintf(stderr, "editcap: at the same time\n");
1035 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1038 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1039 wtap_strerror(err));
1042 case WTAP_ERR_UNSUPPORTED:
1043 case WTAP_ERR_UNSUPPORTED_ENCAP:
1044 case WTAP_ERR_BAD_RECORD:
1045 fprintf(stderr, "(%s)\n", err_info);
1054 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1055 wtap_file_type_string(wtap_file_type(wth)));
1059 * Now, process the rest, if any ... we only write if there is an extra
1060 * argument or so ...
1063 if ((argc - optind) >= 2) {
1065 if (out_frame_type == -2)
1066 out_frame_type = wtap_file_encap(wth);
1068 for (i = optind + 2; i < argc; i++)
1069 if (add_selection(argv[i]) == FALSE)
1072 if (dup_detect || dup_detect_by_time) {
1073 for (i = 0; i < dup_window; i++) {
1074 memset(&fd_hash[i].digest, 0, 16);
1076 nstime_set_unset(&fd_hash[i].time);
1080 while (wtap_read(wth, &err, &err_info, &data_offset)) {
1081 phdr = wtap_phdr(wth);
1083 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
1084 block_start.secs = phdr->ts.secs;
1085 block_start.nsecs = phdr->ts.nsecs;
1087 if (split_packet_count > 0 || secs_per_block > 0) {
1088 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1091 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1093 filename = g_strdup(argv[optind+1]);
1095 pdh = wtap_dump_open(filename, out_file_type,
1096 out_frame_type, wtap_snapshot_length(wth),
1097 FALSE /* compressed */, &err);
1099 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1100 wtap_strerror(err));
1107 if (secs_per_block > 0) {
1108 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1109 (phdr->ts.secs - block_start.secs == secs_per_block &&
1110 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1112 if (!wtap_dump_close(pdh, &err)) {
1113 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1114 wtap_strerror(err));
1117 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1119 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1123 fprintf(stderr, "Continuing writing in file %s\n", filename);
1126 pdh = wtap_dump_open(filename, out_file_type,
1127 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1130 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1131 wtap_strerror(err));
1137 if (split_packet_count > 0) {
1139 /* time for the next file? */
1140 if (written_count > 0 &&
1141 written_count % split_packet_count == 0) {
1142 if (!wtap_dump_close(pdh, &err)) {
1143 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1144 wtap_strerror(err));
1149 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1153 fprintf(stderr, "Continuing writing in file %s\n", filename);
1156 pdh = wtap_dump_open(filename, out_file_type,
1157 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1159 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1160 wtap_strerror(err));
1166 check_ts = check_timestamp(wth);
1168 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1169 (selected(count) && keep_em)) ) {
1171 if (verbose && !dup_detect && !dup_detect_by_time)
1172 printf("Packet: %u\n", count);
1174 /* We simply write it, perhaps after truncating it; we could do other
1175 things, like modify it. */
1177 phdr = wtap_phdr(wth);
1179 if (choplen != 0 && phdr->caplen > choplen) {
1181 snap_phdr.caplen -= choplen;
1185 if (snaplen != 0 && phdr->caplen > snaplen) {
1187 snap_phdr.caplen = snaplen;
1192 * Do we adjust timestamps to insure strict chronologically order?
1195 if (do_strict_time_adjustment) {
1196 if (previous_time.secs || previous_time.nsecs) {
1197 if (!strict_time_adj.is_negative) {
1201 current.secs = phdr->ts.secs;
1202 current.nsecs = phdr->ts.nsecs;
1204 nstime_delta(&delta, ¤t, &previous_time);
1206 if (delta.secs < 0 || delta.nsecs < 0)
1209 * A negative delta indicates that the current packet
1210 * has an absolute timestamp less than the previous packet
1211 * that it is being compared to. This is NOT a normal
1212 * situation since trace files usually have packets in
1213 * chronological order (oldest to newest).
1215 /* printf("++out of order, need to adjust this packet!\n"); */
1217 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1218 snap_phdr.ts.nsecs = previous_time.nsecs;
1219 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1221 snap_phdr.ts.secs++;
1222 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1224 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1230 * A negative strict time adjustment is requested.
1231 * Unconditionally set each timestamp to previous
1232 * packet's timestamp plus delta.
1235 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1236 snap_phdr.ts.nsecs = previous_time.nsecs;
1237 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1239 snap_phdr.ts.secs++;
1240 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1242 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1247 previous_time.secs = phdr->ts.secs;
1248 previous_time.nsecs = phdr->ts.nsecs;
1251 /* assume that if the frame's tv_sec is 0, then
1252 * the timestamp isn't supported */
1253 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1255 if (time_adj.is_negative)
1256 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1258 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1262 /* assume that if the frame's tv_sec is 0, then
1263 * the timestamp isn't supported */
1264 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1266 if (time_adj.is_negative) { /* subtract */
1267 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1268 snap_phdr.ts.secs--;
1269 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1271 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1273 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1275 snap_phdr.ts.secs++;
1276 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1278 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1284 /* suppress duplicates by packet window */
1286 buf = wtap_buf_ptr(wth);
1287 if (is_duplicate(buf, phdr->caplen)) {
1289 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1290 for (i = 0; i < 16; i++) {
1291 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1293 fprintf(stdout, "\n");
1300 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1301 for (i = 0; i < 16; i++) {
1302 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1304 fprintf(stdout, "\n");
1309 /* suppress duplicates by time window */
1310 if (dup_detect_by_time) {
1313 current.secs = phdr->ts.secs;
1314 current.nsecs = phdr->ts.nsecs;
1316 buf = wtap_buf_ptr(wth);
1318 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1320 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1321 for (i = 0; i < 16; i++) {
1322 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1324 fprintf(stdout, "\n");
1331 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1332 for (i = 0; i < 16; i++) {
1333 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1335 fprintf(stdout, "\n");
1340 /* Random error mutation */
1341 if (err_prob > 0.0) {
1342 int real_data_start = 0;
1343 buf = wtap_buf_ptr(wth);
1344 /* Protect non-protocol data */
1345 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1346 real_data_start = find_dct2000_real_data(buf);
1348 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1349 if (rand() <= err_prob * RAND_MAX) {
1350 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1352 if (err_type < ERR_WT_BIT) {
1353 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1354 err_type = ERR_WT_TOTAL;
1356 err_type -= ERR_WT_BYTE;
1359 if (err_type < ERR_WT_BYTE) {
1360 buf[i] = rand() / (RAND_MAX / 255 + 1);
1361 err_type = ERR_WT_TOTAL;
1363 err_type -= ERR_WT_BYTE;
1366 if (err_type < ERR_WT_ALNUM) {
1367 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1368 err_type = ERR_WT_TOTAL;
1370 err_type -= ERR_WT_ALNUM;
1373 if (err_type < ERR_WT_FMT) {
1374 if ((unsigned int)i < phdr->caplen - 2)
1375 strncpy((char*) &buf[i], "%s", 2);
1376 err_type = ERR_WT_TOTAL;
1378 err_type -= ERR_WT_FMT;
1381 if (err_type < ERR_WT_AA) {
1382 for (j = i; j < (int) phdr->caplen; j++) {
1391 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
1393 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1394 filename, wtap_strerror(err));
1406 /* Print a message noting that the read failed somewhere along the line. */
1408 "editcap: An error occurred while reading \"%s\": %s.\n",
1409 argv[optind], wtap_strerror(err));
1412 case WTAP_ERR_UNSUPPORTED:
1413 case WTAP_ERR_UNSUPPORTED_ENCAP:
1414 case WTAP_ERR_BAD_RECORD:
1415 fprintf(stderr, "(%s)\n", err_info);
1422 /* No valid packages found, open the outfile so we can write an empty header */
1424 filename = g_strdup(argv[optind+1]);
1426 pdh = wtap_dump_open(filename, out_file_type,
1427 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1429 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1430 wtap_strerror(err));
1435 if (!wtap_dump_close(pdh, &err)) {
1437 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1438 wtap_strerror(err));
1446 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1447 count - 1, plurality(count - 1, "", "s"),
1448 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1449 } else if (dup_detect_by_time) {
1450 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1451 count - 1, plurality(count - 1, "", "s"),
1452 duplicate_count, plurality(duplicate_count, "", "s"),
1453 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1459 /* Skip meta-information read from file to return offset of real
1461 static int find_dct2000_real_data(guint8 *buf)
1465 for (n=0; buf[n] != '\0'; n++); /* Context name */
1467 n++; /* Context port number */
1468 for (; buf[n] != '\0'; n++); /* Timestamp */
1470 for (; buf[n] != '\0'; n++); /* Protocol name */
1472 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1474 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1476 n += 2; /* Direction & encap */