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
52 #include <process.h> /* getpid */
53 #ifdef HAVE_WINSOCK2_H
58 #ifdef NEED_STRPTIME_H
59 # include "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 find_dct2000_real_data(guint8 *buf);
140 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
143 gchar *buf = g_malloc(16);
146 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
147 /* XXX - find the exact value that still does work */
148 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
149 if(abs_time->secs > 2000000000) {
153 tmp = localtime(&abs_time->secs);
155 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
169 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time,
170 gchar *fprefix, gchar *fsuffix)
176 timestr = abs_time_to_str_with_sec_resolution(time);
177 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
178 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
185 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
187 char *pfx, *last_pathsep;
190 save_file = g_strdup(fname);
191 if (save_file == NULL) {
192 fprintf(stderr, "editcap: Out of memory\n");
196 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
197 pfx = strrchr(save_file,'.');
198 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
199 /* The pathname has a "." in it, and it's in the last component
200 of the pathname (because there is either only one component,
201 i.e. last_pathsep is null as there are no path separators,
202 or the "." is after the path separator before the last
205 Treat it as a separator between the rest of the file name and
206 the file name suffix, and arrange that the names given to the
207 ring buffer files have the specified suffix, i.e. put the
208 changing part of the name *before* the suffix. */
210 *fprefix = g_strdup(save_file);
211 pfx[0] = '.'; /* restore capfile_name */
212 *fsuffix = g_strdup(pfx);
214 /* Either there's no "." in the pathname, or it's in a directory
215 component, so the last component has no suffix. */
216 *fprefix = g_strdup(save_file);
223 /* Add a selection item, a simple parser for now */
225 add_selection(char *sel)
230 if (++max_selected >= MAX_SELECTIONS) {
231 /* Let the user know we stopped selecting */
232 printf("Out of room for packet selections!\n");
236 printf("Add_Selected: %s\n", sel);
238 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
240 printf("Not inclusive ...");
242 selectfrm[max_selected].inclusive = 0;
243 selectfrm[max_selected].first = atoi(sel);
245 printf(" %i\n", selectfrm[max_selected].first);
250 printf("Inclusive ...");
253 selectfrm[max_selected].inclusive = 1;
254 selectfrm[max_selected].first = atoi(sel);
255 selectfrm[max_selected].second = atoi(next);
257 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
264 /* Was the packet selected? */
271 for (i = 0; i<= max_selected; i++) {
273 if (selectfrm[i].inclusive) {
274 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
278 if (recno == selectfrm[i].first)
287 /* is the packet in the selected timeframe */
289 check_timestamp(wtap *wth)
291 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
293 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs <= stoptime );
297 set_time_adjustment(char *optarg)
306 /* skip leading whitespace */
307 while (*optarg == ' ' || *optarg == '\t') {
311 /* check for a negative adjustment */
312 if (*optarg == '-') {
313 time_adj.is_negative = 1;
317 /* collect whole number of seconds, if any */
318 if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */
322 val = strtol(optarg, &frac, 10);
323 if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
324 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
328 if (val < 0) { /* implies '--' since we caught '-' above */
329 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
334 time_adj.tv.tv_sec = val;
336 /* now collect the partial seconds, if any */
337 if (*frac != '\0') { /* chars left, so get fractional part */
338 val = strtol(&(frac[1]), &end, 10);
339 /* if more than 6 fractional digits truncate to 6 */
340 if((end - &(frac[1])) > 6) {
341 frac[7] = 't'; /* 't' for truncate */
342 val = strtol(&(frac[1]), &end, 10);
344 if (*frac != '.' || end == NULL || end == frac
345 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
346 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
352 return; /* no fractional digits */
355 /* adjust fractional portion from fractional to numerator
356 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
357 if (frac && end) { /* both are valid */
358 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
359 while(frac_digits < 6) { /* this is frac of 10^6 */
364 time_adj.tv.tv_usec = val;
368 set_rel_time(char *optarg)
377 /* skip leading whitespace */
378 while (*optarg == ' ' || *optarg == '\t') {
382 /* ignore negative adjustment */
383 if (*optarg == '-') {
387 /* collect whole number of seconds, if any */
388 if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */
392 val = strtol(optarg, &frac, 10);
393 if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
394 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
398 if (val < 0) { /* implies '--' since we caught '-' above */
399 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
404 relative_time_window.secs = val;
406 /* now collect the partial seconds, if any */
407 if (*frac != '\0') { /* chars left, so get fractional part */
408 val = strtol(&(frac[1]), &end, 10);
409 /* if more than 9 fractional digits truncate to 9 */
410 if((end - &(frac[1])) > 9) {
411 frac[10] = 't'; /* 't' for truncate */
412 val = strtol(&(frac[1]), &end, 10);
414 if (*frac != '.' || end == NULL || end == frac
415 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
416 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
422 return; /* no fractional digits */
425 /* adjust fractional portion from fractional to numerator
426 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
427 if (frac && end) { /* both are valid */
428 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
429 while(frac_digits < 9) { /* this is frac of 10^9 */
434 relative_time_window.nsecs = val;
438 is_duplicate(guint8* fd, guint32 len) {
443 if (cur_dup_entry >= dup_window)
446 /* Calculate our digest */
448 md5_append(&ms, fd, len);
449 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
451 fd_hash[cur_dup_entry].len = len;
453 /* Look for duplicates */
454 for (i = 0; i < dup_window; i++) {
455 if (i == cur_dup_entry)
458 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
459 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
468 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
473 if (cur_dup_entry >= dup_window)
476 /* Calculate our digest */
478 md5_append(&ms, fd, len);
479 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
481 fd_hash[cur_dup_entry].len = len;
482 fd_hash[cur_dup_entry].time.secs = current->secs;
483 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
486 * Look for relative time related duplicates.
487 * This is hopefully a reasonably efficient mechanism for
488 * finding duplicates by rel time in the fd_hash[] cache.
489 * We check starting from the most recently added hash
490 * entries and work backwards towards older packets.
491 * This approach allows the dup test to be terminated
492 * when the relative time of a cached entry is found to
493 * be beyond the dup time window.
495 * Of course this assumes that the input trace file is
496 * "well-formed" in the sense that the packet timestamps are
497 * in strict chronologically increasing order (which is NOT
498 * always the case!!).
500 * The fd_hash[] table was deliberatly created large (1,000,000).
501 * Looking for time related duplicates in large trace files with
502 * non-fractional dup time window values can potentially take
503 * a long time to complete.
506 for (i = cur_dup_entry - 1;; i--) {
514 if (i == cur_dup_entry) {
516 * We've decremented back to where we started.
522 if (nstime_is_unset(&(fd_hash[i].time))) {
524 * We've decremented to an unused fd_hash[] entry.
530 nstime_delta(&delta, current, &fd_hash[i].time);
532 if(delta.secs < 0 || delta.nsecs < 0)
535 * A negative delta implies that the current packet
536 * has an absolute timestamp less than the cached packet
537 * that it is being compared to. This is NOT a normal
538 * situation since trace files usually have packets in
539 * chronological order (oldest to newest).
541 * There are several possible ways to deal with this:
542 * 1. 'continue' dup checking with the next cached frame.
543 * 2. 'break' from looking for a duplicate of the current frame.
544 * 3. Take the absolute value of the delta and see if that
545 * falls within the specifed dup time window.
547 * Currently this code does option 1. But it would pretty
548 * easy to add yet-another-editcap-option to select one of
549 * the other behaviors for dealing with out-of-sequence
555 cmp = nstime_cmp(&delta, &relative_time_window);
559 * The delta time indicates that we are now looking at
560 * cached packets beyond the specified dup time window.
564 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
565 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
574 usage(gboolean is_error)
583 fprintf(output, "Editcap %s"
585 " (" SVNVERSION " from " SVNPATH ")"
588 fprintf(output, "Edit and/or translate the format of capture files.\n");
589 fprintf(output, "See http://www.wireshark.org for more information.\n");
590 fprintf(output, "\n");
591 fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
592 fprintf(output, "\n");
593 fprintf(output, "<infile> and <outfile> must both be present.\n");
594 fprintf(output, "A single packet or a range of packets can be selected.\n");
595 fprintf(output, "\n");
596 fprintf(output, "Packet selection:\n");
597 fprintf(output, " -r keep the selected packets; default is to delete them.\n");
598 fprintf(output, " -A <start time> don't output packets whose timestamp is before the\n");
599 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
600 fprintf(output, " -B <stop time> don't output packets whose timestamp is after the\n");
601 fprintf(output, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
602 fprintf(output, "\n");
603 fprintf(output, "Duplicate packet removal:\n");
604 fprintf(output, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
605 fprintf(output, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
606 fprintf(output, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
607 fprintf(output, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
608 fprintf(output, " useful to print MD5 hashes.\n");
609 fprintf(output, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
610 fprintf(output, " LESS THAN <dup time window> prior to current packet.\n");
611 fprintf(output, " A <dup time window> is specified in relative seconds\n");
612 fprintf(output, " (e.g. 0.000001).\n");
613 fprintf(output, "\n");
614 fprintf(output, " NOTE: The use of the 'Duplicate packet removal' options with\n");
615 fprintf(output, " other editcap options except -v may not always work as expected.\n");
616 fprintf(output, " Specifically the -r and -t options will very likely NOT have the\n");
617 fprintf(output, " desired effect if combined with the -d, -D or -w.\n");
618 fprintf(output, "\n");
619 fprintf(output, "Packet manipulation:\n");
620 fprintf(output, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
621 fprintf(output, " -C <choplen> chop each packet at the end by <choplen> bytes.\n");
622 fprintf(output, " -t <time adjustment> adjust the timestamp of each packet;\n");
623 fprintf(output, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
624 fprintf(output, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
625 fprintf(output, " that a particular packet byte will be randomly changed.\n");
626 fprintf(output, "\n");
627 fprintf(output, "Output File(s):\n");
628 fprintf(output, " -c <packets per file> split the packet output to different files\n");
629 fprintf(output, " based on uniform packet counts\n");
630 fprintf(output, " with a maximum of <packets per file> each.\n");
631 fprintf(output, " -i <seconds per file> split the packet output to different files\n");
632 fprintf(output, " based on uniform time intervals\n");
633 fprintf(output, " with a maximum of <seconds per file> each.\n");
634 fprintf(output, " -F <capture type> set the output file type; default is libpcap.\n");
635 fprintf(output, " an empty \"-F\" option will list the file types.\n");
636 fprintf(output, " -T <encap type> set the output file encapsulation type;\n");
637 fprintf(output, " default is the same as the input file.\n");
638 fprintf(output, " an empty \"-T\" option will list the encapsulation types.\n");
639 fprintf(output, "\n");
640 fprintf(output, "Miscellaneous:\n");
641 fprintf(output, " -h display this help and exit.\n");
642 fprintf(output, " -v verbose output.\n");
643 fprintf(output, " If -v is used with any of the 'Duplicate Packet\n");
644 fprintf(output, " Removal' options (-d, -D or -w) then Packet lengths\n");
645 fprintf(output, " and MD5 hashes are printed to standard-out.\n");
646 fprintf(output, "\n");
650 list_capture_types(void) {
653 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
654 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
655 if (wtap_dump_can_open(i))
656 fprintf(stderr, " %s - %s\n",
657 wtap_file_type_short_string(i), wtap_file_type_string(i));
662 list_encap_types(void) {
666 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
667 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
668 string = wtap_encap_short_string(i);
670 fprintf(stderr, " %s - %s\n",
671 string, wtap_encap_string(i));
677 * Don't report failures to load plugins because most (non-wiretap) plugins
678 * *should* fail to load (because we're not linked against libwireshark and
679 * dissector plugins need libwireshark).
682 failure_message(const char *msg_format _U_, va_list ap _U_)
689 main(int argc, char *argv[])
696 unsigned int snaplen = 0; /* No limit */
697 unsigned int choplen = 0; /* No chop */
698 wtap_dumper *pdh = NULL;
700 unsigned duplicate_count = 0;
702 struct wtap_pkthdr snap_phdr;
703 const struct wtap_pkthdr *phdr;
706 int split_packet_count = 0;
707 int written_count = 0;
708 char *filename = NULL;
710 int secs_per_block = 0;
712 nstime_t block_start;
713 gchar *fprefix = NULL;
714 gchar *fsuffix = NULL;
717 char* init_progfile_dir_error;
721 * Get credential information for later use.
723 get_credential_info();
726 /* Register wiretap plugins */
727 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
728 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
729 g_free(init_progfile_dir_error);
731 init_report_err(failure_message,NULL,NULL,NULL);
736 /* Process the options */
737 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:T:vw:")) !=-1) {
742 err_prob = strtod(optarg, &p);
743 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
744 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
748 srand( (unsigned int) (time(NULL) + getpid()) );
752 out_file_type = wtap_short_string_to_file_type(optarg);
753 if (out_file_type < 0) {
754 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
756 list_capture_types();
762 split_packet_count = strtol(optarg, &p, 10);
763 if (p == optarg || *p != '\0') {
764 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
768 if (split_packet_count <= 0) {
769 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
776 choplen = strtol(optarg, &p, 10);
777 if (p == optarg || *p != '\0') {
778 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
786 dup_detect_by_time = FALSE;
787 dup_window = DEFAULT_DUP_DEPTH;
792 dup_detect_by_time = FALSE;
793 dup_window = strtol(optarg, &p, 10);
794 if (p == optarg || *p != '\0') {
795 fprintf(stderr, "editcap: \"%s\" isn't a valid dupicate window value\n",
799 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
800 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
801 dup_window, MAX_DUP_DEPTH);
808 dup_detect_by_time = TRUE;
809 dup_window = MAX_DUP_DEPTH;
810 set_rel_time(optarg);
813 case '?': /* Bad options if GNU getopt */
816 list_capture_types();
833 keep_em = !keep_em; /* Just invert */
837 snaplen = strtol(optarg, &p, 10);
838 if (p == optarg || *p != '\0') {
839 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
846 set_time_adjustment(optarg);
850 out_frame_type = wtap_short_string_to_encap(optarg);
851 if (out_frame_type < 0) {
852 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
860 verbose = !verbose; /* Just invert */
863 case 'i': /* break capture file based on time interval */
864 secs_per_block = atoi(optarg);
865 if(secs_per_block <= 0) {
866 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
875 memset(&starttm,0,sizeof(struct tm));
877 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
878 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
882 check_startstop = TRUE;
883 starttm.tm_isdst = -1;
885 starttime = mktime(&starttm);
893 memset(&stoptm,0,sizeof(struct tm));
895 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
896 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
899 check_startstop = TRUE;
900 stoptm.tm_isdst = -1;
901 stoptime = mktime(&stoptm);
909 printf("Optind = %i, argc = %i\n", optind, argc);
912 if ((argc - optind) < 1) {
919 if (check_startstop && !stoptime) {
921 /* XXX: will work until 2035 */
922 memset(&stoptm,0,sizeof(struct tm));
923 stoptm.tm_year = 135;
927 stoptime = mktime(&stoptm);
930 nstime_set_unset(&block_start);
932 if (starttime > stoptime) {
933 fprintf(stderr, "editcap: start time is after the stop time\n");
937 if (split_packet_count > 0 && secs_per_block > 0) {
938 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
939 fprintf(stderr, "editcap: at the same time\n");
943 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
946 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
950 case WTAP_ERR_UNSUPPORTED:
951 case WTAP_ERR_UNSUPPORTED_ENCAP:
952 case WTAP_ERR_BAD_RECORD:
953 fprintf(stderr, "(%s)\n", err_info);
962 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
963 wtap_file_type_string(wtap_file_type(wth)));
967 * Now, process the rest, if any ... we only write if there is an extra
971 if ((argc - optind) >= 2) {
973 if (out_frame_type == -2)
974 out_frame_type = wtap_file_encap(wth);
976 for (i = optind + 2; i < argc; i++)
977 if (add_selection(argv[i]) == FALSE)
980 if (dup_detect || dup_detect_by_time) {
981 for (i = 0; i < dup_window; i++) {
982 memset(&fd_hash[i].digest, 0, 16);
984 nstime_set_unset(&fd_hash[i].time);
988 while (wtap_read(wth, &err, &err_info, &data_offset)) {
989 phdr = wtap_phdr(wth);
991 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
992 block_start.secs = phdr->ts.secs;
993 block_start.nsecs = phdr->ts.nsecs;
995 if (split_packet_count > 0 || secs_per_block > 0) {
996 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
999 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1001 filename = g_strdup(argv[optind+1]);
1003 pdh = wtap_dump_open(filename, out_file_type,
1004 out_frame_type, wtap_snapshot_length(wth),
1005 FALSE /* compressed */, &err);
1007 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1008 wtap_strerror(err));
1015 if (secs_per_block > 0) {
1016 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1017 (phdr->ts.secs - block_start.secs == secs_per_block &&
1018 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1020 if (!wtap_dump_close(pdh, &err)) {
1021 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1022 wtap_strerror(err));
1025 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1027 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1031 fprintf(stderr, "Continuing writing in file %s\n", filename);
1034 pdh = wtap_dump_open(filename, out_file_type,
1035 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1038 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1039 wtap_strerror(err));
1045 if (split_packet_count > 0) {
1047 /* time for the next file? */
1048 if (written_count > 0 &&
1049 written_count % split_packet_count == 0) {
1050 if (!wtap_dump_close(pdh, &err)) {
1051 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1052 wtap_strerror(err));
1057 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1061 fprintf(stderr, "Continuing writing in file %s\n", filename);
1064 pdh = wtap_dump_open(filename, out_file_type,
1065 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1067 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1068 wtap_strerror(err));
1074 check_ts = check_timestamp(wth);
1076 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1077 (selected(count) && keep_em)) ) {
1079 if (verbose && !dup_detect && !dup_detect_by_time)
1080 printf("Packet: %u\n", count);
1082 /* We simply write it, perhaps after truncating it; we could do other
1083 things, like modify it. */
1085 phdr = wtap_phdr(wth);
1087 if (choplen != 0 && phdr->caplen > choplen) {
1089 snap_phdr.caplen -= choplen;
1093 if (snaplen != 0 && phdr->caplen > snaplen) {
1095 snap_phdr.caplen = snaplen;
1099 /* assume that if the frame's tv_sec is 0, then
1100 * the timestamp isn't supported */
1101 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1103 if (time_adj.is_negative)
1104 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1106 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1110 /* assume that if the frame's tv_sec is 0, then
1111 * the timestamp isn't supported */
1112 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1114 if (time_adj.is_negative) { /* subtract */
1115 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1116 snap_phdr.ts.secs--;
1117 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1119 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1121 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1123 snap_phdr.ts.secs++;
1124 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1126 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1132 /* suppress duplicates by packet window */
1134 buf = wtap_buf_ptr(wth);
1135 if (is_duplicate(buf, phdr->caplen)) {
1137 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1138 for (i = 0; i < 16; i++) {
1139 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1141 fprintf(stdout, "\n");
1148 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1149 for (i = 0; i < 16; i++) {
1150 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1152 fprintf(stdout, "\n");
1157 /* suppress duplicates by time window */
1158 if (dup_detect_by_time) {
1161 current.secs = phdr->ts.secs;
1162 current.nsecs = phdr->ts.nsecs;
1164 buf = wtap_buf_ptr(wth);
1166 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1168 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1169 for (i = 0; i < 16; i++) {
1170 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1172 fprintf(stdout, "\n");
1179 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1180 for (i = 0; i < 16; i++) {
1181 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1183 fprintf(stdout, "\n");
1188 /* Random error mutation */
1189 if (err_prob > 0.0) {
1190 int real_data_start = 0;
1191 buf = wtap_buf_ptr(wth);
1192 /* Protect non-protocol data */
1193 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1194 real_data_start = find_dct2000_real_data(buf);
1196 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1197 if (rand() <= err_prob * RAND_MAX) {
1198 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1200 if (err_type < ERR_WT_BIT) {
1201 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1202 err_type = ERR_WT_TOTAL;
1204 err_type -= ERR_WT_BYTE;
1207 if (err_type < ERR_WT_BYTE) {
1208 buf[i] = rand() / (RAND_MAX / 255 + 1);
1209 err_type = ERR_WT_TOTAL;
1211 err_type -= ERR_WT_BYTE;
1214 if (err_type < ERR_WT_ALNUM) {
1215 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1216 err_type = ERR_WT_TOTAL;
1218 err_type -= ERR_WT_ALNUM;
1221 if (err_type < ERR_WT_FMT) {
1222 if ((unsigned int)i < phdr->caplen - 2)
1223 strncpy((char*) &buf[i], "%s", 2);
1224 err_type = ERR_WT_TOTAL;
1226 err_type -= ERR_WT_FMT;
1229 if (err_type < ERR_WT_AA) {
1230 for (j = i; j < (int) phdr->caplen; j++) {
1239 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
1241 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1242 filename, wtap_strerror(err));
1254 /* Print a message noting that the read failed somewhere along the line. */
1256 "editcap: An error occurred while reading \"%s\": %s.\n",
1257 argv[optind], wtap_strerror(err));
1260 case WTAP_ERR_UNSUPPORTED:
1261 case WTAP_ERR_UNSUPPORTED_ENCAP:
1262 case WTAP_ERR_BAD_RECORD:
1263 fprintf(stderr, "(%s)\n", err_info);
1270 /* No valid packages found, open the outfile so we can write an empty header */
1272 filename = g_strdup(argv[optind+1]);
1274 pdh = wtap_dump_open(filename, out_file_type,
1275 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1277 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1278 wtap_strerror(err));
1283 if (!wtap_dump_close(pdh, &err)) {
1285 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1286 wtap_strerror(err));
1294 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1295 count - 1, plurality(count - 1, "", "s"),
1296 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1297 } else if (dup_detect_by_time) {
1298 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1299 count - 1, plurality(count - 1, "", "s"),
1300 duplicate_count, plurality(duplicate_count, "", "s"),
1301 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1307 /* Skip meta-information read from file to return offset of real
1309 static int find_dct2000_real_data(guint8 *buf)
1313 for (n=0; buf[n] != '\0'; n++); /* Context name */
1315 n++; /* Context port number */
1316 for (; buf[n] != '\0'; n++); /* Timestamp */
1318 for (; buf[n] != '\0'; n++); /* Protocol name */
1320 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1322 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1324 n += 2; /* Direction & encap */