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