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