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