A modified version of "pcapng: shd_userappl in newly created files"
[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
1153         pdh = wtap_dump_open_ng(filename, out_file_type, out_frame_type,
1154           snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1155           FALSE /* compressed */, shb_hdr, idb_inf, &err);
1156         if (pdh == NULL) {
1157           fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1158                   wtap_strerror(err));
1159           exit(2);
1160         }
1161       }
1162
1163       g_assert(filename);
1164
1165       if (secs_per_block > 0) {
1166         while ((phdr->ts.secs - block_start.secs >  secs_per_block) ||
1167                (phdr->ts.secs - block_start.secs == secs_per_block &&
1168                 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1169
1170           if (!wtap_dump_close(pdh, &err)) {
1171             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1172                 wtap_strerror(err));
1173             exit(2);
1174           }
1175           block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1176           g_free(filename);
1177           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1178           g_assert(filename);
1179
1180           if (verbose) {
1181             fprintf(stderr, "Continuing writing in file %s\n", filename);
1182           }
1183
1184           pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1185             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1186             FALSE /* compressed */, &err);
1187
1188           if (pdh == NULL) {
1189             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1190               wtap_strerror(err));
1191             exit(2);
1192           }
1193         }
1194       }
1195
1196       if (split_packet_count > 0) {
1197
1198         /* time for the next file? */
1199         if (written_count > 0 &&
1200             written_count % split_packet_count == 0) {
1201           if (!wtap_dump_close(pdh, &err)) {
1202             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1203                 wtap_strerror(err));
1204             exit(2);
1205           }
1206
1207           g_free(filename);
1208           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1209           g_assert(filename);
1210
1211           if (verbose) {
1212             fprintf(stderr, "Continuing writing in file %s\n", filename);
1213           }
1214
1215           pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1216             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1217             FALSE /* compressed */, &err);
1218           if (pdh == NULL) {
1219             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1220                 wtap_strerror(err));
1221             exit(2);
1222           }
1223         }
1224       }
1225
1226       if (check_startstop)
1227         ts_okay = check_timestamp(wth);
1228
1229       if ( ts_okay && ((!selected(count) && !keep_em) || (selected(count) && keep_em)) ) {
1230
1231         if (verbose && !dup_detect && !dup_detect_by_time)
1232           printf("Packet: %u\n", count);
1233
1234         /* We simply write it, perhaps after truncating it; we could do other
1235            things, like modify it. */
1236
1237         phdr = wtap_phdr(wth);
1238
1239         if (snaplen != 0 && phdr->caplen > snaplen) {
1240           snap_phdr = *phdr;
1241           snap_phdr.caplen = snaplen;
1242           phdr = &snap_phdr;
1243         }
1244
1245         if (choplen < 0) {
1246           snap_phdr = *phdr;
1247           if (((signed int) phdr->caplen + choplen) > 0)
1248             snap_phdr.caplen += choplen;
1249           else
1250             snap_phdr.caplen = 0;
1251           phdr = &snap_phdr;
1252         } else if (choplen > 0) {
1253           snap_phdr = *phdr;
1254           if (phdr->caplen > (unsigned int) choplen) {
1255             snap_phdr.caplen -= choplen;
1256             buf += choplen;
1257           } else
1258             snap_phdr.caplen = 0;
1259           phdr = &snap_phdr;
1260         }
1261
1262         /*
1263          *  Do we adjust timestamps to insure strict chronologically order?
1264          */
1265
1266         if (do_strict_time_adjustment) {
1267           if (previous_time.secs || previous_time.nsecs) {
1268             if (!strict_time_adj.is_negative) {
1269               nstime_t current;
1270               nstime_t delta;
1271
1272               current.secs = phdr->ts.secs;
1273               current.nsecs = phdr->ts.nsecs;
1274
1275               nstime_delta(&delta, &current, &previous_time);
1276
1277               if (delta.secs < 0 || delta.nsecs < 0)
1278               {
1279                 /*
1280                  * A negative delta indicates that the current packet
1281                  * has an absolute timestamp less than the previous packet
1282                  * that it is being compared to.  This is NOT a normal
1283                  * situation since trace files usually have packets in
1284                  * chronological order (oldest to newest).
1285                  */
1286                 /* printf("++out of order, need to adjust this packet!\n"); */
1287                 snap_phdr = *phdr;
1288                 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1289                 snap_phdr.ts.nsecs = previous_time.nsecs;
1290                 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1291                   /* carry */
1292                   snap_phdr.ts.secs++;
1293                   snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1294                 } else {
1295                   snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1296                 }
1297                 phdr = &snap_phdr;
1298               }
1299             } else {
1300               /*
1301                * A negative strict time adjustment is requested.
1302                * Unconditionally set each timestamp to previous
1303                * packet's timestamp plus delta.
1304                */
1305               snap_phdr = *phdr;
1306               snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1307               snap_phdr.ts.nsecs = previous_time.nsecs;
1308               if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1309                 /* carry */
1310                 snap_phdr.ts.secs++;
1311                 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1312               } else {
1313                 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1314               }
1315               phdr = &snap_phdr;
1316             }
1317           }
1318           previous_time.secs = phdr->ts.secs;
1319           previous_time.nsecs = phdr->ts.nsecs;
1320         }
1321
1322         /* assume that if the frame's tv_sec is 0, then
1323          * the timestamp isn't supported */
1324         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1325           snap_phdr = *phdr;
1326           if (time_adj.is_negative)
1327             snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1328           else
1329             snap_phdr.ts.secs += time_adj.tv.tv_sec;
1330           phdr = &snap_phdr;
1331         }
1332
1333         /* assume that if the frame's tv_sec is 0, then
1334          * the timestamp isn't supported */
1335         if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1336           snap_phdr = *phdr;
1337           if (time_adj.is_negative) { /* subtract */
1338             if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1339               snap_phdr.ts.secs--;
1340               snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1341             }
1342             snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1343           } else {                  /* add */
1344             if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1345               /* carry */
1346               snap_phdr.ts.secs++;
1347               snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1348             } else {
1349               snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1350             }
1351           }
1352           phdr = &snap_phdr;
1353         }
1354
1355         /* suppress duplicates by packet window */
1356         if (dup_detect) {
1357           if (is_duplicate(buf, phdr->caplen)) {
1358             if (verbose) {
1359               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1360               for (i = 0; i < 16; i++) {
1361                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1362               }
1363               fprintf(stdout, "\n");
1364             }
1365             duplicate_count++;
1366             count++;
1367             continue;
1368           } else {
1369             if (verbose) {
1370               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1371               for (i = 0; i < 16; i++) {
1372                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1373               }
1374               fprintf(stdout, "\n");
1375             }
1376           }
1377         }
1378
1379         /* suppress duplicates by time window */
1380         if (dup_detect_by_time) {
1381           nstime_t current;
1382
1383           current.secs = phdr->ts.secs;
1384           current.nsecs = phdr->ts.nsecs;
1385
1386           if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1387             if (verbose) {
1388               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1389               for (i = 0; i < 16; i++) {
1390                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1391               }
1392               fprintf(stdout, "\n");
1393             }
1394             duplicate_count++;
1395             count++;
1396             continue;
1397           } else {
1398             if (verbose) {
1399               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1400               for (i = 0; i < 16; i++) {
1401                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1402               }
1403               fprintf(stdout, "\n");
1404             }
1405           }
1406         }
1407
1408         /* Random error mutation */
1409         if (err_prob > 0.0) {
1410           int real_data_start = 0;
1411           /* Protect non-protocol data */
1412           if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1413             real_data_start = find_dct2000_real_data(buf);
1414           }
1415           for (i = real_data_start; i < (int) phdr->caplen; i++) {
1416             if (rand() <= err_prob * RAND_MAX) {
1417               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1418
1419               if (err_type < ERR_WT_BIT) {
1420                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1421                 err_type = ERR_WT_TOTAL;
1422               } else {
1423                 err_type -= ERR_WT_BYTE;
1424               }
1425
1426               if (err_type < ERR_WT_BYTE) {
1427                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1428                 err_type = ERR_WT_TOTAL;
1429               } else {
1430                 err_type -= ERR_WT_BYTE;
1431               }
1432
1433               if (err_type < ERR_WT_ALNUM) {
1434                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1435                 err_type = ERR_WT_TOTAL;
1436               } else {
1437                 err_type -= ERR_WT_ALNUM;
1438               }
1439
1440               if (err_type < ERR_WT_FMT) {
1441                 if ((unsigned int)i < phdr->caplen - 2)
1442                   g_strlcpy((char*) &buf[i], "%s", 2);
1443                 err_type = ERR_WT_TOTAL;
1444               } else {
1445                 err_type -= ERR_WT_FMT;
1446               }
1447
1448               if (err_type < ERR_WT_AA) {
1449                 for (j = i; j < (int) phdr->caplen; j++) {
1450                   buf[j] = 0xAA;
1451                 }
1452                 i = phdr->caplen;
1453               }
1454             }
1455           }
1456         }
1457
1458         if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1459           switch (err) {
1460
1461           case WTAP_ERR_UNSUPPORTED_ENCAP:
1462             /*
1463              * This is a problem with the particular frame we're writing;
1464              * note that, and give the frame number.
1465              */
1466             fprintf(stderr, "editcap: Frame %u of \"%s\" has a network type that can't be saved in a file with that format\n.",
1467                     read_count, argv[optind]);
1468             break;
1469
1470           default:
1471             fprintf(stderr, "editcap: Error writing to %s: %s\n",
1472                     filename, wtap_strerror(err));
1473             break;
1474           }
1475           exit(2);
1476         }
1477         written_count++;
1478       }
1479       count++;
1480     }
1481
1482     g_free(fprefix);
1483     g_free(fsuffix);
1484
1485     if (err != 0) {
1486       /* Print a message noting that the read failed somewhere along the line. */
1487       fprintf(stderr,
1488               "editcap: An error occurred while reading \"%s\": %s.\n",
1489               argv[optind], wtap_strerror(err));
1490       switch (err) {
1491
1492       case WTAP_ERR_UNSUPPORTED:
1493       case WTAP_ERR_UNSUPPORTED_ENCAP:
1494       case WTAP_ERR_BAD_FILE:
1495         fprintf(stderr, "(%s)\n", err_info);
1496         g_free(err_info);
1497         break;
1498       }
1499     }
1500
1501     if (!pdh) {
1502       /* No valid packages found, open the outfile so we can write an empty header */
1503       g_free (filename);
1504       filename = g_strdup(argv[optind+1]);
1505
1506       pdh = wtap_dump_open(filename, out_file_type, out_frame_type,
1507         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1508         FALSE /* compressed */, &err);
1509       if (pdh == NULL) {
1510         fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1511         wtap_strerror(err));
1512         exit(2);
1513       }
1514     }
1515
1516     if (!wtap_dump_close(pdh, &err)) {
1517
1518       fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1519           wtap_strerror(err));
1520       exit(2);
1521
1522     }
1523     g_free(idb_inf);
1524     g_free(shb_hdr);
1525     g_free(filename);
1526   }
1527
1528   if (dup_detect) {
1529     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1530                 count - 1, plurality(count - 1, "", "s"),
1531                 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1532   } else if (dup_detect_by_time) {
1533     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1534                 count - 1, plurality(count - 1, "", "s"),
1535                 duplicate_count, plurality(duplicate_count, "", "s"),
1536                 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1537   }
1538
1539   return 0;
1540 }
1541
1542 /* Skip meta-information read from file to return offset of real
1543    protocol data */
1544 static int find_dct2000_real_data(guint8 *buf)
1545 {
1546   int n=0;
1547
1548   for (n=0; buf[n] != '\0'; n++);   /* Context name */
1549   n++;
1550   n++;                              /* Context port number */
1551   for (; buf[n] != '\0'; n++);      /* Timestamp */
1552   n++;
1553   for (; buf[n] != '\0'; n++);      /* Protocol name */
1554   n++;
1555   for (; buf[n] != '\0'; n++);      /* Variant number (as string) */
1556   n++;
1557   for (; buf[n] != '\0'; n++);      /* Outhdr (as string) */
1558   n++;
1559   n += 2;                           /* Direction & encap */
1560
1561   return n;
1562 }