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