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) {
576 fprintf(stderr, "Editcap %s"
578 " (" SVNVERSION " from " SVNPATH ")"
581 fprintf(stderr, "Edit and/or translate the format of capture files.\n");
582 fprintf(stderr, "See http://www.wireshark.org for more information.\n");
583 fprintf(stderr, "\n");
584 fprintf(stderr, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
585 fprintf(stderr, "\n");
586 fprintf(stderr, "<infile> and <outfile> must both be present.\n");
587 fprintf(stderr, "A single packet or a range of packets can be selected.\n");
588 fprintf(stderr, "\n");
589 fprintf(stderr, "Packet selection:\n");
590 fprintf(stderr, " -r keep the selected packets; default is to delete them.\n");
591 fprintf(stderr, " -A <start time> don't output packets whose timestamp is before the\n");
592 fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
593 fprintf(stderr, " -B <stop time> don't output packets whose timestamp is after the\n");
594 fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
595 fprintf(stderr, "\n");
596 fprintf(stderr, "Duplicate packet removal:\n");
597 fprintf(stderr, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
598 fprintf(stderr, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
599 fprintf(stderr, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
600 fprintf(stderr, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
601 fprintf(stderr, " useful to print MD5 hashes.\n");
602 fprintf(stderr, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
603 fprintf(stderr, " LESS THAN <dup time window> prior to current packet.\n");
604 fprintf(stderr, " A <dup time window> is specified in relative seconds\n");
605 fprintf(stderr, " (e.g. 0.000001).\n");
606 fprintf(stderr, "\n");
607 fprintf(stderr, " NOTE: The use of the 'Duplicate packet removal' options with\n");
608 fprintf(stderr, " other editcap options except -v may not always work as expected.\n");
609 fprintf(stderr, " Specifically the -r and -t options will very likely NOT have the\n");
610 fprintf(stderr, " desired effect if combined with the -d, -D or -w.\n");
611 fprintf(stderr, "\n");
612 fprintf(stderr, "Packet manipulation:\n");
613 fprintf(stderr, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
614 fprintf(stderr, " -C <choplen> chop each packet at the end by <choplen> bytes.\n");
615 fprintf(stderr, " -t <time adjustment> adjust the timestamp of each packet;\n");
616 fprintf(stderr, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
617 fprintf(stderr, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
618 fprintf(stderr, " that a particular packet byte will be randomly changed.\n");
619 fprintf(stderr, "\n");
620 fprintf(stderr, "Output File(s):\n");
621 fprintf(stderr, " -c <packets per file> split the packet output to different files\n");
622 fprintf(stderr, " based on uniform packet counts\n");
623 fprintf(stderr, " with a maximum of <packets per file> each.\n");
624 fprintf(stderr, " -i <seconds per file> split the packet output to different files\n");
625 fprintf(stderr, " based on uniform time intervals\n");
626 fprintf(stderr, " with a maximum of <seconds per file> each.\n");
627 fprintf(stderr, " -F <capture type> set the output file type; default is libpcap.\n");
628 fprintf(stderr, " an empty \"-F\" option will list the file types.\n");
629 fprintf(stderr, " -T <encap type> set the output file encapsulation type;\n");
630 fprintf(stderr, " default is the same as the input file.\n");
631 fprintf(stderr, " an empty \"-T\" option will list the encapsulation types.\n");
632 fprintf(stderr, "\n");
633 fprintf(stderr, "Miscellaneous:\n");
634 fprintf(stderr, " -h display this help and exit.\n");
635 fprintf(stderr, " -v verbose output.\n");
636 fprintf(stderr, " If -v is used with any of the 'Duplicate Packet\n");
637 fprintf(stderr, " Removal' options (-d, -D or -w) then Packet lengths\n");
638 fprintf(stderr, " and MD5 hashes are printed to standard-out.\n");
639 fprintf(stderr, "\n");
643 list_capture_types(void) {
646 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
647 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
648 if (wtap_dump_can_open(i))
649 fprintf(stderr, " %s - %s\n",
650 wtap_file_type_short_string(i), wtap_file_type_string(i));
655 list_encap_types(void) {
659 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
660 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
661 string = wtap_encap_short_string(i);
663 fprintf(stderr, " %s - %s\n",
664 string, wtap_encap_string(i));
670 * Don't report failures to load plugins because most (non-wiretap) plugins
671 * *should* fail to load (because we're not linked against libwireshark and
672 * dissector plugins need libwireshark).
675 failure_message(const char *msg_format _U_, va_list ap _U_)
682 main(int argc, char *argv[])
689 unsigned int snaplen = 0; /* No limit */
690 unsigned int choplen = 0; /* No chop */
691 wtap_dumper *pdh = NULL;
693 unsigned duplicate_count = 0;
695 struct wtap_pkthdr snap_phdr;
696 const struct wtap_pkthdr *phdr;
699 int split_packet_count = 0;
700 int written_count = 0;
701 char *filename = NULL;
703 int secs_per_block = 0;
705 nstime_t block_start;
706 gchar *fprefix = NULL;
707 gchar *fsuffix = NULL;
710 char* init_progfile_dir_error;
714 * Get credential information for later use.
716 get_credential_info();
719 /* Register wiretap plugins */
720 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
721 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
722 g_free(init_progfile_dir_error);
724 init_report_err(failure_message,NULL,NULL,NULL);
729 /* Process the options */
730 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:T:vw:")) !=-1) {
735 err_prob = strtod(optarg, &p);
736 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
737 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
741 srand( (unsigned int) (time(NULL) + getpid()) );
745 out_file_type = wtap_short_string_to_file_type(optarg);
746 if (out_file_type < 0) {
747 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
749 list_capture_types();
755 split_packet_count = strtol(optarg, &p, 10);
756 if (p == optarg || *p != '\0') {
757 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
761 if (split_packet_count <= 0) {
762 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
769 choplen = strtol(optarg, &p, 10);
770 if (p == optarg || *p != '\0') {
771 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
779 dup_detect_by_time = FALSE;
780 dup_window = DEFAULT_DUP_DEPTH;
785 dup_detect_by_time = FALSE;
786 dup_window = strtol(optarg, &p, 10);
787 if (p == optarg || *p != '\0') {
788 fprintf(stderr, "editcap: \"%s\" isn't a valid dupicate window value\n",
792 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
793 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
794 dup_window, MAX_DUP_DEPTH);
801 dup_detect_by_time = TRUE;
802 dup_window = MAX_DUP_DEPTH;
803 set_rel_time(optarg);
806 case '?': /* Bad options if GNU getopt */
809 list_capture_types();
826 keep_em = !keep_em; /* Just invert */
830 snaplen = strtol(optarg, &p, 10);
831 if (p == optarg || *p != '\0') {
832 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
839 set_time_adjustment(optarg);
843 out_frame_type = wtap_short_string_to_encap(optarg);
844 if (out_frame_type < 0) {
845 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
853 verbose = !verbose; /* Just invert */
856 case 'i': /* break capture file based on time interval */
857 secs_per_block = atoi(optarg);
858 if(secs_per_block <= 0) {
859 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
868 memset(&starttm,0,sizeof(struct tm));
870 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
871 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
875 check_startstop = TRUE;
876 starttm.tm_isdst = -1;
878 starttime = mktime(&starttm);
886 memset(&stoptm,0,sizeof(struct tm));
888 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
889 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
892 check_startstop = TRUE;
893 stoptm.tm_isdst = -1;
894 stoptime = mktime(&stoptm);
902 printf("Optind = %i, argc = %i\n", optind, argc);
905 if ((argc - optind) < 1) {
912 if (check_startstop && !stoptime) {
914 /* XXX: will work until 2035 */
915 memset(&stoptm,0,sizeof(struct tm));
916 stoptm.tm_year = 135;
920 stoptime = mktime(&stoptm);
923 nstime_set_unset(&block_start);
925 if (starttime > stoptime) {
926 fprintf(stderr, "editcap: start time is after the stop time\n");
930 if (split_packet_count > 0 && secs_per_block > 0) {
931 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
932 fprintf(stderr, "editcap: at the same time\n");
936 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
939 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
943 case WTAP_ERR_UNSUPPORTED:
944 case WTAP_ERR_UNSUPPORTED_ENCAP:
945 case WTAP_ERR_BAD_RECORD:
946 fprintf(stderr, "(%s)\n", err_info);
955 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
956 wtap_file_type_string(wtap_file_type(wth)));
960 * Now, process the rest, if any ... we only write if there is an extra
964 if ((argc - optind) >= 2) {
966 if (out_frame_type == -2)
967 out_frame_type = wtap_file_encap(wth);
969 for (i = optind + 2; i < argc; i++)
970 if (add_selection(argv[i]) == FALSE)
973 if (dup_detect || dup_detect_by_time) {
974 for (i = 0; i < dup_window; i++) {
975 memset(&fd_hash[i].digest, 0, 16);
977 nstime_set_unset(&fd_hash[i].time);
981 while (wtap_read(wth, &err, &err_info, &data_offset)) {
982 phdr = wtap_phdr(wth);
984 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
985 block_start.secs = phdr->ts.secs;
986 block_start.nsecs = phdr->ts.nsecs;
988 if (split_packet_count > 0 || secs_per_block > 0) {
989 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
992 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
994 filename = g_strdup(argv[optind+1]);
996 pdh = wtap_dump_open(filename, out_file_type,
997 out_frame_type, wtap_snapshot_length(wth),
998 FALSE /* compressed */, &err);
1000 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1001 wtap_strerror(err));
1008 if (secs_per_block > 0) {
1009 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1010 (phdr->ts.secs - block_start.secs == secs_per_block &&
1011 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1013 if (!wtap_dump_close(pdh, &err)) {
1014 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1015 wtap_strerror(err));
1018 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1020 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1024 fprintf(stderr, "Continuing writing in file %s\n", filename);
1027 pdh = wtap_dump_open(filename, out_file_type,
1028 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1031 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1032 wtap_strerror(err));
1038 if (split_packet_count > 0) {
1040 /* time for the next file? */
1041 if (written_count > 0 &&
1042 written_count % split_packet_count == 0) {
1043 if (!wtap_dump_close(pdh, &err)) {
1044 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1045 wtap_strerror(err));
1050 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1054 fprintf(stderr, "Continuing writing in file %s\n", filename);
1057 pdh = wtap_dump_open(filename, out_file_type,
1058 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1060 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1061 wtap_strerror(err));
1067 check_ts = check_timestamp(wth);
1069 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1070 (selected(count) && keep_em)) ) {
1072 if (verbose && !dup_detect && !dup_detect_by_time)
1073 printf("Packet: %u\n", count);
1075 /* We simply write it, perhaps after truncating it; we could do other
1076 things, like modify it. */
1078 phdr = wtap_phdr(wth);
1080 if (choplen != 0 && phdr->caplen > choplen) {
1082 snap_phdr.caplen -= choplen;
1086 if (snaplen != 0 && phdr->caplen > snaplen) {
1088 snap_phdr.caplen = snaplen;
1092 /* assume that if the frame's tv_sec is 0, then
1093 * the timestamp isn't supported */
1094 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1096 if (time_adj.is_negative)
1097 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1099 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1103 /* assume that if the frame's tv_sec is 0, then
1104 * the timestamp isn't supported */
1105 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1107 if (time_adj.is_negative) { /* subtract */
1108 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1109 snap_phdr.ts.secs--;
1110 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1112 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1114 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1116 snap_phdr.ts.secs++;
1117 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1119 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1125 /* suppress duplicates by packet window */
1127 buf = wtap_buf_ptr(wth);
1128 if (is_duplicate(buf, phdr->caplen)) {
1130 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1131 for (i = 0; i < 16; i++) {
1132 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1134 fprintf(stdout, "\n");
1141 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1142 for (i = 0; i < 16; i++) {
1143 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1145 fprintf(stdout, "\n");
1150 /* suppress duplicates by time window */
1151 if (dup_detect_by_time) {
1154 current.secs = phdr->ts.secs;
1155 current.nsecs = phdr->ts.nsecs;
1157 buf = wtap_buf_ptr(wth);
1159 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1161 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1162 for (i = 0; i < 16; i++) {
1163 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1165 fprintf(stdout, "\n");
1172 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1173 for (i = 0; i < 16; i++) {
1174 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1176 fprintf(stdout, "\n");
1181 /* Random error mutation */
1182 if (err_prob > 0.0) {
1183 int real_data_start = 0;
1184 buf = wtap_buf_ptr(wth);
1185 /* Protect non-protocol data */
1186 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1187 real_data_start = find_dct2000_real_data(buf);
1189 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1190 if (rand() <= err_prob * RAND_MAX) {
1191 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1193 if (err_type < ERR_WT_BIT) {
1194 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1195 err_type = ERR_WT_TOTAL;
1197 err_type -= ERR_WT_BYTE;
1200 if (err_type < ERR_WT_BYTE) {
1201 buf[i] = rand() / (RAND_MAX / 255 + 1);
1202 err_type = ERR_WT_TOTAL;
1204 err_type -= ERR_WT_BYTE;
1207 if (err_type < ERR_WT_ALNUM) {
1208 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1209 err_type = ERR_WT_TOTAL;
1211 err_type -= ERR_WT_ALNUM;
1214 if (err_type < ERR_WT_FMT) {
1215 if ((unsigned int)i < phdr->caplen - 2)
1216 strncpy((char*) &buf[i], "%s", 2);
1217 err_type = ERR_WT_TOTAL;
1219 err_type -= ERR_WT_FMT;
1222 if (err_type < ERR_WT_AA) {
1223 for (j = i; j < (int) phdr->caplen; j++) {
1232 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
1234 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1235 filename, wtap_strerror(err));
1247 /* Print a message noting that the read failed somewhere along the line. */
1249 "editcap: An error occurred while reading \"%s\": %s.\n",
1250 argv[optind], wtap_strerror(err));
1253 case WTAP_ERR_UNSUPPORTED:
1254 case WTAP_ERR_UNSUPPORTED_ENCAP:
1255 case WTAP_ERR_BAD_RECORD:
1256 fprintf(stderr, "(%s)\n", err_info);
1263 /* No valid packages found, open the outfile so we can write an empty header */
1265 filename = g_strdup(argv[optind+1]);
1267 pdh = wtap_dump_open(filename, out_file_type,
1268 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1270 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1271 wtap_strerror(err));
1276 if (!wtap_dump_close(pdh, &err)) {
1278 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1279 wtap_strerror(err));
1287 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1288 count - 1, plurality(count - 1, "", "s"),
1289 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1290 } else if (dup_detect_by_time) {
1291 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1292 count - 1, plurality(count - 1, "", "s"),
1293 duplicate_count, plurality(duplicate_count, "", "s"),
1294 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1300 /* Skip meta-information read from file to return offset of real
1302 static int find_dct2000_real_data(guint8 *buf)
1306 for (n=0; buf[n] != '\0'; n++); /* Context name */
1308 n++; /* Context port number */
1309 for (; buf[n] != '\0'; n++); /* Timestamp */
1311 for (; buf[n] != '\0'; n++); /* Protocol name */
1313 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1315 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1317 n += 2; /* Direction & encap */