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