MSVC: fix some guint64 related compiler errors
[obnox/wireshark/wip.git] / editcap.c
1 /* Edit capture files.  We can delete records, 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 <glib.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <time.h>
24 #ifdef HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27
28 #include <string.h>
29 #include "wtap.h"
30
31 #ifdef NEED_GETOPT_H
32 #include "getopt.h"
33 #endif
34
35 /*
36  * Some globals so we can pass things to various routines
37  */
38
39 struct select_item {
40
41   int inclusive;
42   int first, second;
43
44 };
45
46 #define ONE_MILLION 1000000
47
48 /* Weights of different errors we can introduce */
49 /* We should probably make these command-line arguments */
50 /* XXX - Should we add a bit-level error? */
51 #define ERR_WT_BIT   5  /* Flip a random bit */
52 #define ERR_WT_BYTE  5  /* Substitute a random byte */
53 #define ERR_WT_ALNUM 5  /* Substitute a random character in [A-Za-z0-9] */
54 #define ERR_WT_FMT   2  /* Substitute "%s" */
55 #define ERR_WT_AA    1  /* Fill the remainder of the buffer with 0xAA */
56 #define ERR_WT_TOTAL (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
57
58 #define ALNUM_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
59 #define ALNUM_LEN (sizeof(ALNUM_CHARS) - 1)
60
61
62 struct time_adjustment {
63   struct timeval tv;
64   int is_negative;
65 };
66
67 static struct select_item selectfrm[100];
68 static int max_selected = -1;
69 static int keep_em = 0;
70 static int out_file_type = WTAP_FILE_PCAP;   /* default to "libpcap"   */
71 static int out_frame_type = -2;              /* Leave frame type alone */
72 static int verbose = 0;                      /* Not so verbose         */
73 static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */
74 static double err_prob = 0.0;
75
76 /* Add a selection item, a simple parser for now */
77
78 static void add_selection(char *sel)
79 {
80   char *locn;
81   char *next;
82
83   if (max_selected == (sizeof(selectfrm)/sizeof(struct select_item)) - 1)
84     return;
85
86   printf("Add_Selected: %s\n", sel);
87
88   if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
89
90     printf("Not inclusive ...");
91
92     max_selected++;
93     selectfrm[max_selected].inclusive = 0;
94     selectfrm[max_selected].first = atoi(sel);
95
96     printf(" %i\n", selectfrm[max_selected].first);
97
98   }
99   else {
100
101     printf("Inclusive ...");
102
103     next = locn + 1;
104     max_selected++;
105     selectfrm[max_selected].inclusive = 1;
106     selectfrm[max_selected].first = atoi(sel);
107     selectfrm[max_selected].second = atoi(next);
108
109     printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second);
110
111   }
112
113
114 }
115
116 /* Was the record selected? */
117
118 static int selected(int recno)
119 {
120   int i = 0;
121
122   for (i = 0; i<= max_selected; i++) {
123
124     if (selectfrm[i].inclusive) {
125       if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
126         return 1;
127     }
128     else {
129       if (recno == selectfrm[i].first)
130         return 1;
131     }
132   }
133
134   return 0;
135
136 }
137
138 static void
139 set_time_adjustment(char *optarg)
140 {
141   char *frac, *end;
142   long val;
143   int frac_digits;
144
145   if (!optarg)
146     return;
147
148   /* skip leading whitespace */
149   while (*optarg == ' ' || *optarg == '\t') {
150       optarg++;
151   }
152
153   /* check for a negative adjustment */
154   if (*optarg == '-') {
155       time_adj.is_negative = 1;
156       optarg++;
157   }
158
159   /* collect whole number of seconds, if any */
160   if (*optarg == '.') {         /* only fractional (i.e., .5 is ok) */
161       val  = 0;
162       frac = optarg;
163   } else {
164       val = strtol(optarg, &frac, 10);
165       if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) {
166           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
167                   optarg);
168           exit(1);
169       }
170       if (val < 0) {            /* implies '--' since we caught '-' above  */
171           fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
172                   optarg);
173           exit(1);
174       }
175   }
176   time_adj.tv.tv_sec = val;
177
178   /* now collect the partial seconds, if any */
179   if (*frac != '\0') {             /* chars left, so get fractional part */
180     val = strtol(&(frac[1]), &end, 10);
181     if (*frac != '.' || end == NULL || end == frac
182         || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) {
183       fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
184               optarg);
185       exit(1);
186     }
187   }
188   else {
189     return;                     /* no fractional digits */
190   }
191
192   /* adjust fractional portion from fractional to numerator
193    * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */
194   if (frac && end) {            /* both are valid */
195     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
196     while(frac_digits < 6) {    /* this is frac of 10^6 */
197       val *= 10;
198       frac_digits++;
199     }
200   }
201   time_adj.tv.tv_usec = val;
202 }
203
204 static void usage(void)
205 {
206   int i;
207   const char *string;
208
209   fprintf(stderr, "Usage: editcap [-r] [-h] [-v] [-T <encap type>] [-E <probability>]\n");
210   fprintf(stderr, "               [-F <capture type>] [-s <snaplen>] [-t <time adjustment>]\n");
211   fprintf(stderr, "               <infile> <outfile> [ <record#>[-<record#>] ... ]\n");
212   fprintf(stderr, "  where\n");
213   fprintf(stderr, "       \t-E <probability> specifies the probability (between 0 and 1)\n");
214   fprintf(stderr, "       \t    that a particular byte will will have an error.\n");
215   fprintf(stderr, "       \t-F <capture type> specifies the capture file type to write:\n");
216   for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
217     if (wtap_dump_can_open(i))
218       fprintf(stderr, "       \t    %s - %s\n",
219         wtap_file_type_short_string(i), wtap_file_type_string(i));
220   }
221   fprintf(stderr, "       \t    default is libpcap\n");
222   fprintf(stderr, "       \t-h produces this help listing.\n");
223   fprintf(stderr, "       \t-r specifies that the records specified should be kept, not deleted, \n");
224   fprintf(stderr, "                           default is to delete\n");
225   fprintf(stderr, "       \t-s <snaplen> specifies that packets should be truncated to\n");
226   fprintf(stderr, "       \t   <snaplen> bytes of data\n");
227   fprintf(stderr, "       \t-t <time adjustment> specifies the time adjustment\n");
228   fprintf(stderr, "       \t   to be applied to selected packets\n");
229   fprintf(stderr, "       \t-T <encap type> specifies the encapsulation type to use:\n");
230   for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
231       string = wtap_encap_short_string(i);
232       if (string != NULL)
233         fprintf(stderr, "       \t    %s - %s\n",
234           string, wtap_encap_string(i));
235   }
236   fprintf(stderr, "       \t    default is the same as the input file\n");
237   fprintf(stderr, "       \t-v specifies verbose operation, default is silent\n");
238   fprintf(stderr, "\n      \t    A range of records can be specified as well\n");
239 }
240
241 int main(int argc, char *argv[])
242
243 {
244   wtap *wth;
245   int i, j, err;
246   gchar *err_info;
247   extern char *optarg;
248   extern int optind;
249   int opt;
250   char *p;
251   unsigned int snaplen = 0;             /* No limit               */
252   wtap_dumper *pdh;
253   int count = 1;
254   long data_offset;
255   struct wtap_pkthdr snap_phdr;
256   const struct wtap_pkthdr *phdr;
257   int err_type;
258   guint8 *buf;
259
260   /* Process the options first */
261
262   while ((opt = getopt(argc, argv, "E:F:hrs:t:T:v")) !=-1) {
263
264     switch (opt) {
265
266     case 'E':
267       err_prob = strtod(optarg, &p);
268       if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
269         fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
270             optarg);
271         exit(1);
272       }
273       srand(time(NULL) + getpid());
274       break;
275
276     case 'F':
277       out_file_type = wtap_short_string_to_file_type(optarg);
278       if (out_file_type < 0) {
279         fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n",
280             optarg);
281         exit(1);
282       }
283       break;
284
285     case 'h':
286     case '?':              /* Bad options if GNU getopt */
287       usage();
288       exit(1);
289       break;
290
291     case 'r':
292       keep_em = !keep_em;  /* Just invert */
293       break;
294
295     case 's':
296       snaplen = strtol(optarg, &p, 10);
297       if (p == optarg || *p != '\0') {
298         fprintf(stderr, "editcap: \"%s\" isn't a valid snapshot length\n",
299             optarg);
300         exit(1);
301       }
302       break;
303
304     case 't':
305       set_time_adjustment(optarg);
306       break;
307
308     case 'T':
309       out_frame_type = wtap_short_string_to_encap(optarg);
310       if (out_frame_type < 0) {
311         fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n",
312             optarg);
313         exit(1);
314       }
315       break;
316
317     case 'v':
318       verbose = !verbose;  /* Just invert */
319       break;
320
321     }
322
323   }
324
325 #ifdef DEBUG
326   printf("Optind = %i, argc = %i\n", optind, argc);
327 #endif
328
329   if ((argc - optind) < 1) {
330
331     usage();
332     exit(1);
333
334   }
335
336   wth = wtap_open_offline(argv[optind], &err, &err_info, FALSE);
337
338   if (!wth) {
339     fprintf(stderr, "editcap: Can't open %s: %s\n", argv[optind],
340         wtap_strerror(err));
341     switch (err) {
342
343     case WTAP_ERR_UNSUPPORTED:
344     case WTAP_ERR_UNSUPPORTED_ENCAP:
345     case WTAP_ERR_BAD_RECORD:
346       fprintf(stderr, "(%s)\n", err_info);
347       g_free(err_info);
348       break;
349     }
350     exit(1);
351
352   }
353
354   if (verbose) {
355
356     fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
357             wtap_file_type_string(wtap_file_type(wth)));
358
359   }
360
361   /*
362    * Now, process the rest, if any ... we only write if there is an extra
363    * argument or so ...
364    */
365
366   if ((argc - optind) >= 2) {
367
368     if (out_frame_type == -2)
369       out_frame_type = wtap_file_encap(wth);
370
371     pdh = wtap_dump_open(argv[optind + 1], out_file_type,
372                          out_frame_type, wtap_snapshot_length(wth), &err);
373     if (pdh == NULL) {
374
375       fprintf(stderr, "editcap: Can't open or create %s: %s\n", argv[optind+1],
376               wtap_strerror(err));
377       exit(1);
378
379     }
380
381     for (i = optind + 2; i < argc; i++)
382       add_selection(argv[i]);
383
384     while (wtap_read(wth, &err, &err_info, &data_offset)) {
385
386       if ((!selected(count) && !keep_em) ||
387           (selected(count) && keep_em)) {
388
389         if (verbose)
390           printf("Record: %u\n", count);
391
392         /* We simply write it, perhaps after truncating it; we could do other
393            things, like modify it. */
394
395         phdr = wtap_phdr(wth);
396
397         if (snaplen != 0 && phdr->caplen > snaplen) {
398           snap_phdr = *phdr;
399           snap_phdr.caplen = snaplen;
400           phdr = &snap_phdr;
401         }
402
403         /* assume that if the frame's tv_sec is 0, then
404          * the timestamp isn't supported */
405         if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_sec != 0) {
406           snap_phdr = *phdr;
407           if (time_adj.is_negative)
408             snap_phdr.ts.tv_sec -= time_adj.tv.tv_sec;
409           else
410             snap_phdr.ts.tv_sec += time_adj.tv.tv_sec;
411           phdr = &snap_phdr;
412         }
413
414         /* assume that if the frame's tv_sec is 0, then
415          * the timestamp isn't supported */
416         if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_usec != 0) {
417           snap_phdr = *phdr;
418           if (time_adj.is_negative) { /* subtract */
419             if (snap_phdr.ts.tv_usec < time_adj.tv.tv_usec) { /* borrow */
420               snap_phdr.ts.tv_sec--;
421               snap_phdr.ts.tv_usec += ONE_MILLION;
422             }
423             snap_phdr.ts.tv_usec -= time_adj.tv.tv_usec;
424           } else {                  /* add */
425             if (snap_phdr.ts.tv_usec + time_adj.tv.tv_usec > ONE_MILLION) {
426               /* carry */
427               snap_phdr.ts.tv_sec++;
428               snap_phdr.ts.tv_usec += time_adj.tv.tv_usec - ONE_MILLION;
429             } else {
430               snap_phdr.ts.tv_usec += time_adj.tv.tv_usec;
431             }
432           }
433           phdr = &snap_phdr;
434         }
435
436         if (err_prob > 0.0) {
437           buf = wtap_buf_ptr(wth);
438           for (i = 0; i < (int) phdr->caplen; i++) {
439             if (rand() <= err_prob * RAND_MAX) {
440               err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
441
442               if (err_type < ERR_WT_BIT) {
443                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
444                 err_type = ERR_WT_TOTAL;
445               } else {
446                 err_type -= ERR_WT_BYTE;
447               }
448
449               if (err_type < ERR_WT_BYTE) {
450                 buf[i] = rand() / (RAND_MAX / 255 + 1);
451                 err_type = ERR_WT_TOTAL;
452               } else {
453                 err_type -= ERR_WT_BYTE;
454               }
455
456               if (err_type < ERR_WT_ALNUM) {
457                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
458                 err_type = ERR_WT_TOTAL;
459               } else {
460                 err_type -= ERR_WT_ALNUM;
461               }
462
463               if (err_type < ERR_WT_FMT) {
464                 if (i < phdr->caplen - 2)
465                   strcpy(&buf[i],  "%s");
466                 err_type = ERR_WT_TOTAL;
467               } else {
468                 err_type -= ERR_WT_FMT;
469               }
470
471               if (err_type < ERR_WT_AA) {
472                 for (j = i; j < (int) phdr->caplen; j++) {
473                   buf[j] = 0xAA;
474                 }
475                 i = phdr->caplen;
476               }
477             }
478           }
479         }
480
481         if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth),
482                        &err)) {
483
484           fprintf(stderr, "editcap: Error writing to %s: %s\n",
485                   argv[optind + 1], wtap_strerror(err));
486           exit(1);
487
488         }
489
490       }
491
492       count++;
493
494     }
495
496     if (err != 0) {
497       /* Print a message noting that the read failed somewhere along the line. */
498       fprintf(stderr,
499               "editcap: An error occurred while reading \"%s\": %s.\n",
500               argv[optind], wtap_strerror(err));
501       switch (err) {
502
503       case WTAP_ERR_UNSUPPORTED:
504       case WTAP_ERR_UNSUPPORTED_ENCAP:
505       case WTAP_ERR_BAD_RECORD:
506         fprintf(stderr, "(%s)\n", err_info);
507         break;
508       }
509     }
510
511     if (!wtap_dump_close(pdh, &err)) {
512
513       fprintf(stderr, "editcap: Error writing to %s: %s\n", argv[optind + 1],
514               wtap_strerror(err));
515       exit(1);
516
517     }
518   }
519
520   return 0;
521 }
522