Minor cleanup of "-h" output text.
[obnox/wireshark/wip.git] / editcap.c
1 /* Edit capture files.  We can delete packets, adjust timestamps, or
2  * simply convert from one format to another format.
3  *
4  * $Id$
5  *
6  * Originally written by Richard Sharpe.
7  * Improved by Guy Harris.
8  * Further improved by Richard Sharpe.
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdarg.h>
19
20 /*
21  * Just make sure we include the prototype for strptime as well
22  * (needed for glibc 2.2) but make sure we do this only if not
23  * yet defined.
24  */
25
26 #ifndef __USE_XOPEN
27 #  define __USE_XOPEN
28 #endif
29
30 #include <time.h>
31 #include <glib.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37
38
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42
43 #include "wtap.h"
44
45 #ifdef NEED_GETOPT_H
46 #include "getopt.h"
47 #endif
48
49 #ifdef _WIN32
50 #include <process.h>    /* getpid */
51 #ifdef HAVE_WINSOCK2_H
52 #include <winsock2.h>
53 #endif
54 #endif
55
56 #ifdef NEED_STRPTIME_H
57 # include "strptime.h"
58 #endif
59
60 #include "epan/crypt/crypt-md5.h"
61 #include "epan/plugins.h"
62 #include "epan/report_err.h"
63 #include "epan/filesystem.h"
64 #include <wsutil/privileges.h>
65 #include "epan/nstime.h"
66
67 #include "svnversion.h"
68
69 /*
70  * Some globals so we can pass things to various routines
71  */
72
73 struct select_item {
74
75   int inclusive;
76   int first, second;
77
78 };
79
80
81 /*
82  * Duplicate frame detection
83  */
84 typedef struct _fd_hash_t {
85   md5_byte_t digest[16];
86   guint32 len;
87   nstime_t time;
88 } fd_hash_t;
89
90 #define DEFAULT_DUP_DEPTH 5     /* Used with -d */
91 #define MAX_DUP_DEPTH 1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
92
93 fd_hash_t fd_hash[MAX_DUP_DEPTH];
94 int dup_window = DEFAULT_DUP_DEPTH;
95 int cur_dup_entry = 0;
96
97 #define ONE_MILLION 1000000
98 #define ONE_BILLION 1000000000
99
100 /* Weights of different errors we can introduce */
101 /* We should probably make these command-line arguments */
102 /* XXX - Should we add a bit-level error? */
103 #define ERR_WT_BIT   5  /* Flip a random bit */
104 #define ERR_WT_BYTE  5  /* Substitute a random byte */
105 #define ERR_WT_ALNUM 5  /* Substitute a random character in [A-Za-z0-9] */
106 #define ERR_WT_FMT   2  /* Substitute "%s" */
107 #define ERR_WT_AA    1  /* Fill the remainder of the buffer with 0xAA */
108 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
109
110 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
111 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
112
113
114 struct time_adjustment {
115   struct timeval tv;
116   int is_negative;
117 };
118
119 #define MAX_SELECTIONS 512
120 static struct select_item selectfrm[MAX_SELECTIONS];
121 static int max_selected = -1;
122 static int keep_em = 0;
123 static int out_file_type = WTAP_FILE_PCAP;   /* default to "libpcap"   */
124 static int out_frame_type = -2;              /* Leave frame type alone */
125 static int verbose = 0;                      /* Not so verbose         */
126 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
127 static nstime_t relative_time_window = {0, 0}; /* de-dup time window */
128 static double err_prob = 0.0;
129 static time_t starttime = 0;
130 static time_t stoptime = 0;
131 static gboolean check_startstop = FALSE;
132 static gboolean dup_detect = FALSE;
133 static gboolean dup_detect_by_time = FALSE;
134
135 static int find_dct2000_real_data(guint8 *buf);
136
137 /* Add a selection item, a simple parser for now */
138 static gboolean
139 add_selection(char *sel)
140 {
141   char *locn;
142   char *next;
143
144   if (++max_selected >= MAX_SELECTIONS) {
145     /* Let the user know we stopped selecting */
146     printf("Out of room for packet selections!\n");
147     return(FALSE);
148   }
149
150   printf("Add_Selected: %s\n", sel);
151
152   if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
153
154     printf("Not inclusive ...");
155
156     selectfrm[max_selected].inclusive = 0;
157     selectfrm[max_selected].first = atoi(sel);
158
159     printf(" %i\n", selectfrm[max_selected].first);
160
161   }
162   else {
163
164     printf("Inclusive ...");
165
166     next = locn + 1;
167     selectfrm[max_selected].inclusive = 1;
168     selectfrm[max_selected].first = atoi(sel);
169     selectfrm[max_selected].second = atoi(next);
170
171     printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
172
173   }
174
175   return(TRUE);
176 }
177
178 /* Was the packet selected? */
179
180 static int
181 selected(int recno)
182 {
183   int i = 0;
184
185   for (i = 0; i<= max_selected; i++) {
186
187     if (selectfrm[i].inclusive) {
188       if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
189         return 1;
190     }
191     else {
192       if (recno == selectfrm[i].first)
193         return 1;
194     }
195   }
196
197   return 0;
198
199 }
200
201 /* is the packet in the selected timeframe */
202 static gboolean
203 check_timestamp(wtap *wth)
204 {
205   struct wtap_pkthdr* pkthdr = wtap_phdr(wth);
206
207   return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs <= stoptime );
208 }
209
210 static void
211 set_time_adjustment(char *optarg)
212 {
213   char *frac, *end;
214   long val;
215   size_t frac_digits;
216
217   if (!optarg)
218     return;
219
220   /* skip leading whitespace */
221   while (*optarg == ' ' || *optarg == '\t') {
222       optarg++;
223   }
224
225   /* check for a negative adjustment */
226   if (*optarg == '-') {
227       time_adj.is_negative = 1;
228       optarg++;
229   }
230
231   /* collect whole number of seconds, if any */
232   if (*optarg == '.') {         /* only fractional (i.e., .5 is ok) */
233       val  = 0;
234       frac = optarg;
235   } else {
236       val = strtol(optarg, &frac, 10);
237       if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
238           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
239                   optarg);
240           exit(1);
241       }
242       if (val < 0) {            /* implies '--' since we caught '-' above  */
243           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
244                   optarg);
245           exit(1);
246       }
247   }
248   time_adj.tv.tv_sec = val;
249
250   /* now collect the partial seconds, if any */
251   if (*frac != '\0') {             /* chars left, so get fractional part */
252     val = strtol(&(frac[1]), &end, 10);
253     if (*frac != '.' || end == NULL || end == frac
254         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
255       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
256               optarg);
257       exit(1);
258     }
259   }
260   else {
261     return;                     /* no fractional digits */
262   }
263
264   /* adjust fractional portion from fractional to numerator
265    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
266   if (frac && end) {            /* both are valid */
267     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
268     while(frac_digits < 6) {    /* this is frac of 10^6 */
269       val *= 10;
270       frac_digits++;
271     }
272   }
273   time_adj.tv.tv_usec = val;
274 }
275
276 static void
277 set_rel_time(char *optarg)
278 {
279   char *frac, *end;
280   long val;
281   size_t frac_digits;
282
283   if (!optarg)
284     return;
285
286   /* skip leading whitespace */
287   while (*optarg == ' ' || *optarg == '\t') {
288       optarg++;
289   }
290
291   /* ignore negative adjustment  */
292   if (*optarg == '-') {
293       optarg++;
294   }
295
296   /* collect whole number of seconds, if any */
297   if (*optarg == '.') {         /* only fractional (i.e., .5 is ok) */
298       val  = 0;
299       frac = optarg;
300   } else {
301       val = strtol(optarg, &frac, 10);
302       if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
303           fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
304                   optarg);
305           exit(1);
306       }
307       if (val < 0) {            /* implies '--' since we caught '-' above  */
308           fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
309                   optarg);
310           exit(1);
311       }
312   }
313   relative_time_window.secs = val;
314
315   /* now collect the partial seconds, if any */
316   if (*frac != '\0') {             /* chars left, so get fractional part */
317     val = strtol(&(frac[1]), &end, 10);
318     if (*frac != '.' || end == NULL || end == frac
319         || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
320       fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
321               optarg);
322       exit(1);
323     }
324   }
325   else {
326     return;                     /* no fractional digits */
327   }
328
329   /* adjust fractional portion from fractional to numerator
330    * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
331   if (frac && end) {            /* both are valid */
332     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
333     while(frac_digits < 9) {    /* this is frac of 10^9 */
334       val *= 10;
335       frac_digits++;
336     }
337   }
338   relative_time_window.nsecs = val;
339 }
340
341 static gboolean
342 is_duplicate(guint8* fd, guint32 len) {
343   int i;
344   md5_state_t ms;
345
346   cur_dup_entry++;
347   if (cur_dup_entry >= dup_window)
348     cur_dup_entry = 0;
349
350   /* Calculate our digest */
351   md5_init(&ms);
352   md5_append(&ms, fd, len);
353   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
354
355   fd_hash[cur_dup_entry].len = len;
356
357   /* Look for duplicates */
358   for (i = 0; i < dup_window; i++) {
359     if (i == cur_dup_entry)
360       continue;
361
362     if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
363         memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
364       return TRUE;
365     }
366   }
367
368   return FALSE;
369 }
370
371 static gboolean
372 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
373   int i;
374   md5_state_t ms;
375
376   cur_dup_entry++;
377   if (cur_dup_entry >= dup_window)
378     cur_dup_entry = 0;
379
380   /* Calculate our digest */
381   md5_init(&ms);
382   md5_append(&ms, fd, len);
383   md5_finish(&ms, fd_hash[cur_dup_entry].digest);
384
385   fd_hash[cur_dup_entry].len = len;
386   fd_hash[cur_dup_entry].time.secs = current->secs;
387   fd_hash[cur_dup_entry].time.nsecs = current->nsecs;
388
389   /*
390    * Look for relative time related duplicates.
391    * This is hopefully a reasonably efficient mechanism for
392    * finding duplicates by rel time in the fd_hash[] cache.
393    * We check starting from the most recently added hash
394    * entries and work backwards towards older packets.
395    * This approach allows the dup test to be terminated
396    * when the relative time of a cached entry is found to
397    * be beyond the dup time window.
398    *
399    * Of course this assumes that the input trace file is
400    * "well-formed" in the sense that the packet timestamps are
401    * in strict chronologically increasing order (which is NOT
402    * always the case!!).
403    *
404    * The fd_hash[] table was deliberatly created large (1,000,000).
405    * Looking for time related duplicates in large trace files with
406    * non-fractional dup time window values can potentially take
407    * a long time to complete.
408    */
409
410   for (i = cur_dup_entry - 1;; i--) {
411     nstime_t delta;
412     int cmp;
413
414     if (i < 0) {
415       i = dup_window - 1;
416     }
417
418     if (i == cur_dup_entry) {
419       /*
420        * We've decremented back to where we started.
421        * Check no more!
422        */
423       break;
424     }
425
426     if (nstime_is_unset(&(fd_hash[i].time))) {
427       /*
428        * We've decremented to an unused fd_hash[] entry.
429        * Check no more!
430        */
431       break;
432     }
433
434     nstime_delta(&delta, current, &fd_hash[i].time);
435
436     if(delta.secs < 0 || delta.nsecs < 0)
437     {
438       /*
439        * A negative delta implies that the current packet
440        * has an absolute timestamp less than the cached packet
441        * that it is being compared to.  This is NOT a normal
442        * situation since trace files usually have packets in
443        * chronological order (oldest to newest).
444        *
445        * There are several possible ways to deal with this:
446        * 1. 'continue' dup checking with the next cached frame.
447        * 2. 'break' from looking for a duplicate of the current frame.
448        * 3. Take the absolute value of the delta and see if that
449        * falls within the specifed dup time window.
450        *
451        * Currently this code does option 1.  But it would pretty
452        * easy to add yet-another-editcap-option to select one of
453        * the other behaviors for dealing with out-of-sequence
454        * packets.
455        */
456       continue;
457     }
458
459     cmp = nstime_cmp(&delta, &relative_time_window);
460
461     if(cmp > 0) {
462       /*
463        * The delta time indicates that we are now looking at
464        * cached packets beyond the specified dup time window.
465        * Check no more!
466        */
467       break;
468     } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len &&
469           memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
470       return TRUE;
471     }
472   }
473
474   return FALSE;
475 }
476
477 static void
478 usage(void)
479 {
480   fprintf(stderr, "Editcap %s"
481 #ifdef SVNVERSION
482           " (" SVNVERSION ")"
483 #endif
484           "\n", VERSION);
485   fprintf(stderr, "Edit and/or translate the format of capture files.\n");
486   fprintf(stderr, "See http://www.wireshark.org for more information.\n");
487   fprintf(stderr, "\n");
488   fprintf(stderr, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
489   fprintf(stderr, "\n");
490   fprintf(stderr, "<infile> and <outfile> must both be present.\n");
491   fprintf(stderr, "A single packet or a range of packets can be selected.\n");
492   fprintf(stderr, "\n");
493   fprintf(stderr, "Packet selection:\n");
494   fprintf(stderr, "  -r                     keep the selected packets; default is to delete them.\n");
495   fprintf(stderr, "  -A <start time>        don't output packets whose timestamp is before the\n");
496   fprintf(stderr, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
497   fprintf(stderr, "  -B <stop time>         don't output packets whose timestamp is after the\n");
498   fprintf(stderr, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
499   fprintf(stderr, "\n");
500   fprintf(stderr, "Duplicate packet removal:\n");
501   fprintf(stderr, "  -d                     remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
502   fprintf(stderr, "  -D <dup window>        remove packet if duplicate; configurable <dup window>\n");
503   fprintf(stderr, "                         Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
504   fprintf(stderr, "                         NOTE: A <dup window> of 0 with -v (verbose option) is\n");
505   fprintf(stderr, "                         useful to print MD5 hashes.\n");
506   fprintf(stderr, "  -w <dup time window>   remove packet if duplicate packet is found EQUAL TO OR\n");
507   fprintf(stderr, "                         LESS THAN <dup time window> prior to current packet.\n");
508   fprintf(stderr, "                         A <dup time window> is specified in relative seconds\n");
509   fprintf(stderr, "                         (e.g. 0.000001).\n");
510   fprintf(stderr, "\n");
511   fprintf(stderr, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
512   fprintf(stderr, "           other editcap options except -v may not always work as expected.\n");
513   fprintf(stderr, "           Specifically the -r and -t options will very likely NOT have the\n");
514   fprintf(stderr, "           desired effect if combined with the -d, -D or -w.\n");
515   fprintf(stderr, "\n");
516   fprintf(stderr, "Packet manipulation:\n");
517   fprintf(stderr, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
518   fprintf(stderr, "  -C <choplen>           chop each packet at the end by <choplen> bytes.\n");
519   fprintf(stderr, "  -t <time adjustment>   adjust the timestamp of each packet;\n");
520   fprintf(stderr, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
521   fprintf(stderr, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.)\n");
522   fprintf(stderr, "                         that a particular packet byte will be randomly changed.\n");
523   fprintf(stderr, "\n");
524   fprintf(stderr, "Output File(s):\n");
525   fprintf(stderr, "  -c <packets per file>  split the packet output to different files\n");
526   fprintf(stderr, "                         based on uniform packet counts\n");
527   fprintf(stderr, "                         with a maximum of <packets per file> each.\n");
528   fprintf(stderr, "  -i <seconds per file>  split the packet output to different files\n");
529   fprintf(stderr, "                         based on uniform time intervals\n");
530   fprintf(stderr, "                         with a maximum of <seconds per file> each.\n");
531   fprintf(stderr, "  -F <capture type>      set the output file type; default is libpcap.\n");
532   fprintf(stderr, "                         an empty \"-F\" option will list the file types.\n");
533   fprintf(stderr, "  -T <encap type>        set the output file encapsulation type;\n");
534   fprintf(stderr, "                         default is the same as the input file.\n");
535   fprintf(stderr, "                         an empty \"-T\" option will list the encapsulation types.\n");
536   fprintf(stderr, "\n");
537   fprintf(stderr, "Miscellaneous:\n");
538   fprintf(stderr, "  -h                     display this help and exit.\n");
539   fprintf(stderr, "  -v                     verbose output.\n");
540   fprintf(stderr, "                         If -v is used with any of the 'Duplicate Packet\n");
541   fprintf(stderr, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
542   fprintf(stderr, "                         and MD5 hashes are printed to standard-out.\n");
543   fprintf(stderr, "\n");
544 }
545
546 static void
547 list_capture_types(void) {
548     int i;
549
550     fprintf(stderr, "editcap: The available capture file types for \"F\":\n");
551     for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
552       if (wtap_dump_can_open(i))
553         fprintf(stderr, "    %s - %s\n",
554           wtap_file_type_short_string(i), wtap_file_type_string(i));
555     }
556 }
557
558 static void
559 list_encap_types(void) {
560     int i;
561     const char *string;
562
563     fprintf(stderr, "editcap: The available encapsulation types for \"T\":\n");
564     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
565         string = wtap_encap_short_string(i);
566         if (string != NULL)
567           fprintf(stderr, "    %s - %s\n",
568             string, wtap_encap_string(i));
569     }
570 }
571
572 #ifdef HAVE_PLUGINS
573 /*
574  *  Don't report failures to load plugins because most (non-wiretap) plugins
575  *  *should* fail to load (because we're not linked against libwireshark and
576  *  dissector plugins need libwireshark).
577  */
578 static void
579 failure_message(const char *msg_format _U_, va_list ap _U_)
580 {
581         return;
582 }
583 #endif
584
585 int
586 main(int argc, char *argv[])
587 {
588   wtap *wth;
589   int i, j, err;
590   gchar *err_info;
591   extern char *optarg;
592   extern int optind;
593   int opt;
594   char *p;
595   unsigned int snaplen = 0;             /* No limit               */
596   unsigned int choplen = 0;             /* No chop                */
597   wtap_dumper *pdh;
598   int count = 1;
599   unsigned duplicate_count = 0;
600   gint64 data_offset;
601   struct wtap_pkthdr snap_phdr;
602   const struct wtap_pkthdr *phdr;
603   int err_type;
604   guint8 *buf;
605   int split_packet_count = 0;
606   int written_count = 0;
607   char *filename;
608   size_t filenamelen = 0;
609   gboolean check_ts;
610   int secs_per_block = 0;
611   int block_cnt = 0;
612   nstime_t block_start;
613
614 #ifdef HAVE_PLUGINS
615   char* init_progfile_dir_error;
616 #endif
617
618   /*
619    * Get credential information for later use.
620    */
621   get_credential_info();
622
623 #ifdef HAVE_PLUGINS
624   /* Register wiretap plugins */
625   if ((init_progfile_dir_error = init_progfile_dir(argv[0], main))) {
626     g_warning("capinfos: init_progfile_dir(): %s", init_progfile_dir_error);
627     g_free(init_progfile_dir_error);
628   } else {
629     init_report_err(failure_message,NULL,NULL,NULL);
630     init_plugins();
631   }
632 #endif
633
634   /* Process the options */
635   while ((opt = getopt(argc, argv, "A:B:c:C:dD:E:F:hrs:i:t:T:vw:")) !=-1) {
636
637     switch (opt) {
638
639     case 'E':
640       err_prob = strtod(optarg, &p);
641       if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
642         fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
643             optarg);
644         exit(1);
645       }
646       srand( (unsigned int) (time(NULL) + getpid()) );
647       break;
648
649     case 'F':
650       out_file_type = wtap_short_string_to_file_type(optarg);
651       if (out_file_type < 0) {
652         fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
653             optarg);
654         list_capture_types();
655         exit(1);
656       }
657       break;
658
659     case 'c':
660       split_packet_count = strtol(optarg, &p, 10);
661       if (p == optarg || *p != '\0') {
662         fprintf(stderr, "editcap: \"%s\" isn't a valid packet count\n",
663             optarg);
664         exit(1);
665       }
666       if (split_packet_count <= 0) {
667         fprintf(stderr, "editcap: \"%d\" packet count must be larger than zero\n",
668             split_packet_count);
669         exit(1);
670       }
671       break;
672
673     case 'C':
674       choplen = strtol(optarg, &p, 10);
675       if (p == optarg || *p != '\0') {
676         fprintf(stderr, "editcap: \"%s\" isn't a valid chop length\n",
677             optarg);
678         exit(1);
679       }
680       break;
681
682     case 'd':
683       dup_detect = TRUE;
684       dup_detect_by_time = FALSE;
685       dup_window = DEFAULT_DUP_DEPTH;
686       break;
687
688     case 'D':
689       dup_detect = TRUE;
690       dup_detect_by_time = FALSE;
691       dup_window = strtol(optarg, &p, 10);
692       if (p == optarg || *p != '\0') {
693         fprintf(stderr, "editcap: \"%s\" isn't a valid dupicate window value\n",
694             optarg);
695         exit(1);
696       }
697       if (dup_window < 0 || dup_window > MAX_DUP_DEPTH) {
698         fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
699             dup_window, MAX_DUP_DEPTH);
700         exit(1);
701       }
702       break;
703
704     case 'w':
705       dup_detect = FALSE;
706       dup_detect_by_time = TRUE;
707       dup_window = MAX_DUP_DEPTH;
708       set_rel_time(optarg);
709       break;
710
711     case '?':              /* Bad options if GNU getopt */
712       switch(optopt) {
713       case'F':
714         list_capture_types();
715         break;
716       case'T':
717         list_encap_types();
718         break;
719       default:
720         usage();
721       }
722       exit(1);
723       break;
724
725     case 'h':
726       usage();
727       exit(1);
728       break;
729
730     case 'r':
731       keep_em = !keep_em;  /* Just invert */
732       break;
733
734     case 's':
735       snaplen = strtol(optarg, &p, 10);
736       if (p == optarg || *p != '\0') {
737         fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
738                 optarg);
739         exit(1);
740       }
741       break;
742
743     case 't':
744       set_time_adjustment(optarg);
745       break;
746
747     case 'T':
748       out_frame_type = wtap_short_string_to_encap(optarg);
749       if (out_frame_type < 0) {
750         fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
751             optarg);
752         list_encap_types();
753         exit(1);
754       }
755       break;
756
757     case 'v':
758       verbose = !verbose;  /* Just invert */
759       break;
760
761     case 'i': /* break capture file based on time interval */
762       secs_per_block = atoi(optarg);
763       nstime_set_unset(&block_start);
764       if(secs_per_block <= 0) {
765         fprintf(stderr, "editcap: \"%s\" isn't a valid time interval\n\n", optarg);
766         exit(1);
767         }
768       break;
769
770     case 'A':
771     {
772       struct tm starttm;
773
774       memset(&starttm,0,sizeof(struct tm));
775
776       if(!strptime(optarg,"%Y-%m-%d %T",&starttm)) {
777         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
778         exit(1);
779       }
780
781       check_startstop = TRUE;
782       starttm.tm_isdst = -1;
783
784       starttime = mktime(&starttm);
785       break;
786     }
787
788     case 'B':
789     {
790       struct tm stoptm;
791
792       memset(&stoptm,0,sizeof(struct tm));
793
794       if(!strptime(optarg,"%Y-%m-%d %T",&stoptm)) {
795         fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n", optarg);
796         exit(1);
797       }
798       check_startstop = TRUE;
799       stoptm.tm_isdst = -1;
800       stoptime = mktime(&stoptm);
801       break;
802     }
803     }
804
805   }
806
807 #ifdef DEBUG
808   printf("Optind = %i, argc = %i\n", optind, argc);
809 #endif
810
811   if ((argc - optind) < 1) {
812
813     usage();
814     exit(1);
815
816   }
817
818   if (check_startstop && !stoptime) {
819     struct tm stoptm;
820     /* XXX: will work until 2035 */
821     memset(&stoptm,0,sizeof(struct tm));
822     stoptm.tm_year = 135;
823     stoptm.tm_mday = 31;
824     stoptm.tm_mon = 11;
825
826     stoptime = mktime(&stoptm);
827   }
828
829   if (starttime > stoptime) {
830     fprintf(stderr, "editcap: start time is after the stop time\n");
831     exit(1);
832   }
833
834   if (split_packet_count > 0 && secs_per_block > 0) {
835     fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
836     fprintf(stderr, "editcap: at the same time\n");
837     exit(1);
838   }
839
840   wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
841
842   if (!wth) {
843     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
844         wtap_strerror(err));
845     switch (err) {
846
847     case WTAP_ERR_UNSUPPORTED:
848     case WTAP_ERR_UNSUPPORTED_ENCAP:
849     case WTAP_ERR_BAD_RECORD:
850       fprintf(stderr, "(%s)\n", err_info);
851       g_free(err_info);
852       break;
853     }
854     exit(1);
855
856   }
857
858   if (verbose) {
859     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
860             wtap_file_type_string(wtap_file_type(wth)));
861   }
862
863   /*
864    * Now, process the rest, if any ... we only write if there is an extra
865    * argument or so ...
866    */
867
868   if ((argc - optind) >= 2) {
869
870     if (out_frame_type == -2)
871       out_frame_type = wtap_file_encap(wth);
872
873     if (split_packet_count > 0) {
874       filenamelen = strlen(argv[optind+1]) + 20;
875       filename = (char *) g_malloc(filenamelen);
876       if (!filename) {
877         exit(5);
878       }
879       g_snprintf(filename, (gulong) filenamelen, "%s-%05d", argv[optind+1], 0);
880     } else {
881       if (secs_per_block > 0) {
882         filenamelen = strlen(argv[optind+1]) + 7;
883         filename = (char *) g_malloc(filenamelen);
884         if (!filename) {
885           exit(5);
886           }
887         g_snprintf(filename, (gulong) filenamelen, "%s-%05d", argv[optind+1], block_cnt);
888         }
889       else {
890         filename = argv[optind+1];
891         }
892       }
893
894     pdh = wtap_dump_open(filename, out_file_type,
895         out_frame_type, wtap_snapshot_length(wth),
896         FALSE /* compressed */, &err);
897     if (pdh == NULL) {
898
899       fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
900               wtap_strerror(err));
901       exit(1);
902     }
903
904     for (i = optind + 2; i < argc; i++)
905       if (add_selection(argv[i]) == FALSE)
906         break;
907
908     if (dup_detect || dup_detect_by_time) {
909       for (i = 0; i < dup_window; i++) {
910         memset(&fd_hash[i].digest, 0, 16);
911         fd_hash[i].len = 0;
912         nstime_set_unset(&fd_hash[i].time);
913       }
914     }
915
916     while (wtap_read(wth, &err, &err_info, &data_offset)) {
917
918       if (secs_per_block > 0) {
919         phdr = wtap_phdr(wth);
920
921         if (nstime_is_unset(&block_start)) {  /* should only be the first packet */
922           block_start.secs = phdr->ts.secs;
923           block_start.nsecs = phdr->ts.nsecs;
924           }
925
926         while ((phdr->ts.secs - block_start.secs >  secs_per_block) ||
927             (phdr->ts.secs - block_start.secs == secs_per_block &&
928                 phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
929
930           if (!wtap_dump_close(pdh, &err)) {
931             fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
932                 wtap_strerror(err));
933             exit(1);
934             }
935           block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
936           g_snprintf(filename, (gulong) filenamelen, "%s-%05d",argv[optind+1], ++block_cnt);
937
938           if (verbose) {
939             fprintf(stderr, "Continuing writing in file %s\n", filename);
940             }
941
942           pdh = wtap_dump_open(filename, out_file_type,
943              out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
944
945           if (pdh == NULL) {
946             fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
947               wtap_strerror(err));
948             exit(1);
949           }
950         }
951       }
952
953       if (split_packet_count > 0 && (written_count % split_packet_count == 0)) {
954         if (!wtap_dump_close(pdh, &err)) {
955
956           fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
957               wtap_strerror(err));
958           exit(1);
959         }
960
961         g_snprintf(filename, (gulong) filenamelen, "%s-%05d",argv[optind+1], count / split_packet_count);
962
963         if (verbose) {
964           fprintf(stderr, "Continuing writing in file %s\n", filename);
965         }
966
967         pdh = wtap_dump_open(filename, out_file_type,
968             out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err);
969         if (pdh == NULL) {
970
971           fprintf(stderr, "editcap: Can't open or create %s: %s\n", filename,
972               wtap_strerror(err));
973           exit(1);
974         }
975       }
976
977       check_ts = check_timestamp(wth);
978
979       if ( ((check_startstop && check_ts) || (!check_startstop && !check_ts)) && ((!selected(count) && !keep_em) ||
980           (selected(count) && keep_em)) ) {
981
982         if (verbose && !dup_detect && !dup_detect_by_time)
983           printf("Packet: %u\n", count);
984
985         /* We simply write it, perhaps after truncating it; we could do other
986            things, like modify it. */
987
988         phdr = wtap_phdr(wth);
989
990         if (choplen != 0 && phdr->caplen > choplen) {
991           snap_phdr = *phdr;
992           snap_phdr.caplen -= choplen;
993           phdr = &snap_phdr;
994         }
995
996         if (snaplen != 0 && phdr->caplen > snaplen) {
997           snap_phdr = *phdr;
998           snap_phdr.caplen = snaplen;
999           phdr = &snap_phdr;
1000         }
1001
1002         /* assume that if the frame's tv_sec is 0, then
1003          * the timestamp isn't supported */
1004         if (phdr->ts.secs > 0 && time_adj.tv.tv_sec != 0) {
1005           snap_phdr = *phdr;
1006           if (time_adj.is_negative)
1007             snap_phdr.ts.secs -= time_adj.tv.tv_sec;
1008           else
1009             snap_phdr.ts.secs += time_adj.tv.tv_sec;
1010           phdr = &snap_phdr;
1011         }
1012
1013         /* assume that if the frame's tv_sec is 0, then
1014          * the timestamp isn't supported */
1015         if (phdr->ts.secs > 0 && time_adj.tv.tv_usec != 0) {
1016           snap_phdr = *phdr;
1017           if (time_adj.is_negative) { /* subtract */
1018             if (snap_phdr.ts.nsecs/1000 < time_adj.tv.tv_usec) { /* borrow */
1019               snap_phdr.ts.secs--;
1020               snap_phdr.ts.nsecs += ONE_MILLION * 1000;
1021             }
1022             snap_phdr.ts.nsecs -= time_adj.tv.tv_usec * 1000;
1023           } else {                  /* add */
1024             if (snap_phdr.ts.nsecs + time_adj.tv.tv_usec * 1000 > ONE_MILLION * 1000) {
1025               /* carry */
1026               snap_phdr.ts.secs++;
1027               snap_phdr.ts.nsecs += (time_adj.tv.tv_usec - ONE_MILLION) * 1000;
1028             } else {
1029               snap_phdr.ts.nsecs += time_adj.tv.tv_usec * 1000;
1030             }
1031           }
1032           phdr = &snap_phdr;
1033         }
1034
1035         /* suppress duplicates by packet window */
1036         if (dup_detect) {
1037           buf = wtap_buf_ptr(wth);
1038           if (is_duplicate(buf, phdr->caplen)) {
1039             if (verbose) {
1040               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1041               for (i = 0; i < 16; i++) {
1042                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1043               }
1044               fprintf(stdout, "\n");
1045             }
1046             duplicate_count++;
1047             count++;
1048             continue;
1049           } else {
1050             if (verbose) {
1051               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1052               for (i = 0; i < 16; i++) {
1053                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1054               }
1055               fprintf(stdout, "\n");
1056             }
1057           }
1058         }
1059
1060         /* suppress duplicates by time window */
1061         if (dup_detect_by_time) {
1062           nstime_t current;
1063
1064           current.secs = phdr->ts.secs;
1065           current.nsecs = phdr->ts.nsecs;
1066
1067           buf = wtap_buf_ptr(wth);
1068
1069           if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1070             if (verbose) {
1071               fprintf(stdout, "Skipped: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1072               for (i = 0; i < 16; i++) {
1073                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1074               }
1075               fprintf(stdout, "\n");
1076             }
1077             duplicate_count++;
1078             count++;
1079             continue;
1080           } else {
1081             if (verbose) {
1082               fprintf(stdout, "Packet: %u, Len: %u, MD5 Hash: ", count, phdr->caplen);
1083               for (i = 0; i < 16; i++) {
1084                 fprintf(stdout, "%02x", (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1085               }
1086               fprintf(stdout, "\n");
1087             }
1088           }
1089         }
1090
1091         /* Random error mutation */
1092         if (err_prob > 0.0) {
1093           int real_data_start = 0;
1094           buf = wtap_buf_ptr(wth);
1095           /* Protect non-protocol data */
1096           if (wtap_file_type(wth) == WTAP_FILE_CATAPULT_DCT2000) {
1097             real_data_start = find_dct2000_real_data(buf);
1098           }
1099           for (i = real_data_start; i < (int) phdr->caplen; i++) {
1100             if (rand() <= err_prob * RAND_MAX) {
1101               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1102
1103               if (err_type < ERR_WT_BIT) {
1104                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1105                 err_type = ERR_WT_TOTAL;
1106               } else {
1107                 err_type -= ERR_WT_BYTE;
1108               }
1109
1110               if (err_type < ERR_WT_BYTE) {
1111                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1112                 err_type = ERR_WT_TOTAL;
1113               } else {
1114                 err_type -= ERR_WT_BYTE;
1115               }
1116
1117               if (err_type < ERR_WT_ALNUM) {
1118                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1119                 err_type = ERR_WT_TOTAL;
1120               } else {
1121                 err_type -= ERR_WT_ALNUM;
1122               }
1123
1124               if (err_type < ERR_WT_FMT) {
1125                 if ((unsigned int)i < phdr->caplen - 2)
1126                   strncpy((char*) &buf[i],  "%s", 2);
1127                 err_type = ERR_WT_TOTAL;
1128               } else {
1129                 err_type -= ERR_WT_FMT;
1130               }
1131
1132               if (err_type < ERR_WT_AA) {
1133                 for (j = i; j < (int) phdr->caplen; j++) {
1134                   buf[j] = 0xAA;
1135                 }
1136                 i = phdr->caplen;
1137               }
1138             }
1139           }
1140         }
1141
1142         if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
1143                        &err)) {
1144           fprintf(stderr, "editcap: Error writing to %s: %s\n",
1145                   filename, wtap_strerror(err));
1146           exit(1);
1147         }
1148         written_count++;
1149       }
1150       count++;
1151     }
1152
1153     if (err != 0) {
1154       /* Print a message noting that the read failed somewhere along the line. */
1155       fprintf(stderr,
1156               "editcap: An error occurred while reading \"%s\": %s.\n",
1157               argv[optind], wtap_strerror(err));
1158       switch (err) {
1159
1160       case WTAP_ERR_UNSUPPORTED:
1161       case WTAP_ERR_UNSUPPORTED_ENCAP:
1162       case WTAP_ERR_BAD_RECORD:
1163         fprintf(stderr, "(%s)\n", err_info);
1164         g_free(err_info);
1165         break;
1166       }
1167     }
1168
1169     if (!wtap_dump_close(pdh, &err)) {
1170
1171       fprintf(stderr, "editcap: Error writing to %s: %s\n", filename,
1172           wtap_strerror(err));
1173       exit(1);
1174
1175     }
1176   }
1177
1178   if (dup_detect) {
1179     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate window of %u packets.\n",
1180                 count - 1, plurality(count - 1, "", "s"),
1181                 duplicate_count, plurality(duplicate_count, "", "s"), dup_window);
1182   } else if (dup_detect_by_time) {
1183     fprintf(stdout, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1184                 count - 1, plurality(count - 1, "", "s"),
1185                 duplicate_count, plurality(duplicate_count, "", "s"),
1186                 (long)relative_time_window.secs, (long int)relative_time_window.nsecs);
1187   }
1188
1189   return 0;
1190 }
1191
1192 /* Skip meta-information read from file to return offset of real
1193    protocol data */
1194 static int find_dct2000_real_data(guint8 *buf)
1195 {
1196   int n=0;
1197
1198   for (n=0; buf[n] != '\0'; n++);   /* Context name */
1199   n++;
1200   n++;                              /* Context port number */
1201   for (; buf[n] != '\0'; n++);      /* Timestamp */
1202   n++;
1203   for (; buf[n] != '\0'; n++);      /* Protocol name */
1204   n++;
1205   for (; buf[n] != '\0'; n++);      /* Variant number (as string) */
1206   n++;
1207   for (; buf[n] != '\0'; n++);      /* Outhdr (as string) */
1208   n++;
1209   n += 2;                           /* Direction & encap */
1210
1211   return n;
1212 }