Renamed reassembled snmp bytes buffer to "Reassembled SMTP".
[obnox/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 <wsutil/unicode-utils.h>
53 #include <process.h>    /* getpid */
54 #ifdef HAVE_WINSOCK2_H
55 #include <winsock2.h>
56 #endif
57 #endif
58
59 #ifdef NEED_STRPTIME_H
60 # include "wsutil/strptime.h"
61 #endif
62
63 #include "epan/crypt/crypt-md5.h"
64 #include "epan/plugins.h"
65 #include "epan/report_err.h"
66 #include "epan/filesystem.h"
67 #include <wsutil/privileges.h>
68 #include "epan/nstime.h"
69
70 #include "svnversion.h"
71
72 /*
73  * Some globals so we can pass things to various routines
74  */
75
76 struct select_item {
77
78   int inclusive;
79   int first, second;
80
81 };
82
83
84 /*
85  * Duplicate frame detection
86  */
87 typedef struct _fd_hash_t {
88   md5_byte_t digest[16];
89   guint32 len;
90   nstime_t time;
91 } fd_hash_t;
92
93 #define DEFAULT_DUP_DEPTH 5     /* Used with -d */
94 #define MAX_DUP_DEPTH 1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
95
96 fd_hash_t fd_hash[MAX_DUP_DEPTH];
97 int dup_window = DEFAULT_DUP_DEPTH;
98 int cur_dup_entry = 0;
99
100 #define ONE_MILLION 1000000
101 #define ONE_BILLION 1000000000
102
103 /* Weights of different errors we can introduce */
104 /* We should probably make these command-line arguments */
105 /* XXX - Should we add a bit-level error? */
106 #define ERR_WT_BIT   5  /* Flip a random bit */
107 #define ERR_WT_BYTE  5  /* Substitute a random byte */
108 #define ERR_WT_ALNUM 5  /* Substitute a random character in [A-Za-z0-9] */
109 #define ERR_WT_FMT   2  /* Substitute "%s" */
110 #define ERR_WT_AA    1  /* Fill the remainder of the buffer with 0xAA */
111 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
112
113 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
114 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
115
116
117 struct time_adjustment {
118   struct timeval tv;
119   int is_negative;
120 };
121
122 #define MAX_SELECTIONS 512
123 static struct select_item selectfrm[MAX_SELECTIONS];
124 static int max_selected = -1;
125 static int keep_em = 0;
126 static int out_file_type = WTAP_FILE_PCAP;   /* default to "libpcap"   */
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 libpcap.\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(((struct string_elem *)a)->sstr,
748         ((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   unsigned int snaplen = 0;             /* No limit               */
822   int choplen = 0;                      /* No chop                */
823   wtap_dumper *pdh = NULL;
824   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   guint8 *buf;
831   int split_packet_count = 0;
832   int written_count = 0;
833   char *filename = NULL;
834   gboolean check_ts;
835   int secs_per_block = 0;
836   int block_cnt = 0;
837   nstime_t block_start;
838   gchar *fprefix = NULL;
839   gchar *fsuffix = NULL;
840
841 #ifdef HAVE_PLUGINS
842   char* init_progfile_dir_error;
843 #endif
844
845 #ifdef _WIN32
846   arg_list_utf_16to8(argc, argv);
847 #endif /* _WIN32 */
848
849   /*
850    * Get credential information for later use.
851    */
852   init_process_policies();
853
854 #ifdef HAVE_PLUGINS
855   /* Register wiretap plugins */
856   if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
857     g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
858     g_free(init_progfile_dir_error);
859   } else {
860     init_report_err(failure_message,NULL,NULL,NULL);
861     init_plugins();
862   }
863 #endif
864
865   /* Process the options */
866   while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:S:T:vw:")) !=-1) {
867
868     switch (opt) {
869
870     case 'E':
871       err_prob = strtod(optarg, &p);
872       if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
873         fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
874             optarg);
875         exit(1);
876       }
877       srand( (unsigned int) (time(NULL) + getpid()) );
878       break;
879
880     case 'F':
881       out_file_type = wtap_short_string_to_file_type(optarg);
882       if (out_file_type < 0) {
883         fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
884             optarg);
885         list_capture_types();
886         exit(1);
887       }
888       break;
889
890     case 'c':
891       split_packet_count = strtol(optarg, &p, 10);
892       if (p == optarg || *p != '\0') {
893         fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
894             optarg);
895         exit(1);
896       }
897       if (split_packet_count <= 0) {
898         fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
899             split_packet_count);
900         exit(1);
901       }
902       break;
903
904     case 'C':
905           choplen = strtol(optarg, &p, 10);
906       if (p == optarg || *p != '\0') {
907         fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
908             optarg);
909         exit(1);
910       }
911       break;
912
913     case 'd':
914       dup_detect = TRUE;
915       dup_detect_by_time = FALSE;
916       dup_window = DEFAULT_DUP_DEPTH;
917       break;
918
919     case 'D':
920       dup_detect = TRUE;
921       dup_detect_by_time = FALSE;
922       dup_window = strtol(optarg, &p, 10);
923       if (p == optarg || *p != '\0') {
924         fprintf(stderr, "editcap: \"%s\" isn't a valid duplicate window value\n",
925             optarg);
926         exit(1);
927       }
928       if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
929         fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
930             dup_window, MAX_DUP_DEPTH);
931         exit(1);
932       }
933       break;
934
935     case 'w':
936       dup_detect = FALSE;
937       dup_detect_by_time = TRUE;
938       dup_window = MAX_DUP_DEPTH;
939       set_rel_time(optarg);
940       break;
941
942     case '?':              /* Bad options if GNU getopt */
943       switch(optopt) {
944       case'F':
945         list_capture_types();
946         break;
947       case'T':
948         list_encap_types();
949         break;
950       default:
951         usage(TRUE);
952       }
953       exit(1);
954       break;
955
956     case 'h':
957       usage(FALSE);
958       exit(1);
959       break;
960
961     case 'r':
962       keep_em = !keep_em;  /* Just invert */
963       break;
964
965     case 's':
966       snaplen = strtol(optarg, &p, 10);
967       if (p == optarg || *p != '\0') {
968         fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
969                 optarg);
970         exit(1);
971       }
972       break;
973
974     case 't':
975       set_time_adjustment(optarg);
976       break;
977
978     case 'S':
979       set_strict_time_adj(optarg);
980       do_strict_time_adjustment = TRUE;
981       break;
982
983     case 'T':
984       out_frame_type = wtap_short_string_to_encap(optarg);
985       if (out_frame_type < 0) {
986         fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
987             optarg);
988         list_encap_types();
989         exit(1);
990       }
991       break;
992
993     case 'v':
994       verbose = !verbose;  /* Just invert */
995       break;
996
997     case 'i': /* break capture file based on time interval */
998       secs_per_block = atoi(optarg);
999       if(secs_per_block <= 0) {
1000         fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
1001         exit(1);
1002         }
1003       break;
1004
1005     case 'A':
1006     {
1007       struct tm starttm;
1008
1009       memset(&starttm,0,sizeof(struct tm));
1010
1011       if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
1012         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1013         exit(1);
1014       }
1015
1016       check_startstop = TRUE;
1017       starttm.tm_isdst = -1;
1018
1019       starttime = mktime(&starttm);
1020       break;
1021     }
1022
1023     case 'B':
1024     {
1025       struct tm stoptm;
1026
1027       memset(&stoptm,0,sizeof(struct tm));
1028
1029       if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
1030         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
1031         exit(1);
1032       }
1033       check_startstop = TRUE;
1034       stoptm.tm_isdst = -1;
1035       stoptime = mktime(&stoptm);
1036       break;
1037     }
1038     }
1039
1040   }
1041
1042 #ifdef DEBUG
1043   printf("Optind = %i, argc = %i\n", optind, argc);
1044 #endif
1045
1046   if ((argc - optind) < 1) {
1047
1048     usage(TRUE);
1049     exit(1);
1050
1051   }
1052
1053   if (check_startstop && !stoptime) {
1054     struct tm stoptm;
1055     /* XXX: will work until 2035 */
1056     memset(&stoptm,0,sizeof(struct tm));
1057     stoptm.tm_year = 135;
1058     stoptm.tm_mday = 31;
1059     stoptm.tm_mon = 11;
1060
1061     stoptime = mktime(&stoptm);
1062   }
1063
1064   nstime_set_unset(&block_start);
1065
1066   if (starttime > stoptime) {
1067     fprintf(stderr, "editcap: start time is after the stop time\n");
1068     exit(1);
1069   }
1070
1071   if (split_packet_count > 0 && secs_per_block > 0) {
1072     fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1073     fprintf(stderr, "editcap: at the same time\n");
1074     exit(1);
1075   }
1076
1077   wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
1078
1079   if (!wth) {
1080     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
1081         wtap_strerror(err));
1082     switch (err) {
1083
1084     case WTAP_ERR_UNSUPPORTED:
1085     case WTAP_ERR_UNSUPPORTED_ENCAP:
1086     case WTAP_ERR_BAD_RECORD:
1087       fprintf(stderr, "(%s)\n", err_info);
1088       g_free(err_info);
1089       break;
1090     }
1091     exit(2);
1092
1093   }
1094
1095   if (verbose) {
1096     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1097             wtap_file_type_string(wtap_file_type(wth)));
1098   }
1099
1100   /*
1101    * Now, process the rest, if any ... we only write if there is an extra
1102    * argument or so ...
1103    */
1104
1105   if ((argc - optind) >= 2) {
1106
1107     if (out_frame_type == -2)
1108       out_frame_type = wtap_file_encap(wth);
1109
1110     for (i = optind + 2; i < argc; i++)
1111       if (add_selection(argv[i]) == FALSE)
1112         break;
1113
1114     if (dup_detect || dup_detect_by_time) {
1115       for (i = 0; i < dup_window; i++) {
1116         memset(&fd_hash[i].digest, 0, 16);
1117         fd_hash[i].len = 0;
1118         nstime_set_unset(&fd_hash[i].time);
1119       }
1120     }
1121
1122     while (wtap_read(wth, &err, &err_info, &data_offset)) {
1123       phdr = wtap_phdr(wth);
1124       buf = wtap_buf_ptr(wth);
1125
1126       if (nstime_is_unset(&block_start)) {  /* should only be the first packet */
1127         block_start.secs = phdr->ts.secs;
1128         block_start.nsecs = phdr->ts.nsecs;
1129
1130         if (split_packet_count > 0 || secs_per_block > 0) {
1131           if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix))
1132               exit(2);
1133
1134           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1135         } else
1136           filename = g_strdup(argv[optind+1]);
1137
1138         pdh = wtap_dump_open(filename, out_file_type,
1139             out_frame_type, wtap_snapshot_length(wth),
1140             FALSE /* compressed */, &err);
1141         if (pdh == NULL) {
1142           fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1143                   wtap_strerror(err));
1144           exit(2);
1145         }
1146       }
1147
1148       g_assert(filename);
1149
1150       if (secs_per_block > 0) {
1151         while ((phdr->ts.secs - block_start.secs >  secs_per_block) ||
1152                (phdr->ts.secs - block_start.secs == secs_per_block &&
1153                 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1154
1155           if (!wtap_dump_close(pdh, &err)) {
1156             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1157                 wtap_strerror(err));
1158             exit(2);
1159           }
1160           block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1161           g_free(filename);
1162           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1163           g_assert(filename);
1164
1165           if (verbose) {
1166             fprintf(stderr, "Continuing writing in file %s\n", filename);
1167           }
1168
1169           pdh = wtap_dump_open(filename, out_file_type,
1170              out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1171
1172           if (pdh == NULL) {
1173             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1174               wtap_strerror(err));
1175             exit(2);
1176           }
1177         }
1178       }
1179
1180       if (split_packet_count > 0) {
1181
1182         /* time for the next file? */
1183         if (written_count > 0 &&
1184             written_count % split_packet_count == 0) {
1185           if (!wtap_dump_close(pdh, &err)) {
1186             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1187                 wtap_strerror(err));
1188             exit(2);
1189           }
1190
1191           g_free(filename);
1192           filename = fileset_get_filename_by_pattern(block_cnt++, &phdr->ts, fprefix, fsuffix);
1193           g_assert(filename);
1194
1195           if (verbose) {
1196             fprintf(stderr, "Continuing writing in file %s\n", filename);
1197           }
1198
1199           pdh = wtap_dump_open(filename, out_file_type,
1200               out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1201           if (pdh == NULL) {
1202             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1203                 wtap_strerror(err));
1204             exit(2);
1205           }
1206         }
1207       }
1208
1209       check_ts = check_timestamp(wth);
1210
1211       if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
1212           (selected(count) && keep_em)) ) {
1213
1214         if (verbose && !dup_detect && !dup_detect_by_time)
1215           printf("Packet: %u\n", count);
1216
1217         /* We simply write it, perhaps after truncating it; we could do other
1218            things, like modify it. */
1219
1220         phdr = wtap_phdr(wth);
1221
1222         if (choplen < 0 && (phdr->caplen + choplen) > 0) {
1223           snap_phdr = *phdr;
1224           snap_phdr.caplen += choplen;
1225           phdr = &snap_phdr;
1226         }
1227
1228         if (choplen > 0 && phdr->caplen > (unsigned int) choplen) {
1229           snap_phdr = *phdr;
1230           snap_phdr.caplen -= choplen;
1231           snap_phdr.len -= choplen;
1232                   buf += choplen;
1233           phdr = &snap_phdr;
1234         }
1235
1236         if (snaplen != 0 && phdr->caplen > snaplen) {
1237           snap_phdr = *phdr;
1238           snap_phdr.caplen = snaplen;
1239           phdr = &snap_phdr;
1240         }
1241
1242         /*
1243          *  Do we adjust timestamps to insure strict chronologically order?
1244          */
1245
1246         if (do_strict_time_adjustment) {
1247           if (previous_time.secs || previous_time.nsecs) {
1248             if (!strict_time_adj.is_negative) {
1249               nstime_t current;
1250               nstime_t delta;
1251
1252               current.secs = phdr->ts.secs;
1253               current.nsecs = phdr->ts.nsecs;
1254
1255               nstime_delta(&delta, &current, &previous_time);
1256
1257               if (delta.secs < 0 || delta.nsecs < 0)
1258               {
1259                 /*
1260                  * A negative delta indicates that the current packet
1261                  * has an absolute timestamp less than the previous packet
1262                  * that it is being compared to.  This is NOT a normal
1263                  * situation since trace files usually have packets in
1264                  * chronological order (oldest to newest).
1265                  */
1266                 /* printf("++out of order, need to adjust this packet!\n"); */
1267                 snap_phdr = *phdr;
1268                 snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1269                 snap_phdr.ts.nsecs = previous_time.nsecs;
1270                 if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1271                   /* carry */
1272                   snap_phdr.ts.secs++;
1273                   snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1274                 } else {
1275                   snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1276                 }
1277                 phdr = &snap_phdr;
1278               }
1279             } else {
1280               /*
1281                * A negative strict time adjustment is requested.
1282                * Unconditionally set each timestamp to previous
1283                * packet's timestamp plus delta.
1284                */
1285               snap_phdr = *phdr;
1286               snap_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.tv_sec;
1287               snap_phdr.ts.nsecs = previous_time.nsecs;
1288               if (snap_phdr.ts.nsecs + strict_time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1289                 /* carry */
1290                 snap_phdr.ts.secs++;
1291                 snap_phdr.ts.nsecs += (strict_time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1292               } else {
1293                 snap_phdr.ts.nsecs += strict_time_adj.tv.tv_usec * 1000;
1294               }
1295               phdr = &snap_phdr;
1296             }
1297           }
1298           previous_time.secs = phdr->ts.secs;
1299           previous_time.nsecs = phdr->ts.nsecs;
1300         }
1301
1302         /* assume that if the frame's tv_sec is 0, then
1303          * the timestamp isn't supported */
1304         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1305           snap_phdr = *phdr;
1306           if (time_adj.is_negative)
1307             snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1308           else
1309             snap_phdr.ts.secs += time_adj.tv.tv_sec;
1310           phdr = &snap_phdr;
1311         }
1312
1313         /* assume that if the frame's tv_sec is 0, then
1314          * the timestamp isn't supported */
1315         if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1316           snap_phdr = *phdr;
1317           if (time_adj.is_negative) { /* subtract */
1318             if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1319               snap_phdr.ts.secs--;
1320               snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1321             }
1322             snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1323           } else {                  /* add */
1324             if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1325               /* carry */
1326               snap_phdr.ts.secs++;
1327               snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1328             } else {
1329               snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1330             }
1331           }
1332           phdr = &snap_phdr;
1333         }
1334
1335         /* suppress duplicates by packet window */
1336         if (dup_detect) {
1337           if (is_duplicate(buf, phdr->caplen)) {
1338             if (verbose) {
1339               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1340               for (i = 0; i < 16; i++) {
1341                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1342               }
1343               fprintf(stdout, "\n");
1344             }
1345             duplicate_count++;
1346             count++;
1347             continue;
1348           } else {
1349             if (verbose) {
1350               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1351               for (i = 0; i < 16; i++) {
1352                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1353               }
1354               fprintf(stdout, "\n");
1355             }
1356           }
1357         }
1358
1359         /* suppress duplicates by time window */
1360         if (dup_detect_by_time) {
1361           nstime_t current;
1362
1363           current.secs = phdr->ts.secs;
1364           current.nsecs = phdr->ts.nsecs;
1365
1366           if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1367             if (verbose) {
1368               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1369               for (i = 0; i < 16; i++) {
1370                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1371               }
1372               fprintf(stdout, "\n");
1373             }
1374             duplicate_count++;
1375             count++;
1376             continue;
1377           } else {
1378             if (verbose) {
1379               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1380               for (i = 0; i < 16; i++) {
1381                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1382               }
1383               fprintf(stdout, "\n");
1384             }
1385           }
1386         }
1387
1388         /* Random error mutation */
1389         if (err_prob > 0.0) {
1390           int real_data_start = 0;
1391           /* Protect non-protocol data */
1392           if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1393             real_data_start = find_dct2000_real_data(buf);
1394           }
1395           for (i = real_data_start; i < (int) phdr->caplen; i++) {
1396             if (rand() <= err_prob * RAND_MAX) {
1397               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1398
1399               if (err_type < ERR_WT_BIT) {
1400                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1401                 err_type = ERR_WT_TOTAL;
1402               } else {
1403                 err_type -= ERR_WT_BYTE;
1404               }
1405
1406               if (err_type < ERR_WT_BYTE) {
1407                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1408                 err_type = ERR_WT_TOTAL;
1409               } else {
1410                 err_type -= ERR_WT_BYTE;
1411               }
1412
1413               if (err_type < ERR_WT_ALNUM) {
1414                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1415                 err_type = ERR_WT_TOTAL;
1416               } else {
1417                 err_type -= ERR_WT_ALNUM;
1418               }
1419
1420               if (err_type < ERR_WT_FMT) {
1421                 if ((unsigned int)i < phdr->caplen - 2)
1422                   strncpy((char*) &buf[i],  "%s", 2);
1423                 err_type = ERR_WT_TOTAL;
1424               } else {
1425                 err_type -= ERR_WT_FMT;
1426               }
1427
1428               if (err_type < ERR_WT_AA) {
1429                 for (j = i; j < (int) phdr->caplen; j++) {
1430                   buf[j] = 0xAA;
1431                 }
1432                 i = phdr->caplen;
1433               }
1434             }
1435           }
1436         }
1437
1438         if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), buf, &err)) {
1439           fprintf(stderr, "editcap: Error writing to %s: %s\n",
1440                   filename, wtap_strerror(err));
1441           exit(2);
1442         }
1443         written_count++;
1444       }
1445       count++;
1446     }
1447
1448     g_free(fprefix);
1449     g_free(fsuffix);
1450
1451     if (err != 0) {
1452       /* Print a message noting that the read failed somewhere along the line. */
1453       fprintf(stderr,
1454               "editcap: An error occurred while reading \"%s\": %s.\n",
1455               argv[optind], wtap_strerror(err));
1456       switch (err) {
1457
1458       case WTAP_ERR_UNSUPPORTED:
1459       case WTAP_ERR_UNSUPPORTED_ENCAP:
1460       case WTAP_ERR_BAD_RECORD:
1461         fprintf(stderr, "(%s)\n", err_info);
1462         g_free(err_info);
1463         break;
1464       }
1465     }
1466
1467     if (!pdh) {
1468       /* No valid packages found, open the outfile so we can write an empty header */
1469       g_free (filename);
1470       filename = g_strdup(argv[optind+1]);
1471
1472       pdh = wtap_dump_open(filename, out_file_type,
1473                            out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
1474       if (pdh == NULL) {
1475         fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
1476                 wtap_strerror(err));
1477         exit(2);
1478       }
1479     }
1480
1481     if (!wtap_dump_close(pdh, &err)) {
1482
1483       fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1484           wtap_strerror(err));
1485       exit(2);
1486
1487     }
1488     g_free(filename);
1489   }
1490
1491   if (dup_detect) {
1492     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1493                 count - 1, plurality(count - 1, "", "s"),
1494                 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1495   } else if (dup_detect_by_time) {
1496     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1497                 count - 1, plurality(count - 1, "", "s"),
1498                 duplicate_count, plurality(duplicate_count, "", "s"),
1499                 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1500   }
1501
1502   return 0;
1503 }
1504
1505 /* Skip meta-information read from file to return offset of real
1506    protocol data */
1507 static int find_dct2000_real_data(guint8 *buf)
1508 {
1509   int n=0;
1510
1511   for (n=0; buf[n] != '\0'; n++);   /* Context name */
1512   n++;
1513   n++;                              /* Context port number */
1514   for (; buf[n] != '\0'; n++);      /* Timestamp */
1515   n++;
1516   for (; buf[n] != '\0'; n++);      /* Protocol name */
1517   n++;
1518   for (; buf[n] != '\0'; n++);      /* Variant number (as string) */
1519   n++;
1520   for (; buf[n] != '\0'; n++);      /* Outhdr (as string) */
1521   n++;
1522   n += 2;                           /* Direction & encap */
1523
1524   return n;
1525 }