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
50 #include <process.h> /* getpid */
51 #ifdef HAVE_WINSOCK2_H
56 #ifdef NEED_STRPTIME_H
57 # include "strptime.h"
60 #include "epan/crypt/crypt-md5.h"
61 #include "epan/plugins.h"
62 #include "epan/report_err.h"
63 #include "epan/filesystem.h"
64 #include <wsutil/privileges.h>
65 #include "epan/nstime.h"
67 #include "svnversion.h"
70 * Some globals so we can pass things to various routines
82 * Duplicate frame detection
84 typedef struct _fd_hash_t {
85 md5_byte_t digest[16];
90 #define DEFAULT_DUP_DEPTH 5 /* Used with -d */
91 #define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */
93 fd_hash_t fd_hash[MAX_DUP_DEPTH];
94 int dup_window = DEFAULT_DUP_DEPTH;
95 int cur_dup_entry = 0;
97 #define ONE_MILLION 1000000
98 #define ONE_BILLION 1000000000
100 /* Weights of different errors we can introduce */
101 /* We should probably make these command-line arguments */
102 /* XXX - Should we add a bit-level error? */
103 #define ERR_WT_BIT 5 /* Flip a random bit */
104 #define ERR_WT_BYTE 5 /* Substitute a random byte */
105 #define ERR_WT_ALNUM 5 /* Substitute a random character in [A-Za-z0-9] */
106 #define ERR_WT_FMT 2 /* Substitute "%s" */
107 #define ERR_WT_AA 1 /* Fill the remainder of the buffer with 0xAA */
108 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
110 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
111 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
114 struct time_adjustment {
119 #define MAX_SELECTIONS 512
120 static struct select_item selectfrm[MAX_SELECTIONS];
121 static int max_selected = -1;
122 static int keep_em = 0;
123 static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */
124 static int out_frame_type = -2; /* Leave frame type alone */
125 static int verbose = 0; /* Not so verbose */
126 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
127 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
128 static double err_prob = 0.0;
129 static time_t starttime = 0;
130 static time_t stoptime = 0;
131 static gboolean check_startstop = FALSE;
132 static gboolean dup_detect = FALSE;
133 static gboolean dup_detect_by_time = FALSE;
135 static int find_dct2000_real_data(guint8 *buf);
138 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
141 gchar *buf = g_malloc(16);
144 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
145 /* XXX - find the exact value that still does work */
146 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
147 if(abs_time->secs > 2000000000) {
151 tmp = localtime(&abs_time->secs);
153 g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
167 fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time,
168 gchar *fprefix, gchar *fsuffix)
174 timestr = abs_time_to_str_with_sec_resolution(time);
175 g_snprintf(filenum, sizeof(filenum), "%05u", idx);
176 abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
183 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
185 char *pfx, *last_pathsep;
188 save_file = g_strdup(fname);
189 if (save_file == NULL) {
190 fprintf(stderr, "editcap: Out of memory\n");
194 last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
195 pfx = strrchr(save_file,'.');
196 if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
197 /* The pathname has a "." in it, and it's in the last component
198 of the pathname (because there is either only one component,
199 i.e. last_pathsep is null as there are no path separators,
200 or the "." is after the path separator before the last
203 Treat it as a separator between the rest of the file name and
204 the file name suffix, and arrange that the names given to the
205 ring buffer files have the specified suffix, i.e. put the
206 changing part of the name *before* the suffix. */
208 *fprefix = g_strdup(save_file);
209 pfx[0] = '.'; /* restore capfile_name */
210 *fsuffix = g_strdup(pfx);
212 /* Either there's no "." in the pathname, or it's in a directory
213 component, so the last component has no suffix. */
214 *fprefix = g_strdup(save_file);
221 /* Add a selection item, a simple parser for now */
223 add_selection(char *sel)
228 if (++max_selected >= MAX_SELECTIONS) {
229 /* Let the user know we stopped selecting */
230 printf("Out of room for packet selections!\n");
234 printf("Add_Selected: %s\n", sel);
236 if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
238 printf("Not inclusive ...");
240 selectfrm[max_selected].inclusive = 0;
241 selectfrm[max_selected].first = atoi(sel);
243 printf(" %i\n", selectfrm[max_selected].first);
248 printf("Inclusive ...");
251 selectfrm[max_selected].inclusive = 1;
252 selectfrm[max_selected].first = atoi(sel);
253 selectfrm[max_selected].second = atoi(next);
255 printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
262 /* Was the packet selected? */
269 for (i = 0; i<= max_selected; i++) {
271 if (selectfrm[i].inclusive) {
272 if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
276 if (recno == selectfrm[i].first)
285 /* is the packet in the selected timeframe */
287 check_timestamp(wtap *wth)
289 struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
291 return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs <= stoptime );
295 set_time_adjustment(char *optarg)
304 /* skip leading whitespace */
305 while (*optarg == ' ' || *optarg == '\t') {
309 /* check for a negative adjustment */
310 if (*optarg == '-') {
311 time_adj.is_negative = 1;
315 /* collect whole number of seconds, if any */
316 if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */
320 val = strtol(optarg, &frac, 10);
321 if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
322 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
326 if (val < 0) { /* implies '--' since we caught '-' above */
327 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
332 time_adj.tv.tv_sec = val;
334 /* now collect the partial seconds, if any */
335 if (*frac != '\0') { /* chars left, so get fractional part */
336 val = strtol(&(frac[1]), &end, 10);
337 if (*frac != '.' || end == NULL || end == frac
338 || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
339 fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
345 return; /* no fractional digits */
348 /* adjust fractional portion from fractional to numerator
349 * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
350 if (frac && end) { /* both are valid */
351 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
352 while(frac_digits < 6) { /* this is frac of 10^6 */
357 time_adj.tv.tv_usec = val;
361 set_rel_time(char *optarg)
370 /* skip leading whitespace */
371 while (*optarg == ' ' || *optarg == '\t') {
375 /* ignore negative adjustment */
376 if (*optarg == '-') {
380 /* collect whole number of seconds, if any */
381 if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */
385 val = strtol(optarg, &frac, 10);
386 if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
387 fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
391 if (val < 0) { /* implies '--' since we caught '-' above */
392 fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
397 relative_time_window.secs = val;
399 /* now collect the partial seconds, if any */
400 if (*frac != '\0') { /* chars left, so get fractional part */
401 val = strtol(&(frac[1]), &end, 10);
402 if (*frac != '.' || end == NULL || end == frac
403 || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
404 fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
410 return; /* no fractional digits */
413 /* adjust fractional portion from fractional to numerator
414 * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
415 if (frac && end) { /* both are valid */
416 frac_digits = end - frac - 1; /* fractional digit count (remember '.') */
417 while(frac_digits < 9) { /* this is frac of 10^9 */
422 relative_time_window.nsecs = val;
426 is_duplicate(guint8* fd, guint32 len) {
431 if (cur_dup_entry >= dup_window)
434 /* Calculate our digest */
436 md5_append(&ms, fd, len);
437 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
439 fd_hash[cur_dup_entry].len = len;
441 /* Look for duplicates */
442 for (i = 0; i < dup_window; i++) {
443 if (i == cur_dup_entry)
446 if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
447 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
456 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
461 if (cur_dup_entry >= dup_window)
464 /* Calculate our digest */
466 md5_append(&ms, fd, len);
467 md5_finish(&ms, fd_hash[cur_dup_entry].digest);
469 fd_hash[cur_dup_entry].len = len;
470 fd_hash[cur_dup_entry].time.secs = current->secs;
471 fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
474 * Look for relative time related duplicates.
475 * This is hopefully a reasonably efficient mechanism for
476 * finding duplicates by rel time in the fd_hash[] cache.
477 * We check starting from the most recently added hash
478 * entries and work backwards towards older packets.
479 * This approach allows the dup test to be terminated
480 * when the relative time of a cached entry is found to
481 * be beyond the dup time window.
483 * Of course this assumes that the input trace file is
484 * "well-formed" in the sense that the packet timestamps are
485 * in strict chronologically increasing order (which is NOT
486 * always the case!!).
488 * The fd_hash[] table was deliberatly created large (1,000,000).
489 * Looking for time related duplicates in large trace files with
490 * non-fractional dup time window values can potentially take
491 * a long time to complete.
494 for (i = cur_dup_entry - 1;; i--) {
502 if (i == cur_dup_entry) {
504 * We've decremented back to where we started.
510 if (nstime_is_unset(&(fd_hash[i].time))) {
512 * We've decremented to an unused fd_hash[] entry.
518 nstime_delta(&delta, current, &fd_hash[i].time);
520 if(delta.secs < 0 || delta.nsecs < 0)
523 * A negative delta implies that the current packet
524 * has an absolute timestamp less than the cached packet
525 * that it is being compared to. This is NOT a normal
526 * situation since trace files usually have packets in
527 * chronological order (oldest to newest).
529 * There are several possible ways to deal with this:
530 * 1. 'continue' dup checking with the next cached frame.
531 * 2. 'break' from looking for a duplicate of the current frame.
532 * 3. Take the absolute value of the delta and see if that
533 * falls within the specifed dup time window.
535 * Currently this code does option 1. But it would pretty
536 * easy to add yet-another-editcap-option to select one of
537 * the other behaviors for dealing with out-of-sequence
543 cmp = nstime_cmp(&delta, &relative_time_window);
547 * The delta time indicates that we are now looking at
548 * cached packets beyond the specified dup time window.
552 } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
553 memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
564 fprintf(stderr, "Editcap %s"
566 " (" SVNVERSION " from " SVNPATH ")"
569 fprintf(stderr, "Edit and/or translate the format of capture files.\n");
570 fprintf(stderr, "See http://www.wireshark.org for more information.\n");
571 fprintf(stderr, "\n");
572 fprintf(stderr, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
573 fprintf(stderr, "\n");
574 fprintf(stderr, "<infile> and <outfile> must both be present.\n");
575 fprintf(stderr, "A single packet or a range of packets can be selected.\n");
576 fprintf(stderr, "\n");
577 fprintf(stderr, "Packet selection:\n");
578 fprintf(stderr, " -r keep the selected packets; default is to delete them.\n");
579 fprintf(stderr, " -A <start time> don't output packets whose timestamp is before the\n");
580 fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
581 fprintf(stderr, " -B <stop time> don't output packets whose timestamp is after the\n");
582 fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss).\n");
583 fprintf(stderr, "\n");
584 fprintf(stderr, "Duplicate packet removal:\n");
585 fprintf(stderr, " -d remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
586 fprintf(stderr, " -D <dup window> remove packet if duplicate; configurable <dup window>\n");
587 fprintf(stderr, " Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
588 fprintf(stderr, " NOTE: A <dup window> of 0 with -v (verbose option) is\n");
589 fprintf(stderr, " useful to print MD5 hashes.\n");
590 fprintf(stderr, " -w <dup time window> remove packet if duplicate packet is found EQUAL TO OR\n");
591 fprintf(stderr, " LESS THAN <dup time window> prior to current packet.\n");
592 fprintf(stderr, " A <dup time window> is specified in relative seconds\n");
593 fprintf(stderr, " (e.g. 0.000001).\n");
594 fprintf(stderr, "\n");
595 fprintf(stderr, " NOTE: The use of the 'Duplicate packet removal' options with\n");
596 fprintf(stderr, " other editcap options except -v may not always work as expected.\n");
597 fprintf(stderr, " Specifically the -r and -t options will very likely NOT have the\n");
598 fprintf(stderr, " desired effect if combined with the -d, -D or -w.\n");
599 fprintf(stderr, "\n");
600 fprintf(stderr, "Packet manipulation:\n");
601 fprintf(stderr, " -s <snaplen> truncate each packet to max. <snaplen> bytes of data.\n");
602 fprintf(stderr, " -C <choplen> chop each packet at the end by <choplen> bytes.\n");
603 fprintf(stderr, " -t <time adjustment> adjust the timestamp of each packet;\n");
604 fprintf(stderr, " <time adjustment> is in relative seconds (e.g. -0.5).\n");
605 fprintf(stderr, " -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
606 fprintf(stderr, " that a particular packet byte will be randomly changed.\n");
607 fprintf(stderr, "\n");
608 fprintf(stderr, "Output File(s):\n");
609 fprintf(stderr, " -c <packets per file> split the packet output to different files\n");
610 fprintf(stderr, " based on uniform packet counts\n");
611 fprintf(stderr, " with a maximum of <packets per file> each.\n");
612 fprintf(stderr, " -i <seconds per file> split the packet output to different files\n");
613 fprintf(stderr, " based on uniform time intervals\n");
614 fprintf(stderr, " with a maximum of <seconds per file> each.\n");
615 fprintf(stderr, " -F <capture type> set the output file type; default is libpcap.\n");
616 fprintf(stderr, " an empty \"-F\" option will list the file types.\n");
617 fprintf(stderr, " -T <encap type> set the output file encapsulation type;\n");
618 fprintf(stderr, " default is the same as the input file.\n");
619 fprintf(stderr, " an empty \"-T\" option will list the encapsulation types.\n");
620 fprintf(stderr, "\n");
621 fprintf(stderr, "Miscellaneous:\n");
622 fprintf(stderr, " -h display this help and exit.\n");
623 fprintf(stderr, " -v verbose output.\n");
624 fprintf(stderr, " If -v is used with any of the 'Duplicate Packet\n");
625 fprintf(stderr, " Removal' options (-d, -D or -w) then Packet lengths\n");
626 fprintf(stderr, " and MD5 hashes are printed to standard-out.\n");
627 fprintf(stderr, "\n");
631 list_capture_types(void) {
634 fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
635 for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
636 if (wtap_dump_can_open(i))
637 fprintf(stderr, " %s - %s\n",
638 wtap_file_type_short_string(i), wtap_file_type_string(i));
643 list_encap_types(void) {
647 fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
648 for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
649 string = wtap_encap_short_string(i);
651 fprintf(stderr, " %s - %s\n",
652 string, wtap_encap_string(i));
658 * Don't report failures to load plugins because most (non-wiretap) plugins
659 * *should* fail to load (because we're not linked against libwireshark and
660 * dissector plugins need libwireshark).
663 failure_message(const char *msg_format _U_, va_list ap _U_)
670 main(int argc, char *argv[])
679 unsigned int snaplen = 0; /* No limit */
680 unsigned int choplen = 0; /* No chop */
681 wtap_dumper *pdh = NULL;
683 unsigned duplicate_count = 0;
685 struct wtap_pkthdr snap_phdr;
686 const struct wtap_pkthdr *phdr;
689 int split_packet_count = 0;
690 int written_count = 0;
691 char *filename = NULL;
693 int secs_per_block = 0;
695 nstime_t block_start;
696 gchar *fprefix = NULL;
697 gchar *fsuffix = NULL;
700 char* init_progfile_dir_error;
704 * Get credential information for later use.
706 get_credential_info();
709 /* Register wiretap plugins */
710 if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
711 g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
712 g_free(init_progfile_dir_error);
714 init_report_err(failure_message,NULL,NULL,NULL);
719 /* Process the options */
720 while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:T:vw:")) !=-1) {
725 err_prob = strtod(optarg, &p);
726 if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
727 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
731 srand( (unsigned int) (time(NULL) + getpid()) );
735 out_file_type = wtap_short_string_to_file_type(optarg);
736 if (out_file_type < 0) {
737 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
739 list_capture_types();
745 split_packet_count = strtol(optarg, &p, 10);
746 if (p == optarg || *p != '\0') {
747 fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
751 if (split_packet_count <= 0) {
752 fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
759 choplen = strtol(optarg, &p, 10);
760 if (p == optarg || *p != '\0') {
761 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
769 dup_detect_by_time = FALSE;
770 dup_window = DEFAULT_DUP_DEPTH;
775 dup_detect_by_time = FALSE;
776 dup_window = strtol(optarg, &p, 10);
777 if (p == optarg || *p != '\0') {
778 fprintf(stderr, "editcap: \"%s\" isn't a valid dupicate window value\n",
782 if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
783 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
784 dup_window, MAX_DUP_DEPTH);
791 dup_detect_by_time = TRUE;
792 dup_window = MAX_DUP_DEPTH;
793 set_rel_time(optarg);
796 case '?': /* Bad options if GNU getopt */
799 list_capture_types();
816 keep_em = !keep_em; /* Just invert */
820 snaplen = strtol(optarg, &p, 10);
821 if (p == optarg || *p != '\0') {
822 fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
829 set_time_adjustment(optarg);
833 out_frame_type = wtap_short_string_to_encap(optarg);
834 if (out_frame_type < 0) {
835 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
843 verbose = !verbose; /* Just invert */
846 case 'i': /* break capture file based on time interval */
847 secs_per_block = atoi(optarg);
848 if(secs_per_block <= 0) {
849 fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
858 memset(&starttm,0,sizeof(struct tm));
860 if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
861 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
865 check_startstop = TRUE;
866 starttm.tm_isdst = -1;
868 starttime = mktime(&starttm);
876 memset(&stoptm,0,sizeof(struct tm));
878 if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
879 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
882 check_startstop = TRUE;
883 stoptm.tm_isdst = -1;
884 stoptime = mktime(&stoptm);
892 printf("Optind = %i, argc = %i\n", optind, argc);
895 if ((argc - optind) < 1) {
902 if (check_startstop && !stoptime) {
904 /* XXX: will work until 2035 */
905 memset(&stoptm,0,sizeof(struct tm));
906 stoptm.tm_year = 135;
910 stoptime = mktime(&stoptm);
913 nstime_set_unset(&block_start);
915 if (starttime > stoptime) {
916 fprintf(stderr, "editcap: start time is after the stop time\n");
920 if (split_packet_count > 0 && secs_per_block > 0) {
921 fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
922 fprintf(stderr, "editcap: at the same time\n");
926 wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
929 fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
933 case WTAP_ERR_UNSUPPORTED:
934 case WTAP_ERR_UNSUPPORTED_ENCAP:
935 case WTAP_ERR_BAD_RECORD:
936 fprintf(stderr, "(%s)\n", err_info);
945 fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
946 wtap_file_type_string(wtap_file_type(wth)));
950 * Now, process the rest, if any ... we only write if there is an extra
954 if ((argc - optind) >= 2) {
956 if (out_frame_type == -2)
957 out_frame_type = wtap_file_encap(wth);
959 for (i = optind + 2; i < argc; i++)
960 if (add_selection(argv[i]) == FALSE)
963 if (dup_detect || dup_detect_by_time) {
964 for (i = 0; i < dup_window; i++) {
965 memset(&fd_hash[i].digest, 0, 16);
967 nstime_set_unset(&fd_hash[i].time);
971 while (wtap_read(wth, &err, &err_info, &data_offset)) {
972 phdr = wtap_phdr(wth);
974 if (nstime_is_unset(&block_start)) { /* should only be the first packet */
975 block_start.secs = phdr->ts.secs;
976 block_start.nsecs = phdr->ts.nsecs;
978 if (split_packet_count > 0 || secs_per_block > 0) {
979 if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
982 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
984 filename = g_strdup(argv[optind+1]);
986 pdh = wtap_dump_open(filename, out_file_type,
987 out_frame_type, wtap_snapshot_length(wth),
988 FALSE /* compressed */, &err);
990 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
998 if (secs_per_block > 0) {
999 while ((phdr->ts.secs - block_start.secs > secs_per_block) ||
1000 (phdr->ts.secs - block_start.secs == secs_per_block &&
1001 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1003 if (!wtap_dump_close(pdh, &err)) {
1004 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1005 wtap_strerror(err));
1008 block_start.secs = block_start.secs + secs_per_block; /* reset for next interval */
1010 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1014 fprintf(stderr, "Continuing writing in file %s\n", filename);
1017 pdh = wtap_dump_open(filename, out_file_type,
1018 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1021 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1022 wtap_strerror(err));
1028 if (split_packet_count > 0) {
1030 /* time for the next file? */
1031 if (written_count > 0 &&
1032 written_count % split_packet_count == 0) {
1033 if (!wtap_dump_close(pdh, &err)) {
1034 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1035 wtap_strerror(err));
1040 filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1044 fprintf(stderr, "Continuing writing in file %s\n", filename);
1047 pdh = wtap_dump_open(filename, out_file_type,
1048 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1050 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1051 wtap_strerror(err));
1057 check_ts = check_timestamp(wth);
1059 if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1060 (selected(count) && keep_em)) ) {
1062 if (verbose && !dup_detect && !dup_detect_by_time)
1063 printf("Packet: %u\n", count);
1065 /* We simply write it, perhaps after truncating it; we could do other
1066 things, like modify it. */
1068 phdr = wtap_phdr(wth);
1070 if (choplen != 0 && phdr->caplen > choplen) {
1072 snap_phdr.caplen -= choplen;
1076 if (snaplen != 0 && phdr->caplen > snaplen) {
1078 snap_phdr.caplen = snaplen;
1082 /* assume that if the frame's tv_sec is 0, then
1083 * the timestamp isn't supported */
1084 if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1086 if (time_adj.is_negative)
1087 snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1089 snap_phdr.ts.secs += time_adj.tv.tv_sec;
1093 /* assume that if the frame's tv_sec is 0, then
1094 * the timestamp isn't supported */
1095 if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1097 if (time_adj.is_negative) { /* subtract */
1098 if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1099 snap_phdr.ts.secs--;
1100 snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1102 snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1104 if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1106 snap_phdr.ts.secs++;
1107 snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1109 snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1115 /* suppress duplicates by packet window */
1117 buf = wtap_buf_ptr(wth);
1118 if (is_duplicate(buf, phdr->caplen)) {
1120 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1121 for (i = 0; i < 16; i++) {
1122 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1124 fprintf(stdout, "\n");
1131 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1132 for (i = 0; i < 16; i++) {
1133 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1135 fprintf(stdout, "\n");
1140 /* suppress duplicates by time window */
1141 if (dup_detect_by_time) {
1144 current.secs = phdr->ts.secs;
1145 current.nsecs = phdr->ts.nsecs;
1147 buf = wtap_buf_ptr(wth);
1149 if (is_duplicate_rel_time(buf, phdr->caplen, ¤t)) {
1151 fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1152 for (i = 0; i < 16; i++) {
1153 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1155 fprintf(stdout, "\n");
1162 fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1163 for (i = 0; i < 16; i++) {
1164 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1166 fprintf(stdout, "\n");
1171 /* Random error mutation */
1172 if (err_prob > 0.0) {
1173 int real_data_start = 0;
1174 buf = wtap_buf_ptr(wth);
1175 /* Protect non-protocol data */
1176 if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1177 real_data_start = find_dct2000_real_data(buf);
1179 for (i = real_data_start; i < (int) phdr->caplen; i++) {
1180 if (rand() <= err_prob * RAND_MAX) {
1181 err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1183 if (err_type < ERR_WT_BIT) {
1184 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1185 err_type = ERR_WT_TOTAL;
1187 err_type -= ERR_WT_BYTE;
1190 if (err_type < ERR_WT_BYTE) {
1191 buf[i] = rand() / (RAND_MAX / 255 + 1);
1192 err_type = ERR_WT_TOTAL;
1194 err_type -= ERR_WT_BYTE;
1197 if (err_type < ERR_WT_ALNUM) {
1198 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1199 err_type = ERR_WT_TOTAL;
1201 err_type -= ERR_WT_ALNUM;
1204 if (err_type < ERR_WT_FMT) {
1205 if ((unsigned int)i < phdr->caplen - 2)
1206 strncpy((char*) &buf[i], "%s", 2);
1207 err_type = ERR_WT_TOTAL;
1209 err_type -= ERR_WT_FMT;
1212 if (err_type < ERR_WT_AA) {
1213 for (j = i; j < (int) phdr->caplen; j++) {
1222 if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
1224 fprintf(stderr, "editcap: Error writing to %s: %s\n",
1225 filename, wtap_strerror(err));
1237 /* Print a message noting that the read failed somewhere along the line. */
1239 "editcap: An error occurred while reading \"%s\": %s.\n",
1240 argv[optind], wtap_strerror(err));
1243 case WTAP_ERR_UNSUPPORTED:
1244 case WTAP_ERR_UNSUPPORTED_ENCAP:
1245 case WTAP_ERR_BAD_RECORD:
1246 fprintf(stderr, "(%s)\n", err_info);
1253 /* No valid packages found, open the outfile so we can write an empty header */
1255 filename = g_strdup(argv[optind+1]);
1257 pdh = wtap_dump_open(filename, out_file_type,
1258 out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1260 fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1261 wtap_strerror(err));
1266 if (!wtap_dump_close(pdh, &err)) {
1268 fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1269 wtap_strerror(err));
1277 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1278 count - 1, plurality(count - 1, "", "s"),
1279 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1280 } else if (dup_detect_by_time) {
1281 fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1282 count - 1, plurality(count - 1, "", "s"),
1283 duplicate_count, plurality(duplicate_count, "", "s"),
1284 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1290 /* Skip meta-information read from file to return offset of real
1292 static int find_dct2000_real_data(guint8 *buf)
1296 for (n=0; buf[n] != '\0'; n++); /* Context name */
1298 n++; /* Context port number */
1299 for (; buf[n] != '\0'; n++); /* Timestamp */
1301 for (; buf[n] != '\0'; n++); /* Protocol name */
1303 for (; buf[n] != '\0'; n++); /* Variant number (as string) */
1305 for (; buf[n] != '\0'; n++); /* Outhdr (as string) */
1307 n += 2; /* Direction & encap */