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