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