From Guy Martin via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6993 :
[metze/wireshark/wip.git] / editcap.c
1 /* Edit capture files.  We can delete packets, adjust timestamps, or
2  * simply convert from one format to another format.
3  *
4  * $Id$
5  *
6  * Originally written by Richard Sharpe.
7  * Improved by Guy Harris.
8  * Further improved by Richard Sharpe.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdarg.h>
19
20 /*
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
23  * yet defined.
24  */
25
26 #ifndef __USE_XOPEN
27 #  define __USE_XOPEN
28 #endif
29
30 #include <time.h>
31 #include <glib.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37
38
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42
43 #include "wtap.h"
44
45 #ifndef HAVE_GETOPT
46 #include "wsutil/wsgetopt.h"
47 #endif
48
49 #ifdef _WIN32
50 #include <wsutil/unicode-utils.h>
51 #include <process.h>    /* getpid */
52 #ifdef HAVE_WINSOCK2_H
53 #include <winsock2.h>
54 #endif
55 #endif
56
57 #ifdef NEED_STRPTIME_H
58 # include "wsutil/strptime.h"
59 #endif
60
61 #include "epan/crypt/md5.h"
62 #include "epan/plugins.h"
63 #include "epan/report_err.h"
64 #include "epan/filesystem.h"
65 #include <wsutil/privileges.h>
66 #include "epan/nstime.h"
67
68 #include "svnversion.h"
69
70 /*
71  * Some globals so we can pass things to various routines
72  */
73
74 struct select_item {
75
76   int inclusive;
77   int first, second;
78
79 };
80
81
82 /*
83  * Duplicate frame detection
84  */
85 typedef struct _fd_hash_t {
86   md5_byte_t digest[16];
87   guint32 len;
88   nstime_t time;
89 } fd_hash_t;
90
91 #define DEFAULT_DUP_DEPTH 5     /* Used with -d */
92 #define MAX_DUP_DEPTH 1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
93
94 fd_hash_t fd_hash[MAX_DUP_DEPTH];
95 int dup_window = DEFAULT_DUP_DEPTH;
96 int cur_dup_entry = 0;
97
98 #define ONE_MILLION 1000000
99 #define ONE_BILLION 1000000000
100
101 /* Weights of different errors we can introduce */
102 /* We should probably make these command-line arguments */
103 /* XXX - Should we add a bit-level error? */
104 #define ERR_WT_BIT   5  /* Flip a random bit */
105 #define ERR_WT_BYTE  5  /* Substitute a random byte */
106 #define ERR_WT_ALNUM 5  /* Substitute a random character in [A-Za-z0-9] */
107 #define ERR_WT_FMT   2  /* Substitute "%s" */
108 #define ERR_WT_AA    1  /* Fill the remainder of the buffer with 0xAA */
109 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
110
111 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
112 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
113
114
115 struct time_adjustment {
116   struct timeval tv;
117   int is_negative;
118 };
119
120 #define MAX_SELECTIONS 512
121 static struct select_item selectfrm[MAX_SELECTIONS];
122 static int max_selected = -1;
123 static int keep_em = 0;
124 #ifdef PCAP_NG_DEFAULT
125 static int out_file_type = WTAP_FILE_PCAPNG; /* default to pcapng   */
126 #else
127 static int out_file_type = WTAP_FILE_PCAP;   /* default to pcap     */
128 #endif
129 static int out_frame_type = -2;              /* Leave frame type alone */
130 static int verbose = 0;                      /* Not so verbose         */
131 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
132 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
133 static double err_prob = 0.0;
134 static time_t starttime = 0;
135 static time_t stoptime = 0;
136 static gboolean check_startstop = FALSE;
137 static gboolean dup_detect = FALSE;
138 static gboolean dup_detect_by_time = FALSE;
139
140 static int do_strict_time_adjustment = FALSE;
141 static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */
142 static nstime_t previous_time = {0, 0}; /* previous time */
143
144 static int find_dct2000_real_data(guint8 *buf);
145
146 static gchar *
147 abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time)
148 {
149     struct tm *tmp;
150     gchar *buf = g_malloc(16);
151
152 #ifdef _MSC_VER
153     /* calling localtime() on MSVC 2005 with huge values causes it to crash */
154     /* XXX - find the exact value that still does work */
155     /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
156     if(abs_time->secs > 2000000000) {
157         tmp = NULL;
158     } else
159 #endif
160     tmp = localtime(&abs_time->secs);
161     if (tmp) {
162         g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
163             tmp->tm_year + 1900,
164             tmp->tm_mon+1,
165             tmp->tm_mday,
166             tmp->tm_hour,
167             tmp->tm_min,
168             tmp->tm_sec);
169     } else
170         buf[0] = '\0';
171
172     return buf;
173 }
174
175 static gchar*
176 fileset_get_filename_by_pattern(guint idx,    const struct wtap_nstime *time_val,
177                                 gchar *fprefix, gchar *fsuffix)
178 {
179     gchar filenum[5+1];
180     gchar *timestr;
181     gchar *abs_str;
182
183     timestr = abs_time_to_str_with_sec_resolution(time_val);
184     g_snprintf(filenum, sizeof(filenum), "%05u", idx);
185     abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
186     g_free(timestr);
187
188     return abs_str;
189 }
190
191 static gboolean
192 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
193 {
194     char  *pfx, *last_pathsep;
195     gchar *save_file;
196
197     save_file = g_strdup(fname);
198     if (save_file == NULL) {
199       fprintf(stderr, "editcap: Out of memory\n");
200       return FALSE;
201     }
202
203     last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
204     pfx = strrchr(save_file,'.');
205     if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
206       /* The pathname has a "." in it, and it's in the last component
207          of the pathname (because there is either only one component,
208          i.e. last_pathsep is null as there are no path separators,
209          or the "." is after the path separator before the last
210          component.
211
212          Treat it as a separator between the rest of the file name and
213          the file name suffix, and arrange that the names given to the
214          ring buffer files have the specified suffix, i.e. put the
215          changing part of the name *before* the suffix. */
216       pfx[0] = '\0';
217       *fprefix = g_strdup(save_file);
218       pfx[0] = '.'; /* restore capfile_name */
219       *fsuffix = g_strdup(pfx);
220     } else {
221       /* Either there's no "." in the pathname, or it's in a directory
222          component, so the last component has no suffix. */
223       *fprefix = g_strdup(save_file);
224       *fsuffix = NULL;
225     }
226     g_free(save_file);
227     return TRUE;
228 }
229
230 /* Add a selection item, a simple parser for now */
231 static gboolean
232 add_selection(char *sel)
233 {
234   char *locn;
235   char *next;
236
237   if (++max_selected >= MAX_SELECTIONS) {
238     /* Let the user know we stopped selecting */
239     printf("Out of room for packet selections!\n");
240     return(FALSE);
241   }
242
243   printf("Add_Selected: %s\n", sel);
244
245   if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
246
247     printf("Not inclusive ...");
248
249     selectfrm[max_selected].inclusive = 0;
250     selectfrm[max_selected].first = atoi(sel);
251
252     printf(" %i\n", selectfrm[max_selected].first);
253
254   }
255   else {
256
257     printf("Inclusive ...");
258
259     next = locn + 1;
260     selectfrm[max_selected].inclusive = 1;
261     selectfrm[max_selected].first = atoi(sel);
262     selectfrm[max_selected].second = atoi(next);
263
264     printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
265
266   }
267
268   return(TRUE);
269 }
270
271 /* Was the packet selected? */
272
273 static int
274 selected(int recno)
275 {
276   int i = 0;
277
278   for (i = 0; i<= max_selected; i++) {
279
280     if (selectfrm[i].inclusive) {
281       if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
282         return 1;
283     }
284     else {
285       if (recno == selectfrm[i].first)
286         return 1;
287     }
288   }
289
290   return 0;
291
292 }
293
294 /* is the packet in the selected timeframe */
295 static gboolean
296 check_timestamp(wtap *wth)
297 {
298   struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
299
300   return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime );
301 }
302
303 static void
304 set_time_adjustment(char *optarg_str_p)
305 {
306   char *frac, *end;
307   long val;
308   size_t frac_digits;
309
310   if (!optarg_str_p)
311     return;
312
313   /* skip leading whitespace */
314   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
315       optarg_str_p++;
316   }
317
318   /* check for a negative adjustment */
319   if (*optarg_str_p == '-') {
320       time_adj.is_negative = 1;
321       optarg_str_p++;
322   }
323
324   /* collect whole number of seconds, if any */
325   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
326       val  = 0;
327       frac = optarg_str_p;
328   } else {
329       val = strtol(optarg_str_p, &frac, 10);
330       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
331           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
332                   optarg_str_p);
333           exit(1);
334       }
335       if (val < 0) {            /* implies '--' since we caught '-' above  */
336           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
337                   optarg_str_p);
338           exit(1);
339       }
340   }
341   time_adj.tv.tv_sec = val;
342
343   /* now collect the partial seconds, if any */
344   if (*frac != '\0') {             /* chars left, so get fractional part */
345     val = strtol(&(frac[1]), &end, 10);
346     /* if more than 6 fractional digits truncate to 6 */
347     if((end - &(frac[1])) > 6) {
348         frac[7] = 't'; /* 't' for truncate */
349         val = strtol(&(frac[1]), &end, 10);
350     }
351     if (*frac != '.' || end == NULL || end == frac
352         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
353       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
354               optarg_str_p);
355       exit(1);
356     }
357   }
358   else {
359     return;                     /* no fractional digits */
360   }
361
362   /* adjust fractional portion from fractional to numerator
363    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
364   if (frac && end) {            /* both are valid */
365     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
366     while(frac_digits < 6) {    /* this is frac of 10^6 */
367       val *= 10;
368       frac_digits++;
369     }
370   }
371   time_adj.tv.tv_usec = val;
372 }
373
374 static void
375 set_strict_time_adj(char *optarg_str_p)
376 {
377   char *frac, *end;
378   long val;
379   size_t frac_digits;
380
381   if (!optarg_str_p)
382     return;
383
384   /* skip leading whitespace */
385   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
386       optarg_str_p++;
387   }
388
389   /*
390    * check for a negative adjustment
391    * A negative strict adjustment value is a flag
392    * to adjust all frames by the specifed delta time.
393    */
394   if (*optarg_str_p == '-') {
395       strict_time_adj.is_negative = 1;
396       optarg_str_p++;
397   }
398
399   /* collect whole number of seconds, if any */
400   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
401       val  = 0;
402       frac = optarg_str_p;
403   } else {
404       val = strtol(optarg_str_p, &frac, 10);
405       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
406           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
407                   optarg_str_p);
408           exit(1);
409       }
410       if (val < 0) {            /* implies '--' since we caught '-' above  */
411           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
412                   optarg_str_p);
413           exit(1);
414       }
415   }
416   strict_time_adj.tv.tv_sec = val;
417
418   /* now collect the partial seconds, if any */
419   if (*frac != '\0') {             /* chars left, so get fractional part */
420     val = strtol(&(frac[1]), &end, 10);
421     /* if more than 6 fractional digits truncate to 6 */
422     if((end - &(frac[1])) > 6) {
423         frac[7] = 't'; /* 't' for truncate */
424         val = strtol(&(frac[1]), &end, 10);
425     }
426     if (*frac != '.' || end == NULL || end == frac
427         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
428       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
429               optarg_str_p);
430       exit(1);
431     }
432   }
433   else {
434     return;                     /* no fractional digits */
435   }
436
437   /* adjust fractional portion from fractional to numerator
438    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
439   if (frac && end) {            /* both are valid */
440     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
441     while(frac_digits < 6) {    /* this is frac of 10^6 */
442       val *= 10;
443       frac_digits++;
444     }
445   }
446   strict_time_adj.tv.tv_usec = val;
447 }
448
449 static void
450 set_rel_time(char *optarg_str_p)
451 {
452   char *frac, *end;
453   long val;
454   size_t frac_digits;
455
456   if (!optarg_str_p)
457     return;
458
459   /* skip leading whitespace */
460   while (*optarg_str_p == ' ' || *optarg_str_p == '\t') {
461       optarg_str_p++;
462   }
463
464   /* ignore negative adjustment  */
465   if (*optarg_str_p == '-') {
466       optarg_str_p++;
467   }
468
469   /* collect whole number of seconds, if any */
470   if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
471       val  = 0;
472       frac = optarg_str_p;
473   } else {
474       val = strtol(optarg_str_p, &frac, 10);
475       if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) {
476           fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
477                   optarg_str_p);
478           exit(1);
479       }
480       if (val < 0) {            /* implies '--' since we caught '-' above  */
481           fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
482                   optarg_str_p);
483           exit(1);
484       }
485   }
486   relative_time_window.secs = val;
487
488   /* now collect the partial seconds, if any */
489   if (*frac != '\0') {             /* chars left, so get fractional part */
490     val = strtol(&(frac[1]), &end, 10);
491     /* if more than 9 fractional digits truncate to 9 */
492     if((end - &(frac[1])) > 9) {
493         frac[10] = 't'; /* 't' for truncate */
494         val = strtol(&(frac[1]), &end, 10);
495     }
496     if (*frac != '.' || end == NULL || end == frac
497         || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
498       fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
499               optarg_str_p);
500       exit(1);
501     }
502   }
503   else {
504     return;                     /* no fractional digits */
505   }
506
507   /* adjust fractional portion from fractional to numerator
508    * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
509   if (frac && end) {            /* both are valid */
510     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
511     while(frac_digits < 9) {    /* this is frac of 10^9 */
512       val *= 10;
513       frac_digits++;
514     }
515   }
516   relative_time_window.nsecs = val;
517 }
518
519 static gboolean
520 is_duplicate(guint8* fd, guint32 len) {
521   int i;
522   md5_state_t ms;
523
524   cur_dup_entry++;
525   if (cur_dup_entry >= dup_window)
526     cur_dup_entry = 0;
527
528   /* Calculate our digest */
529   md5_init(&ms);
530   md5_append(&ms, fd, len);
531   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
532
533   fd_hash[cur_dup_entry].len = len;
534
535   /* Look for duplicates */
536   for (i = 0; i < dup_window; i++) {
537     if (i == cur_dup_entry)
538       continue;
539
540     if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
541         memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
542       return TRUE;
543     }
544   }
545
546   return FALSE;
547 }
548
549 static gboolean
550 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
551   int i;
552   md5_state_t ms;
553
554   cur_dup_entry++;
555   if (cur_dup_entry >= dup_window)
556     cur_dup_entry = 0;
557
558   /* Calculate our digest */
559   md5_init(&ms);
560   md5_append(&ms, fd, len);
561   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
562
563   fd_hash[cur_dup_entry].len = len;
564   fd_hash[cur_dup_entry].time.secs = current->secs;
565   fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
566
567   /*
568    * Look for relative time related duplicates.
569    * This is hopefully a reasonably efficient mechanism for
570    * finding duplicates by rel time in the fd_hash[] cache.
571    * We check starting from the most recently added hash
572    * entries and work backwards towards older packets.
573    * This approach allows the dup test to be terminated
574    * when the relative time of a cached entry is found to
575    * be beyond the dup time window.
576    *
577    * Of course this assumes that the input trace file is
578    * "well-formed" in the sense that the packet timestamps are
579    * in strict chronologically increasing order (which is NOT
580    * always the case!!).
581    *
582    * The fd_hash[] table was deliberatly created large (1,000,000).
583    * Looking for time related duplicates in large trace files with
584    * non-fractional dup time window values can potentially take
585    * a long time to complete.
586    */
587
588   for (i = cur_dup_entry - 1;; i--) {
589     nstime_t delta;
590     int cmp;
591
592     if (i < 0) {
593       i = dup_window - 1;
594     }
595
596     if (i == cur_dup_entry) {
597       /*
598        * We've decremented back to where we started.
599        * Check no more!
600        */
601       break;
602     }
603
604     if (nstime_is_unset(&(fd_hash[i].time))) {
605       /*
606        * We've decremented to an unused fd_hash[] entry.
607        * Check no more!
608        */
609       break;
610     }
611
612     nstime_delta(&delta, current, &fd_hash[i].time);
613
614     if(delta.secs < 0 || delta.nsecs < 0)
615     {
616       /*
617        * A negative delta implies that the current packet
618        * has an absolute timestamp less than the cached packet
619        * that it is being compared to.  This is NOT a normal
620        * situation since trace files usually have packets in
621        * chronological order (oldest to newest).
622        *
623        * There are several possible ways to deal with this:
624        * 1. 'continue' dup checking with the next cached frame.
625        * 2. 'break' from looking for a duplicate of the current frame.
626        * 3. Take the absolute value of the delta and see if that
627        * falls within the specifed dup time window.
628        *
629        * Currently this code does option 1.  But it would pretty
630        * easy to add yet-another-editcap-option to select one of
631        * the other behaviors for dealing with out-of-sequence
632        * packets.
633        */
634       continue;
635     }
636
637     cmp = nstime_cmp(&delta, &relative_time_window);
638
639     if(cmp > 0) {
640       /*
641        * The delta time indicates that we are now looking at
642        * cached packets beyond the specified dup time window.
643        * Check no more!
644        */
645       break;
646     } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
647           memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
648       return TRUE;
649     }
650   }
651
652   return FALSE;
653 }
654
655 static void
656 usage(gboolean is_error)
657 {
658   FILE *output;
659
660   if (!is_error)
661     output = stdout;
662   else
663     output = stderr;
664
665   fprintf(output, "Editcap %s"
666 #ifdef SVNVERSION
667     " (" SVNVERSION " from " SVNPATH ")"
668 #endif
669     "\n", VERSION);
670   fprintf(output, "Edit and/or translate the format of capture files.\n");
671   fprintf(output, "See http://www.wireshark.org for more information.\n");
672   fprintf(output, "\n");
673   fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
674   fprintf(output, "\n");
675   fprintf(output, "<infile> and <outfile> must both be present.\n");
676   fprintf(output, "A single packet or a range of packets can be selected.\n");
677   fprintf(output, "\n");
678   fprintf(output, "Packet selection:\n");
679   fprintf(output, "  -r                     keep the selected packets; default is to delete them.\n");
680   fprintf(output, "  -A <start time>        only output packets whose timestamp is after (or equal\n");
681   fprintf(output, "                         to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
682   fprintf(output, "  -B <stop time>         only output packets whose timestamp is before the\n");
683   fprintf(output, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
684   fprintf(output, "\n");
685   fprintf(output, "Duplicate packet removal:\n");
686   fprintf(output, "  -d                     remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
687   fprintf(output, "  -D <dup window>        remove packet if duplicate; configurable <dup window>\n");
688   fprintf(output, "                         Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
689   fprintf(output, "                         NOTE: A <dup window> of 0 with -v (verbose option) is\n");
690   fprintf(output, "                         useful to print MD5 hashes.\n");
691   fprintf(output, "  -w <dup time window>   remove packet if duplicate packet is found EQUAL TO OR\n");
692   fprintf(output, "                         LESS THAN <dup time window> prior to current packet.\n");
693   fprintf(output, "                         A <dup time window> is specified in relative seconds\n");
694   fprintf(output, "                         (e.g. 0.000001).\n");
695   fprintf(output, "\n");
696   fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
697   fprintf(output, "           other editcap options except -v may not always work as expected.\n");
698   fprintf(output, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
699   fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
700   fprintf(output, "\n");
701   fprintf(output, "Packet manipulation:\n");
702   fprintf(output, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
703   fprintf(output, "  -C <choplen>           chop each packet by <choplen> bytes. Positive values\n");
704   fprintf(output, "                         chop at the packet beginning, negative values at the\n");
705   fprintf(output, "                         packet end.\n");
706   fprintf(output, "  -t <time adjustment>   adjust the timestamp of each packet;\n");
707   fprintf(output, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
708   fprintf(output, "  -S <strict adjustment> adjust timestamp of packets if necessary to insure\n");
709   fprintf(output, "                         strict chronological increasing order. The <strict\n");
710   fprintf(output, "                         adjustment> is specified in relative seconds with\n");
711   fprintf(output, "                         values of 0 or 0.000001 being the most reasonable.\n");
712   fprintf(output, "                         A negative adjustment value will modify timestamps so\n");
713   fprintf(output, "                         that each packet's delta time is the absolute value\n");
714   fprintf(output, "                         of the adjustment specified. A value of -0 will set\n");
715   fprintf(output, "                         all packets to the timestamp of the first packet.\n");
716   fprintf(output, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
717   fprintf(output, "                         that a particular packet byte will be randomly changed.\n");
718   fprintf(output, "\n");
719   fprintf(output, "Output File(s):\n");
720   fprintf(output, "  -c <packets per file>  split the packet output to different files\n");
721   fprintf(output, "                         based on uniform packet counts\n");
722   fprintf(output, "                         with a maximum of <packets per file> each.\n");
723   fprintf(output, "  -i <seconds per file>  split the packet output to different files\n");
724   fprintf(output, "                         based on uniform time intervals\n");
725   fprintf(output, "                         with a maximum of <seconds per file> each.\n");
726   fprintf(output, "  -F <capture type>      set the output file type; default is pcapng.\n");
727   fprintf(output, "                         an empty \"-F\" option will list the file types.\n");
728   fprintf(output, "  -T <encap type>        set the output file encapsulation type;\n");
729   fprintf(output, "                         default is the same as the input file.\n");
730   fprintf(output, "                         an empty \"-T\" option will list the encapsulation types.\n");
731   fprintf(output, "\n");
732   fprintf(output, "Miscellaneous:\n");
733   fprintf(output, "  -h                     display this help and exit.\n");
734   fprintf(output, "  -v                     verbose output.\n");
735   fprintf(output, "                         If -v is used with any of the 'Duplicate Packet\n");
736   fprintf(output, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
737   fprintf(output, "                         and MD5 hashes are printed to standard-out.\n");
738   fprintf(output, "\n");
739 }
740
741 struct string_elem {
742     const char *sstr;   /* The short string */
743     const char *lstr;   /* The long string */
744 };
745
746 static gint
747 string_compare(gconstpointer a, gconstpointer b)
748 {
749     return strcmp(((const struct string_elem *)a)->sstr,
750         ((const struct string_elem *)b)->sstr);
751 }
752
753 static void
754 string_elem_print(gpointer data, gpointer not_used _U_)
755 {
756     fprintf(stderr, "    %s - %s\n",
757         ((struct string_elem *)data)->sstr,
758         ((struct string_elem *)data)->lstr);
759 }
760
761 static void
762 list_capture_types(void) {
763     int i;
764     struct string_elem *captypes;
765     GSList *list = NULL;
766
767     captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES);
768     fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
769     for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
770       if (wtap_dump_can_open(i)) {
771         captypes[i].sstr = wtap_file_type_short_string(i);
772         captypes[i].lstr = wtap_file_type_string(i);
773         list = g_slist_insert_sorted(list, &captypes[i], string_compare);
774       }
775     }
776     g_slist_foreach(list, string_elem_print, NULL);
777     g_slist_free(list);
778     g_free(captypes);
779 }
780
781 static void
782 list_encap_types(void) {
783     int i;
784     struct string_elem *encaps;
785     GSList *list = NULL;
786
787     encaps = g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
788     fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
789     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
790         encaps[i].sstr = wtap_encap_short_string(i);
791         if (encaps[i].sstr != NULL) {
792             encaps[i].lstr = wtap_encap_string(i);
793             list = g_slist_insert_sorted(list, &encaps[i], string_compare);
794         }
795     }
796     g_slist_foreach(list, string_elem_print, NULL);
797     g_slist_free(list);
798     g_free(encaps);
799 }
800
801 #ifdef HAVE_PLUGINS
802 /*
803  *  Don't report failures to load plugins because most (non-wiretap) plugins
804  *  *should* fail to load (because we're not linked against libwireshark and
805  *  dissector plugins need libwireshark).
806  */
807 static void
808 failure_message(const char *msg_format _U_, va_list ap _U_)
809 {
810     return;
811 }
812 #endif
813
814 int
815 main(int argc, char *argv[])
816 {
817   wtap *wth;
818   int i, j, err;
819   gchar *err_info;
820   int opt;
821
822   char *p;
823   guint32 snaplen = 0;                  /* No limit               */
824   int choplen = 0;                      /* No chop                */
825   wtap_dumper *pdh = NULL;
826   int count = 1;
827   unsigned duplicate_count = 0;
828   gint64 data_offset;
829   struct wtap_pkthdr snap_phdr;
830   const struct wtap_pkthdr *phdr;
831   int err_type;
832   wtapng_section_t *shb_hdr;
833   wtapng_iface_descriptions_t *idb_inf;
834   guint8 *buf;
835   guint32 read_count = 0;
836   int split_packet_count = 0;
837   int written_count = 0;
838   char *filename = NULL;
839   gboolean ts_okay = TRUE;
840   int secs_per_block = 0;
841   int block_cnt = 0;
842   nstime_t block_start;
843   gchar *fprefix = NULL;
844   gchar *fsuffix = NULL;
845   char appname[100];
846
847 #ifdef HAVE_PLUGINS
848   char* init_progfile_dir_error;
849 #endif
850
851 #ifdef _WIN32
852   arg_list_utf_16to8(argc, argv);
853 #endif /* _WIN32 */
854
855   /*
856    * Get credential information for later use.
857    */
858   init_process_policies();
859
860 #ifdef HAVE_PLUGINS
861   /* Register wiretap plugins */
862   if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
863     g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
864     g_free(init_progfile_dir_error);
865   } else {
866     init_report_err(failure_message,NULL,NULL,NULL);
867     init_plugins();
868   }
869 #endif
870
871   /* Process the options */
872   while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
873
874     switch (opt) {
875
876     case 'E':
877       err_prob = strtod(optarg, &p);
878       if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
879         fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
880             optarg);
881         exit(1);
882       }
883       srand( (unsigned int) (time(NULL) + getpid()) );
884       break;
885
886     case 'F':
887       out_file_type = wtap_short_string_to_file_type(optarg);
888       if (out_file_type < 0) {
889         fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
890             optarg);
891         list_capture_types();
892         exit(1);
893       }
894       break;
895
896     case 'c':
897       split_packet_count = strtol(optarg, &p, 10);
898       if (p == optarg || *p != '\0') {
899         fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
900             optarg);
901         exit(1);
902       }
903       if (split_packet_count <= 0) {
904         fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
905             split_packet_count);
906         exit(1);
907       }
908       break;
909
910     case 'C':
911       choplen = strtol(optarg, &p, 10);
912       if (p == optarg || *p != '\0') {
913         fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
914             optarg);
915         exit(1);
916       }
917       break;
918
919     case 'd':
920       dup_detect = TRUE;
921       dup_detect_by_time = FALSE;
922       dup_window = DEFAULT_DUP_DEPTH;
923       break;
924
925     case 'D':
926       dup_detect = TRUE;
927       dup_detect_by_time = FALSE;
928       dup_window = strtol(optarg, &p, 10);
929       if (p == optarg || *p != '\0') {
930         fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
931             optarg);
932         exit(1);
933       }
934       if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
935         fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
936             dup_window, MAX_DUP_DEPTH);
937         exit(1);
938       }
939       break;
940
941     case 'w':
942       dup_detect = FALSE;
943       dup_detect_by_time = TRUE;
944       dup_window = MAX_DUP_DEPTH;
945       set_rel_time(optarg);
946       break;
947
948     case '?':              /* Bad options if GNU getopt */
949       switch(optopt) {
950       case'F':
951         list_capture_types();
952         break;
953       case'T':
954         list_encap_types();
955         break;
956       default:
957         usage(TRUE);
958       }
959       exit(1);
960       break;
961
962     case 'h':
963       usage(FALSE);
964       exit(1);
965       break;
966
967     case 'r':
968       keep_em = !keep_em;  /* Just invert */
969       break;
970
971     case 's':
972       snaplen = strtol(optarg, &p, 10);
973       if (p == optarg || *p != '\0') {
974         fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
975                 optarg);
976         exit(1);
977       }
978       break;
979
980     case 't':
981       set_time_adjustment(optarg);
982       break;
983
984     case 'S':
985       set_strict_time_adj(optarg);
986       do_strict_time_adjustment = TRUE;
987       break;
988
989     case 'T':
990       out_frame_type = wtap_short_string_to_encap(optarg);
991       if (out_frame_type < 0) {
992         fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
993           optarg);
994         list_encap_types();
995         exit(1);
996       }
997       break;
998
999     case 'v':
1000       verbose = !verbose;  /* Just invert */
1001       break;
1002
1003     case 'i': /* break capture file based on time interval */
1004       secs_per_block = atoi(optarg);
1005       if(secs_per_block <= 0) {
1006         fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1007         exit(1);
1008         }
1009       break;
1010
1011     case 'A':
1012     {
1013       struct tm starttm;
1014
1015       memset(&starttm,0,sizeof(struct tm));
1016
1017       if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1018         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1019         exit(1);
1020       }
1021
1022       check_startstop = TRUE;
1023       starttm.tm_isdst = -1;
1024
1025       starttime = mktime(&starttm);
1026       break;
1027     }
1028
1029     case 'B':
1030     {
1031       struct tm stoptm;
1032
1033       memset(&stoptm,0,sizeof(struct tm));
1034
1035       if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1036         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1037         exit(1);
1038       }
1039       check_startstop = TRUE;
1040       stoptm.tm_isdst = -1;
1041       stoptime = mktime(&stoptm);
1042       break;
1043     }
1044     }
1045
1046   }
1047
1048 #ifdef DEBUG
1049   printf("Optind = %i, argc = %i\n", optind, argc);
1050 #endif
1051
1052   if ((argc - optind) < 1) {
1053
1054     usage(TRUE);
1055     exit(1);
1056
1057   }
1058
1059   if (check_startstop && !stoptime) {
1060     struct tm stoptm;
1061     /* XXX: will work until 2035 */
1062     memset(&stoptm,0,sizeof(struct tm));
1063     stoptm.tm_year = 135;
1064     stoptm.tm_mday = 31;
1065     stoptm.tm_mon = 11;
1066
1067     stoptime = mktime(&stoptm);
1068   }
1069
1070   nstime_set_unset(&block_start);
1071
1072   if (starttime > stoptime) {
1073     fprintf(stderr, "editcap: start time is after the stop time\n");
1074     exit(1);
1075   }
1076
1077   if (split_packet_count > 0 && secs_per_block > 0) {
1078     fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1079     fprintf(stderr, "editcap: at the same time\n");
1080     exit(1);
1081   }
1082
1083   wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1084
1085   if (!wth) {
1086     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1087         wtap_strerror(err));
1088     switch (err) {
1089
1090     case WTAP_ERR_UNSUPPORTED:
1091     case WTAP_ERR_UNSUPPORTED_ENCAP:
1092     case WTAP_ERR_BAD_FILE:
1093       fprintf(stderr, "(%s)\n", err_info);
1094       g_free(err_info);
1095       break;
1096     }
1097     exit(2);
1098
1099   }
1100
1101   if (verbose) {
1102     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1103             wtap_file_type_string(wtap_file_type(wth)));
1104   }
1105
1106   shb_hdr = wtap_file_get_shb_info(wth);
1107   idb_inf = wtap_file_get_idb_info(wth);
1108
1109   /*
1110    * Now, process the rest, if any ... we only write if there is an extra
1111    * argument or so ...
1112    */
1113
1114   if ((argc - optind) >= 2) {
1115
1116     if (out_frame_type == -2)
1117       out_frame_type = wtap_file_encap(wth);
1118
1119     for (i = optind + 2; i < argc; i++)
1120       if (add_selection(argv[i]) == FALSE)
1121         break;
1122
1123     if (dup_detect || dup_detect_by_time) {
1124       for (i = 0; i < dup_window; i++) {
1125         memset(&fd_hash[i].digest, 0, 16);
1126         fd_hash[i].len = 0;
1127         nstime_set_unset(&fd_hash[i].time);
1128       }
1129     }
1130
1131     while (wtap_read(wth, &err, &err_info, &data_offset)) {
1132       read_count++;
1133
1134       phdr = wtap_phdr(wth);
1135       buf = wtap_buf_ptr(wth);
1136
1137       if (nstime_is_unset(&block_start)) {  /* should only be the first packet */
1138         block_start.secs = phdr->ts.secs;
1139         block_start.nsecs = phdr->ts.nsecs;
1140
1141         if (split_packet_count > 0 || secs_per_block > 0) {
1142           if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1143               exit(2);
1144
1145           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1146         } else
1147           filename = g_strdup(argv[optind+1]);
1148
1149         /* If we don't have an application name add Editcap */
1150         if(shb_hdr->shb_user_appl == NULL) {
1151           g_snprintf(appname, sizeof(appname), "Editcap " VERSION);
1152           shb_hdr->shb_user_appl = appname;
1153         }
1154
1155         pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1156           snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1157           FALSE /* compressed */, shb_hdr, idb_inf, &err);
1158
1159         if (pdh == NULL) {
1160           fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1161                   wtap_strerror(err));
1162           exit(2);
1163         }
1164
1165         g_free(idb_inf);
1166         idb_inf = NULL;
1167       }
1168
1169       g_assert(filename);
1170
1171       if (secs_per_block > 0) {
1172         while ((phdr->ts.secs - block_start.secs >  secs_per_block) ||
1173                (phdr->ts.secs - block_start.secs == secs_per_block &&
1174                 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1175
1176           if (!wtap_dump_close(pdh, &err)) {
1177             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1178                 wtap_strerror(err));
1179             exit(2);
1180           }
1181           block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1182           g_free(filename);
1183           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1184           g_assert(filename);
1185
1186           if (verbose) {
1187             fprintf(stderr, "Continuing writing in file %s\n", filename);
1188           }
1189
1190           pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1191             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1192             FALSE /* compressed */, &err);
1193
1194           if (pdh == NULL) {
1195             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1196               wtap_strerror(err));
1197             exit(2);
1198           }
1199         }
1200       }
1201
1202       if (split_packet_count > 0) {
1203
1204         /* time for the next file? */
1205         if (written_count > 0 &&
1206             written_count % split_packet_count == 0) {
1207           if (!wtap_dump_close(pdh, &err)) {
1208             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1209                 wtap_strerror(err));
1210             exit(2);
1211           }
1212
1213           g_free(filename);
1214           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1215           g_assert(filename);
1216
1217           if (verbose) {
1218             fprintf(stderr, "Continuing writing in file %s\n", filename);
1219           }
1220
1221           pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1222             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1223             FALSE /* compressed */, &err);
1224           if (pdh == NULL) {
1225             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1226                 wtap_strerror(err));
1227             exit(2);
1228           }
1229         }
1230       }
1231
1232       if (check_startstop)
1233         ts_okay = check_timestamp(wth);
1234
1235       if ( ts_okay && ((!selected(count) && !keep_em) || (selected(count) && keep_em)) ) {
1236
1237         if (verbose && !dup_detect && !dup_detect_by_time)
1238           printf("Packet: %u\n", count);
1239
1240         /* We simply write it, perhaps after truncating it; we could do other
1241            things, like modify it. */
1242
1243         phdr = wtap_phdr(wth);
1244
1245         if (snaplen != 0 && phdr->caplen > snaplen) {
1246           snap_phdr = *phdr;
1247           snap_phdr.caplen = snaplen;
1248           phdr = &snap_phdr;
1249         }
1250
1251         if (choplen < 0) {
1252           snap_phdr = *phdr;
1253           if (((signed int) phdr->caplen + choplen) > 0)
1254             snap_phdr.caplen += choplen;
1255           else
1256             snap_phdr.caplen = 0;
1257           phdr = &snap_phdr;
1258         } else if (choplen > 0) {
1259           snap_phdr = *phdr;
1260           if (phdr->caplen > (unsigned int) choplen) {
1261             snap_phdr.caplen -= choplen;
1262             buf += choplen;
1263           } else
1264             snap_phdr.caplen = 0;
1265           phdr = &snap_phdr;
1266         }
1267
1268         /*
1269          *  Do we adjust timestamps to insure strict chronologically order?
1270          */
1271
1272         if (do_strict_time_adjustment) {
1273           if (previous_time.secs || previous_time.nsecs) {
1274             if (!strict_time_adj.is_negative) {
1275               nstime_t current;
1276               nstime_t delta;
1277
1278               current.secs = phdr->ts.secs;
1279               current.nsecs = phdr->ts.nsecs;
1280
1281               nstime_delta(&delta, &current, &previous_time);
1282
1283               if (delta.secs < 0 || delta.nsecs < 0)
1284               {
1285                 /*
1286                  * A negative delta indicates that the current packet
1287                  * has an absolute timestamp less than the previous packet
1288                  * that it is being compared to.  This is NOT a normal
1289                  * situation since trace files usually have packets in
1290                  * chronological order (oldest to newest).
1291                  */
1292                 /* printf("++out of order, need to adjust this packet!\n"); */
1293                 snap_phdr = *phdr;
1294                 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1295                 snap_phdr.ts.nsecs = previous_time.nsecs;
1296                 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1297                   /* carry */
1298                   snap_phdr.ts.secs++;
1299                   snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1300                 } else {
1301                   snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1302                 }
1303                 phdr = &snap_phdr;
1304               }
1305             } else {
1306               /*
1307                * A negative strict time adjustment is requested.
1308                * Unconditionally set each timestamp to previous
1309                * packet's timestamp plus delta.
1310                */
1311               snap_phdr = *phdr;
1312               snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1313               snap_phdr.ts.nsecs = previous_time.nsecs;
1314               if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1315                 /* carry */
1316                 snap_phdr.ts.secs++;
1317                 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1318               } else {
1319                 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1320               }
1321               phdr = &snap_phdr;
1322             }
1323           }
1324           previous_time.secs = phdr->ts.secs;
1325           previous_time.nsecs = phdr->ts.nsecs;
1326         }
1327
1328         /* assume that if the frame's tv_sec is 0, then
1329          * the timestamp isn't supported */
1330         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1331           snap_phdr = *phdr;
1332           if (time_adj.is_negative)
1333             snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1334           else
1335             snap_phdr.ts.secs += time_adj.tv.tv_sec;
1336           phdr = &snap_phdr;
1337         }
1338
1339         /* assume that if the frame's tv_sec is 0, then
1340          * the timestamp isn't supported */
1341         if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1342           snap_phdr = *phdr;
1343           if (time_adj.is_negative) { /* subtract */
1344             if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1345               snap_phdr.ts.secs--;
1346               snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1347             }
1348             snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1349           } else {                  /* add */
1350             if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1351               /* carry */
1352               snap_phdr.ts.secs++;
1353               snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1354             } else {
1355               snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1356             }
1357           }
1358           phdr = &snap_phdr;
1359         }
1360
1361         /* suppress duplicates by packet window */
1362         if (dup_detect) {
1363           if (is_duplicate(buf, phdr->caplen)) {
1364             if (verbose) {
1365               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1366               for (i = 0; i < 16; i++) {
1367                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1368               }
1369               fprintf(stdout, "\n");
1370             }
1371             duplicate_count++;
1372             count++;
1373             continue;
1374           } else {
1375             if (verbose) {
1376               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1377               for (i = 0; i < 16; i++) {
1378                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1379               }
1380               fprintf(stdout, "\n");
1381             }
1382           }
1383         }
1384
1385         /* suppress duplicates by time window */
1386         if (dup_detect_by_time) {
1387           nstime_t current;
1388
1389           current.secs = phdr->ts.secs;
1390           current.nsecs = phdr->ts.nsecs;
1391
1392           if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1393             if (verbose) {
1394               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1395               for (i = 0; i < 16; i++) {
1396                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1397               }
1398               fprintf(stdout, "\n");
1399             }
1400             duplicate_count++;
1401             count++;
1402             continue;
1403           } else {
1404             if (verbose) {
1405               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1406               for (i = 0; i < 16; i++) {
1407                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1408               }
1409               fprintf(stdout, "\n");
1410             }
1411           }
1412         }
1413
1414         /* Random error mutation */
1415         if (err_prob > 0.0) {
1416           int real_data_start = 0;
1417           /* Protect non-protocol data */
1418           if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1419             real_data_start = find_dct2000_real_data(buf);
1420           }
1421           for (i = real_data_start; i < (int) phdr->caplen; i++) {
1422             if (rand() <= err_prob * RAND_MAX) {
1423               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1424
1425               if (err_type < ERR_WT_BIT) {
1426                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1427                 err_type = ERR_WT_TOTAL;
1428               } else {
1429                 err_type -= ERR_WT_BYTE;
1430               }
1431
1432               if (err_type < ERR_WT_BYTE) {
1433                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1434                 err_type = ERR_WT_TOTAL;
1435               } else {
1436                 err_type -= ERR_WT_BYTE;
1437               }
1438
1439               if (err_type < ERR_WT_ALNUM) {
1440                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1441                 err_type = ERR_WT_TOTAL;
1442               } else {
1443                 err_type -= ERR_WT_ALNUM;
1444               }
1445
1446               if (err_type < ERR_WT_FMT) {
1447                 if ((unsigned int)i < phdr->caplen - 2)
1448                   g_strlcpy((char*) &buf[i], "%s", 2);
1449                 err_type = ERR_WT_TOTAL;
1450               } else {
1451                 err_type -= ERR_WT_FMT;
1452               }
1453
1454               if (err_type < ERR_WT_AA) {
1455                 for (j = i; j < (int) phdr->caplen; j++) {
1456                   buf[j] = 0xAA;
1457                 }
1458                 i = phdr->caplen;
1459               }
1460             }
1461           }
1462         }
1463
1464         if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1465           switch (err) {
1466
1467           case WTAP_ERR_UNSUPPORTED_ENCAP:
1468             /*
1469              * This is a problem with the particular frame we're writing;
1470              * note that, and give the frame number.
1471              */
1472             fprintf(stderr, "editcap: Frame %u of \"%s\" has a network type that can't be saved in a file with that format\n.",
1473                     read_count, argv[optind]);
1474             break;
1475
1476           default:
1477             fprintf(stderr, "editcap: Error writing to %s: %s\n",
1478                     filename, wtap_strerror(err));
1479             break;
1480           }
1481           exit(2);
1482         }
1483         written_count++;
1484       }
1485       count++;
1486     }
1487
1488     g_free(fprefix);
1489     g_free(fsuffix);
1490
1491     if (err != 0) {
1492       /* Print a message noting that the read failed somewhere along the line. */
1493       fprintf(stderr,
1494               "editcap: An error occurred while reading \"%s\": %s.\n",
1495               argv[optind], wtap_strerror(err));
1496       switch (err) {
1497
1498       case WTAP_ERR_UNSUPPORTED:
1499       case WTAP_ERR_UNSUPPORTED_ENCAP:
1500       case WTAP_ERR_BAD_FILE:
1501         fprintf(stderr, "(%s)\n", err_info);
1502         g_free(err_info);
1503         break;
1504       }
1505     }
1506
1507     if (!pdh) {
1508       /* No valid packages found, open the outfile so we can write an empty header */
1509       g_free (filename);
1510       filename = g_strdup(argv[optind+1]);
1511
1512       pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1513         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1514         FALSE /* compressed */, &err);
1515       if (pdh == NULL) {
1516         fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1517         wtap_strerror(err));
1518         exit(2);
1519       }
1520     }
1521
1522     if (!wtap_dump_close(pdh, &err)) {
1523
1524       fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1525           wtap_strerror(err));
1526       exit(2);
1527
1528     }
1529     g_free(shb_hdr);
1530     g_free(filename);
1531   }
1532
1533   if (dup_detect) {
1534     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1535                 count - 1, plurality(count - 1, "", "s"),
1536                 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1537   } else if (dup_detect_by_time) {
1538     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1539                 count - 1, plurality(count - 1, "", "s"),
1540                 duplicate_count, plurality(duplicate_count, "", "s"),
1541                 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1542   }
1543
1544   return 0;
1545 }
1546
1547 /* Skip meta-information read from file to return offset of real
1548    protocol data */
1549 static int find_dct2000_real_data(guint8 *buf)
1550 {
1551   int n=0;
1552
1553   for (n=0; buf[n] != '\0'; n++);   /* Context name */
1554   n++;
1555   n++;                              /* Context port number */
1556   for (; buf[n] != '\0'; n++);      /* Timestamp */
1557   n++;
1558   for (; buf[n] != '\0'; n++);      /* Protocol name */
1559   n++;
1560   for (; buf[n] != '\0'; n++);      /* Variant number (as string) */
1561   n++;
1562   for (; buf[n] != '\0'; n++);      /* Outhdr (as string) */
1563   n++;
1564   n += 2;                           /* Direction & encap */
1565
1566   return n;
1567 }