qt: follow stream: fix crash during close
[metze/wireshark/wip.git] / editcap.c
1 /* editcap.c
2  * Edit capture files.  We can delete packets, adjust timestamps, or
3  * simply convert from one format to another format.
4  *
5  * Originally written by Richard Sharpe.
6  * Improved by Guy Harris.
7  * Further improved by Richard Sharpe.
8  *
9  * Copyright 2013, Richard Sharpe <realrichardsharpe[AT]gmail.com>
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * SPDX-License-Identifier: GPL-2.0+
16  */
17
18 #include <config.h>
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24
25 /*
26  * Just make sure we include the prototype for strptime as well
27  * (needed for glibc 2.2) but make sure we do this only if not
28  * yet defined.
29  */
30
31 #ifndef __USE_XOPEN
32 #  define __USE_XOPEN
33 #endif
34
35 #include <time.h>
36 #include <glib.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #ifdef HAVE_GETOPT_H
43 #include <getopt.h>
44 #endif
45
46 #include <wiretap/wtap.h>
47
48 #include "epan/etypes.h"
49
50 #ifndef HAVE_GETOPT_LONG
51 #include "wsutil/wsgetopt.h"
52 #endif
53
54 #ifdef _WIN32
55 #include <wsutil/unicode-utils.h>
56 #include <process.h>    /* getpid */
57 #include <winsock2.h>
58 #endif
59
60 #ifndef HAVE_STRPTIME
61 # include "wsutil/strptime.h"
62 #endif
63
64 #include <wsutil/crash_info.h>
65 #include <wsutil/clopts_common.h>
66 #include <wsutil/cmdarg_err.h>
67 #include <wsutil/filesystem.h>
68 #include <wsutil/file_util.h>
69 #include <wsutil/wsgcrypt.h>
70 #include <wsutil/plugins.h>
71 #include <wsutil/privileges.h>
72 #include <wsutil/report_message.h>
73 #include <wsutil/strnatcmp.h>
74 #include <wsutil/str_util.h>
75 #include <version_info.h>
76 #include <wsutil/pint.h>
77 #include <wsutil/strtoi.h>
78 #include <wiretap/wtap_opttypes.h>
79 #include <wiretap/pcapng.h>
80
81 #include "ui/failure_message.h"
82
83 #include "ringbuffer.h" /* For RINGBUFFER_MAX_NUM_FILES */
84
85 #define INVALID_OPTION 1
86 #define INVALID_FILE 2
87 #define CANT_EXTRACT_PREFIX 2
88 #define WRITE_ERROR 2
89 #define DUMP_ERROR 2
90
91 /*
92  * Some globals so we can pass things to various routines
93  */
94
95 struct select_item {
96     gboolean inclusive;
97     guint first, second;
98 };
99
100 /*
101  * Duplicate frame detection
102  */
103 typedef struct _fd_hash_t {
104     guint8     digest[16];
105     guint32    len;
106     nstime_t   frame_time;
107 } fd_hash_t;
108
109 #define DEFAULT_DUP_DEPTH       5   /* Used with -d */
110 #define MAX_DUP_DEPTH     1000000   /* the maximum window (and actual size of fd_hash[]) for de-duplication */
111
112 static fd_hash_t fd_hash[MAX_DUP_DEPTH];
113 static int       dup_window    = DEFAULT_DUP_DEPTH;
114 static int       cur_dup_entry = 0;
115
116 static guint32   ignored_bytes  = 0;  /* Used with -I */
117
118 #define ONE_BILLION 1000000000
119
120 /* Weights of different errors we can introduce */
121 /* We should probably make these command-line arguments */
122 /* XXX - Should we add a bit-level error? */
123 #define ERR_WT_BIT      5   /* Flip a random bit */
124 #define ERR_WT_BYTE     5   /* Substitute a random byte */
125 #define ERR_WT_ALNUM    5   /* Substitute a random character in [A-Za-z0-9] */
126 #define ERR_WT_FMT      2   /* Substitute "%s" */
127 #define ERR_WT_AA       1   /* Fill the remainder of the buffer with 0xAA */
128 #define ERR_WT_TOTAL    (ERR_WT_BIT + ERR_WT_BYTE + ERR_WT_ALNUM + ERR_WT_FMT + ERR_WT_AA)
129
130 #define ALNUM_CHARS     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
131 #define ALNUM_LEN       (sizeof(ALNUM_CHARS) - 1)
132
133 struct time_adjustment {
134     nstime_t tv;
135     int is_negative;
136 };
137
138 typedef struct _chop_t {
139     int len_begin;
140     int off_begin_pos;
141     int off_begin_neg;
142     int len_end;
143     int off_end_pos;
144     int off_end_neg;
145 } chop_t;
146
147
148 /* Table of user comments */
149 GTree *frames_user_comments = NULL;
150
151 #define MAX_SELECTIONS 512
152 static struct select_item     selectfrm[MAX_SELECTIONS];
153 static guint                  max_selected              = 0;
154 static int                    keep_em                   = 0;
155 #ifdef PCAP_NG_DEFAULT
156 static int                    out_file_type_subtype     = WTAP_FILE_TYPE_SUBTYPE_PCAPNG; /* default to pcapng   */
157 #else
158 static int                    out_file_type_subtype     = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcap     */
159 #endif
160 static int                    out_frame_type            = -2; /* Leave frame type alone */
161 static int                    verbose                   = 0;  /* Not so verbose         */
162 static struct time_adjustment time_adj                  = {{0, 0}, 0}; /* no adjustment */
163 static nstime_t               relative_time_window      = {0, 0}; /* de-dup time window */
164 static double                 err_prob                  = 0.0;
165 static time_t                 starttime                 = 0;
166 static time_t                 stoptime                  = 0;
167 static gboolean               check_startstop           = FALSE;
168 static gboolean               rem_vlan                  = FALSE;
169 static gboolean               dup_detect                = FALSE;
170 static gboolean               dup_detect_by_time        = FALSE;
171
172 static int                    do_strict_time_adjustment = FALSE;
173 static struct time_adjustment strict_time_adj           = {{0, 0}, 0}; /* strict time adjustment */
174 static nstime_t               previous_time             = {0, 0}; /* previous time */
175
176 static int find_dct2000_real_data(guint8 *buf);
177 static void handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
178                             const struct wtap_pkthdr *in_phdr, guint8 **buf,
179                             gboolean adjlen);
180
181 static gchar *
182 abs_time_to_str_with_sec_resolution(const nstime_t *abs_time)
183 {
184     struct tm *tmp;
185     gchar     *buf = (gchar *)g_malloc(16);
186
187     tmp = localtime(&abs_time->secs);
188
189     if (tmp) {
190         g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d",
191             tmp->tm_year + 1900,
192             tmp->tm_mon+1,
193             tmp->tm_mday,
194             tmp->tm_hour,
195             tmp->tm_min,
196             tmp->tm_sec);
197     } else {
198         buf[0] = '\0';
199     }
200
201     return buf;
202 }
203
204 static gchar *
205 fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr,
206                                 gchar *fprefix, gchar *fsuffix)
207 {
208     gchar  filenum[5+1];
209     gchar *timestr;
210     gchar *abs_str;
211
212     g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES);
213     if (phdr->presence_flags & WTAP_HAS_TS) {
214         timestr = abs_time_to_str_with_sec_resolution(&phdr->ts);
215         abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
216         g_free(timestr);
217     } else
218         abs_str = g_strconcat(fprefix, "_", filenum, fsuffix, NULL);
219
220     return abs_str;
221 }
222
223 static gboolean
224 fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix)
225 {
226     char  *pfx, *last_pathsep;
227     gchar *save_file;
228
229     save_file = g_strdup(fname);
230     if (save_file == NULL) {
231         fprintf(stderr, "editcap: Out of memory\n");
232         return FALSE;
233     }
234
235     last_pathsep = strrchr(save_file, G_DIR_SEPARATOR);
236     pfx = strrchr(save_file,'.');
237     if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) {
238         /* The pathname has a "." in it, and it's in the last component
239          * of the pathname (because there is either only one component,
240          * i.e. last_pathsep is null as there are no path separators,
241          * or the "." is after the path separator before the last
242          * component.
243
244          * Treat it as a separator between the rest of the file name and
245          * the file name suffix, and arrange that the names given to the
246          * ring buffer files have the specified suffix, i.e. put the
247          * changing part of the name *before* the suffix. */
248         pfx[0] = '\0';
249         *fprefix = g_strdup(save_file);
250         pfx[0] = '.'; /* restore capfile_name */
251         *fsuffix = g_strdup(pfx);
252     } else {
253         /* Either there's no "." in the pathname, or it's in a directory
254          * component, so the last component has no suffix. */
255         *fprefix = g_strdup(save_file);
256         *fsuffix = NULL;
257     }
258     g_free(save_file);
259     return TRUE;
260 }
261
262 /* Add a selection item, a simple parser for now */
263 static gboolean
264 add_selection(char *sel, guint* max_selection)
265 {
266     char *locn;
267     char *next;
268
269     if (max_selected >= MAX_SELECTIONS) {
270         /* Let the user know we stopped selecting */
271         fprintf(stderr, "Out of room for packet selections.\n");
272         return(FALSE);
273     }
274
275     if (verbose)
276         fprintf(stderr, "Add_Selected: %s\n", sel);
277
278     if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */
279         if (verbose)
280             fprintf(stderr, "Not inclusive ...");
281
282         selectfrm[max_selected].inclusive = FALSE;
283         selectfrm[max_selected].first = get_guint32(sel, "packet number");
284         if (selectfrm[max_selected].first > *max_selection)
285             *max_selection = selectfrm[max_selected].first;
286
287         if (verbose)
288             fprintf(stderr, " %u\n", selectfrm[max_selected].first);
289     } else {
290         if (verbose)
291             fprintf(stderr, "Inclusive ...");
292
293         *locn = '\0';    /* split the range */
294         next = locn + 1;
295         selectfrm[max_selected].inclusive = TRUE;
296         selectfrm[max_selected].first = get_guint32(sel, "beginning of packet range");
297         selectfrm[max_selected].second = get_guint32(next, "end of packet range");
298
299         if (selectfrm[max_selected].second == 0)
300         {
301             /* Not a valid number, presume all */
302             selectfrm[max_selected].second = *max_selection = G_MAXUINT;
303         }
304         else if (selectfrm[max_selected].second > *max_selection)
305             *max_selection = selectfrm[max_selected].second;
306
307         if (verbose)
308             fprintf(stderr, " %u, %u\n", selectfrm[max_selected].first,
309                    selectfrm[max_selected].second);
310     }
311
312     max_selected++;
313     return(TRUE);
314 }
315
316 /* Was the packet selected? */
317
318 static int
319 selected(guint recno)
320 {
321     guint i;
322
323     for (i = 0; i < max_selected; i++) {
324         if (selectfrm[i].inclusive) {
325             if (selectfrm[i].first <= recno && selectfrm[i].second >= recno)
326                 return 1;
327         } else {
328             if (recno == selectfrm[i].first)
329                 return 1;
330         }
331     }
332
333   return 0;
334 }
335
336 static gboolean
337 set_time_adjustment(char *optarg_str_p)
338 {
339     char   *frac, *end;
340     long    val;
341     size_t  frac_digits;
342
343     if (!optarg_str_p)
344         return TRUE;
345
346     /* skip leading whitespace */
347     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
348         optarg_str_p++;
349
350     /* check for a negative adjustment */
351     if (*optarg_str_p == '-') {
352         time_adj.is_negative = 1;
353         optarg_str_p++;
354     }
355
356     /* collect whole number of seconds, if any */
357     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
358         val  = 0;
359         frac = optarg_str_p;
360     } else {
361         val = strtol(optarg_str_p, &frac, 10);
362         if (frac == NULL || frac == optarg_str_p
363             || val == LONG_MIN || val == LONG_MAX) {
364             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
365                     optarg_str_p);
366             return FALSE;
367         }
368         if (val < 0) {            /* implies '--' since we caught '-' above  */
369             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
370                     optarg_str_p);
371             return FALSE;
372         }
373     }
374     time_adj.tv.secs = val;
375
376     /* now collect the partial seconds, if any */
377     if (*frac != '\0') {             /* chars left, so get fractional part */
378         val = strtol(&(frac[1]), &end, 10);
379         /* if more than 9 fractional digits truncate to 9 */
380         if ((end - &(frac[1])) > 9) {
381             frac[10] = 't'; /* 't' for truncate */
382             val = strtol(&(frac[1]), &end, 10);
383         }
384         if (*frac != '.' || end == NULL || end == frac || val < 0
385             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
386             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
387                     optarg_str_p);
388             return FALSE;
389         }
390     } else {
391         return TRUE;                     /* no fractional digits */
392     }
393
394     /* adjust fractional portion from fractional to numerator
395      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
396     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
397     while(frac_digits < 9) {    /* this is frac of 10^9 */
398         val *= 10;
399         frac_digits++;
400     }
401
402     time_adj.tv.nsecs = (int)val;
403     return TRUE;
404 }
405
406 static gboolean
407 set_strict_time_adj(char *optarg_str_p)
408 {
409     char   *frac, *end;
410     long    val;
411     size_t  frac_digits;
412
413     if (!optarg_str_p)
414         return TRUE;
415
416     /* skip leading whitespace */
417     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
418         optarg_str_p++;
419
420     /*
421      * check for a negative adjustment
422      * A negative strict adjustment value is a flag
423      * to adjust all frames by the specifed delta time.
424      */
425     if (*optarg_str_p == '-') {
426         strict_time_adj.is_negative = 1;
427         optarg_str_p++;
428     }
429
430     /* collect whole number of seconds, if any */
431     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
432         val  = 0;
433         frac = optarg_str_p;
434     } else {
435         val = strtol(optarg_str_p, &frac, 10);
436         if (frac == NULL || frac == optarg_str_p
437             || val == LONG_MIN || val == LONG_MAX) {
438             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
439                     optarg_str_p);
440             return FALSE;
441         }
442         if (val < 0) {            /* implies '--' since we caught '-' above  */
443             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
444                     optarg_str_p);
445             return FALSE;
446         }
447     }
448     strict_time_adj.tv.secs = val;
449
450     /* now collect the partial seconds, if any */
451     if (*frac != '\0') {             /* chars left, so get fractional part */
452         val = strtol(&(frac[1]), &end, 10);
453         /* if more than 9 fractional digits truncate to 9 */
454         if ((end - &(frac[1])) > 9) {
455             frac[10] = 't'; /* 't' for truncate */
456             val = strtol(&(frac[1]), &end, 10);
457         }
458         if (*frac != '.' || end == NULL || end == frac || val < 0
459             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
460             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
461                     optarg_str_p);
462             return FALSE;
463         }
464     } else {
465         return TRUE;                     /* no fractional digits */
466     }
467
468     /* adjust fractional portion from fractional to numerator
469      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
470     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
471     while(frac_digits < 9) {    /* this is frac of 10^9 */
472         val *= 10;
473         frac_digits++;
474     }
475
476     strict_time_adj.tv.nsecs = (int)val;
477     return TRUE;
478 }
479
480 static gboolean
481 set_rel_time(char *optarg_str_p)
482 {
483     char   *frac, *end;
484     long    val;
485     size_t  frac_digits;
486
487     if (!optarg_str_p)
488         return TRUE;
489
490     /* skip leading whitespace */
491     while (*optarg_str_p == ' ' || *optarg_str_p == '\t')
492         optarg_str_p++;
493
494     /* ignore negative adjustment  */
495     if (*optarg_str_p == '-')
496         optarg_str_p++;
497
498     /* collect whole number of seconds, if any */
499     if (*optarg_str_p == '.') {         /* only fractional (i.e., .5 is ok) */
500         val  = 0;
501         frac = optarg_str_p;
502     } else {
503         val = strtol(optarg_str_p, &frac, 10);
504         if (frac == NULL || frac == optarg_str_p
505             || val == LONG_MIN || val == LONG_MAX) {
506             fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n",
507                     optarg_str_p);
508             return FALSE;
509         }
510         if (val < 0) {            /* implies '--' since we caught '-' above  */
511             fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n",
512                     optarg_str_p);
513             return FALSE;
514         }
515     }
516     relative_time_window.secs = val;
517
518     /* now collect the partial seconds, if any */
519     if (*frac != '\0') {             /* chars left, so get fractional part */
520         val = strtol(&(frac[1]), &end, 10);
521         /* if more than 9 fractional digits truncate to 9 */
522         if ((end - &(frac[1])) > 9) {
523             frac[10] = 't'; /* 't' for truncate */
524             val = strtol(&(frac[1]), &end, 10);
525         }
526         if (*frac != '.' || end == NULL || end == frac || val < 0
527             || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
528             fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
529                     optarg_str_p);
530             return FALSE;
531         }
532     } else {
533         return TRUE;                     /* no fractional digits */
534     }
535
536     /* adjust fractional portion from fractional to numerator
537      * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */
538     frac_digits = end - frac - 1;   /* fractional digit count (remember '.') */
539     while(frac_digits < 9) {    /* this is frac of 10^9 */
540         val *= 10;
541         frac_digits++;
542     }
543
544     relative_time_window.nsecs = (int)val;
545     return TRUE;
546 }
547
548 #define LINUX_SLL_OFFSETP 14
549 #define VLAN_SIZE 4
550 static void
551 sll_remove_vlan_info(guint8* fd, guint32* len) {
552     if (pntoh16(fd + LINUX_SLL_OFFSETP) == ETHERTYPE_VLAN) {
553         int rest_len;
554         /* point to start of vlan */
555         fd = fd + LINUX_SLL_OFFSETP;
556         /* bytes to read after vlan info */
557         rest_len = *len - (LINUX_SLL_OFFSETP + VLAN_SIZE);
558         /* remove vlan info from packet */
559         memmove(fd, fd + VLAN_SIZE, rest_len);
560         *len -= 4;
561     }
562 }
563
564 static void
565 remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) {
566     switch (phdr->pkt_encap) {
567         case WTAP_ENCAP_SLL:
568             sll_remove_vlan_info(fd, len);
569             break;
570         default:
571             /* no support for current pkt_encap */
572             break;
573     }
574 }
575
576 static gboolean
577 is_duplicate(guint8* fd, guint32 len) {
578     int i;
579
580     /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
581     guint32 offset = ignored_bytes;
582     guint32 new_len;
583     guint8 *new_fd;
584
585     if (len <= ignored_bytes) {
586         offset = 0;
587     }
588
589     new_fd  = &fd[offset];
590     new_len = len - (offset);
591
592     cur_dup_entry++;
593     if (cur_dup_entry >= dup_window)
594         cur_dup_entry = 0;
595
596     /* Calculate our digest */
597     gcry_md_hash_buffer(GCRY_MD_MD5, fd_hash[cur_dup_entry].digest, new_fd, new_len);
598
599     fd_hash[cur_dup_entry].len = len;
600
601     /* Look for duplicates */
602     for (i = 0; i < dup_window; i++) {
603         if (i == cur_dup_entry)
604             continue;
605
606         if (fd_hash[i].len == fd_hash[cur_dup_entry].len
607             && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
608             return TRUE;
609         }
610     }
611
612     return FALSE;
613 }
614
615 static gboolean
616 is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) {
617     int i;
618
619     /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
620     guint32 offset = ignored_bytes;
621     guint32 new_len;
622     guint8 *new_fd;
623
624     if (len <= ignored_bytes) {
625         offset = 0;
626     }
627
628     new_fd  = &fd[offset];
629     new_len = len - (offset);
630
631     cur_dup_entry++;
632     if (cur_dup_entry >= dup_window)
633         cur_dup_entry = 0;
634
635     /* Calculate our digest */
636     gcry_md_hash_buffer(GCRY_MD_MD5, fd_hash[cur_dup_entry].digest, new_fd, new_len);
637
638     fd_hash[cur_dup_entry].len = len;
639     fd_hash[cur_dup_entry].frame_time.secs = current->secs;
640     fd_hash[cur_dup_entry].frame_time.nsecs = current->nsecs;
641
642     /*
643      * Look for relative time related duplicates.
644      * This is hopefully a reasonably efficient mechanism for
645      * finding duplicates by rel time in the fd_hash[] cache.
646      * We check starting from the most recently added hash
647      * entries and work backwards towards older packets.
648      * This approach allows the dup test to be terminated
649      * when the relative time of a cached entry is found to
650      * be beyond the dup time window.
651      *
652      * Of course this assumes that the input trace file is
653      * "well-formed" in the sense that the packet timestamps are
654      * in strict chronologically increasing order (which is NOT
655      * always the case!!).
656      *
657      * The fd_hash[] table was deliberately created large (1,000,000).
658      * Looking for time related duplicates in large trace files with
659      * non-fractional dup time window values can potentially take
660      * a long time to complete.
661      */
662
663     for (i = cur_dup_entry - 1;; i--) {
664         nstime_t delta;
665         int cmp;
666
667         if (i < 0)
668             i = dup_window - 1;
669
670         if (i == cur_dup_entry) {
671             /*
672              * We've decremented back to where we started.
673              * Check no more!
674              */
675             break;
676         }
677
678         if (nstime_is_unset(&(fd_hash[i].frame_time))) {
679             /*
680              * We've decremented to an unused fd_hash[] entry.
681              * Check no more!
682              */
683             break;
684         }
685
686         nstime_delta(&delta, current, &fd_hash[i].frame_time);
687
688         if (delta.secs < 0 || delta.nsecs < 0) {
689             /*
690              * A negative delta implies that the current packet
691              * has an absolute timestamp less than the cached packet
692              * that it is being compared to.  This is NOT a normal
693              * situation since trace files usually have packets in
694              * chronological order (oldest to newest).
695              *
696              * There are several possible ways to deal with this:
697              * 1. 'continue' dup checking with the next cached frame.
698              * 2. 'break' from looking for a duplicate of the current frame.
699              * 3. Take the absolute value of the delta and see if that
700              * falls within the specifed dup time window.
701              *
702              * Currently this code does option 1.  But it would pretty
703              * easy to add yet-another-editcap-option to select one of
704              * the other behaviors for dealing with out-of-sequence
705              * packets.
706              */
707             continue;
708         }
709
710         cmp = nstime_cmp(&delta, &relative_time_window);
711
712         if (cmp > 0) {
713             /*
714              * The delta time indicates that we are now looking at
715              * cached packets beyond the specified dup time window.
716              * Check no more!
717              */
718             break;
719         } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len
720                    && memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) {
721             return TRUE;
722         }
723     }
724
725     return FALSE;
726 }
727
728 static void
729 print_usage(FILE *output)
730 {
731     fprintf(output, "\n");
732     fprintf(output, "Usage: editcap [options] ... <infile> <outfile> [ <packet#>[-<packet#>] ... ]\n");
733     fprintf(output, "\n");
734     fprintf(output, "<infile> and <outfile> must both be present.\n");
735     fprintf(output, "A single packet or a range of packets can be selected.\n");
736     fprintf(output, "\n");
737     fprintf(output, "Packet selection:\n");
738     fprintf(output, "  -r                     keep the selected packets; default is to delete them.\n");
739     fprintf(output, "  -A <start time>        only output packets whose timestamp is after (or equal\n");
740     fprintf(output, "                         to) the given time (format as YYYY-MM-DD hh:mm:ss).\n");
741     fprintf(output, "  -B <stop time>         only output packets whose timestamp is before the\n");
742     fprintf(output, "                         given time (format as YYYY-MM-DD hh:mm:ss).\n");
743     fprintf(output, "\n");
744     fprintf(output, "Duplicate packet removal:\n");
745     fprintf(output, "  --novlan               remove vlan info from packets before checking for duplicates.\n");
746     fprintf(output, "  -d                     remove packet if duplicate (window == %d).\n", DEFAULT_DUP_DEPTH);
747     fprintf(output, "  -D <dup window>        remove packet if duplicate; configurable <dup window>.\n");
748     fprintf(output, "                         Valid <dup window> values are 0 to %d.\n", MAX_DUP_DEPTH);
749     fprintf(output, "                         NOTE: A <dup window> of 0 with -v (verbose option) is\n");
750     fprintf(output, "                         useful to print MD5 hashes.\n");
751     fprintf(output, "  -w <dup time window>   remove packet if duplicate packet is found EQUAL TO OR\n");
752     fprintf(output, "                         LESS THAN <dup time window> prior to current packet.\n");
753     fprintf(output, "                         A <dup time window> is specified in relative seconds\n");
754     fprintf(output, "                         (e.g. 0.000001).\n");
755     fprintf(output, "  -a <framenum>:<comment> Add or replace comment for given frame number\n");
756     fprintf(output, "\n");
757     fprintf(output, "  -I <bytes to ignore>   ignore the specified number of bytes at the beginning\n");
758     fprintf(output, "                         of the frame during MD5 hash calculation, unless the\n");
759     fprintf(output, "                         frame is too short, then the full frame is used.\n");
760     fprintf(output, "                         Useful to remove duplicated packets taken on\n");
761     fprintf(output, "                         several routers (different mac addresses for\n");
762     fprintf(output, "                         example).\n");
763     fprintf(output, "                         e.g. -I 26 in case of Ether/IP will ignore\n");
764     fprintf(output, "                         ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
765     fprintf(output, "\n");
766     fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
767     fprintf(output, "           other editcap options except -v may not always work as expected.\n");
768     fprintf(output, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
769     fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
770     fprintf(output, "\n");
771     fprintf(output, "Packet manipulation:\n");
772     fprintf(output, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
773     fprintf(output, "  -C [offset:]<choplen>  chop each packet by <choplen> bytes. Positive values\n");
774     fprintf(output, "                         chop at the packet beginning, negative values at the\n");
775     fprintf(output, "                         packet end. If an optional offset precedes the length,\n");
776     fprintf(output, "                         then the bytes chopped will be offset from that value.\n");
777     fprintf(output, "                         Positive offsets are from the packet beginning,\n");
778     fprintf(output, "                         negative offsets are from the packet end. You can use\n");
779     fprintf(output, "                         this option more than once, allowing up to 2 chopping\n");
780     fprintf(output, "                         regions within a packet provided that at least 1\n");
781     fprintf(output, "                         choplen is positive and at least 1 is negative.\n");
782     fprintf(output, "  -L                     adjust the frame (i.e. reported) length when chopping\n");
783     fprintf(output, "                         and/or snapping.\n");
784     fprintf(output, "  -t <time adjustment>   adjust the timestamp of each packet.\n");
785     fprintf(output, "                         <time adjustment> is in relative seconds (e.g. -0.5).\n");
786     fprintf(output, "  -S <strict adjustment> adjust timestamp of packets if necessary to ensure\n");
787     fprintf(output, "                         strict chronological increasing order. The <strict\n");
788     fprintf(output, "                         adjustment> is specified in relative seconds with\n");
789     fprintf(output, "                         values of 0 or 0.000001 being the most reasonable.\n");
790     fprintf(output, "                         A negative adjustment value will modify timestamps so\n");
791     fprintf(output, "                         that each packet's delta time is the absolute value\n");
792     fprintf(output, "                         of the adjustment specified. A value of -0 will set\n");
793     fprintf(output, "                         all packets to the timestamp of the first packet.\n");
794     fprintf(output, "  -E <error probability> set the probability (between 0.0 and 1.0 incl.) that\n");
795     fprintf(output, "                         a particular packet byte will be randomly changed.\n");
796     fprintf(output, "  -o <change offset>     When used in conjunction with -E, skip some bytes from the\n");
797     fprintf(output, "                         beginning of the packet. This allows one to preserve some\n");
798     fprintf(output, "                         bytes, in order to have some headers untouched.\n");
799     fprintf(output, "\n");
800     fprintf(output, "Output File(s):\n");
801     fprintf(output, "  -c <packets per file>  split the packet output to different files based on\n");
802     fprintf(output, "                         uniform packet counts with a maximum of\n");
803     fprintf(output, "                         <packets per file> each.\n");
804     fprintf(output, "  -i <seconds per file>  split the packet output to different files based on\n");
805     fprintf(output, "                         uniform time intervals with a maximum of\n");
806     fprintf(output, "                         <seconds per file> each.\n");
807     fprintf(output, "  -F <capture type>      set the output file type; default is pcapng. An empty\n");
808     fprintf(output, "                         \"-F\" option will list the file types.\n");
809     fprintf(output, "  -T <encap type>        set the output file encapsulation type; default is the\n");
810     fprintf(output, "                         same as the input file. An empty \"-T\" option will\n");
811     fprintf(output, "                         list the encapsulation types.\n");
812     fprintf(output, "\n");
813     fprintf(output, "Miscellaneous:\n");
814     fprintf(output, "  -h                     display this help and exit.\n");
815     fprintf(output, "  -v                     verbose output.\n");
816     fprintf(output, "                         If -v is used with any of the 'Duplicate Packet\n");
817     fprintf(output, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
818     fprintf(output, "                         and MD5 hashes are printed to standard-error.\n");
819 }
820
821 struct string_elem {
822     const char *sstr;   /* The short string */
823     const char *lstr;   /* The long string */
824 };
825
826 static gint
827 string_compare(gconstpointer a, gconstpointer b)
828 {
829     return strcmp(((const struct string_elem *)a)->sstr,
830         ((const struct string_elem *)b)->sstr);
831 }
832
833 static gint
834 string_nat_compare(gconstpointer a, gconstpointer b)
835 {
836     return ws_ascii_strnatcmp(((const struct string_elem *)a)->sstr,
837         ((const struct string_elem *)b)->sstr);
838 }
839
840 static void
841 string_elem_print(gpointer data, gpointer stream_ptr)
842 {
843     fprintf((FILE *) stream_ptr, "    %s - %s\n",
844         ((struct string_elem *)data)->sstr,
845         ((struct string_elem *)data)->lstr);
846 }
847
848 static void
849 list_capture_types(FILE *stream) {
850     int i;
851     struct string_elem *captypes;
852     GSList *list = NULL;
853
854     captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES);
855     fprintf(stream, "editcap: The available capture file types for the \"-F\" flag are:\n");
856     for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
857         if (wtap_dump_can_open(i)) {
858             captypes[i].sstr = wtap_file_type_subtype_short_string(i);
859             captypes[i].lstr = wtap_file_type_subtype_string(i);
860             list = g_slist_insert_sorted(list, &captypes[i], string_compare);
861         }
862     }
863     g_slist_foreach(list, string_elem_print, stream);
864     g_slist_free(list);
865     g_free(captypes);
866 }
867
868 static void
869 list_encap_types(FILE *stream) {
870     int i;
871     struct string_elem *encaps;
872     GSList *list = NULL;
873
874     encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
875     fprintf(stream, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
876     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
877         encaps[i].sstr = wtap_encap_short_string(i);
878         if (encaps[i].sstr != NULL) {
879             encaps[i].lstr = wtap_encap_string(i);
880             list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare);
881         }
882     }
883     g_slist_foreach(list, string_elem_print, stream);
884     g_slist_free(list);
885     g_free(encaps);
886 }
887
888 static int
889 framenum_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
890 {
891     if (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b))
892         return -1;
893
894     if (GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b))
895         return 1;
896
897     return 0;
898 }
899
900 /*
901  * General errors and warnings are reported with an console message
902  * in editcap.
903  */
904 static void
905 failure_warning_message(const char *msg_format, va_list ap)
906 {
907   fprintf(stderr, "editcap: ");
908   vfprintf(stderr, msg_format, ap);
909   fprintf(stderr, "\n");
910 }
911
912 /*
913  * Report additional information for an error in command-line arguments.
914  */
915 static void
916 failure_message_cont(const char *msg_format, va_list ap)
917 {
918   vfprintf(stderr, msg_format, ap);
919   fprintf(stderr, "\n");
920 }
921
922 static wtap_dumper *
923 editcap_dump_open(const char *filename, guint32 snaplen,
924                   GArray* shb_hdrs,
925                   wtapng_iface_descriptions_t *idb_inf,
926                   GArray* nrb_hdrs, int *write_err)
927 {
928   wtap_dumper *pdh;
929
930   if (strcmp(filename, "-") == 0) {
931     /* Write to the standard output. */
932     pdh = wtap_dump_open_stdout_ng(out_file_type_subtype, out_frame_type,
933                                    snaplen, FALSE /* compressed */,
934                                    shb_hdrs, idb_inf, nrb_hdrs, write_err);
935   } else {
936     pdh = wtap_dump_open_ng(filename, out_file_type_subtype, out_frame_type,
937                             snaplen, FALSE /* compressed */,
938                             shb_hdrs, idb_inf, nrb_hdrs, write_err);
939   }
940   return pdh;
941 }
942
943 int
944 main(int argc, char *argv[])
945 {
946     GString      *comp_info_str;
947     GString      *runtime_info_str;
948     char         *init_progfile_dir_error;
949     wtap         *wth = NULL;
950     int           i, j, read_err, write_err;
951     gchar        *read_err_info, *write_err_info;
952     int           opt;
953     static const struct option long_options[] = {
954         {"novlan", no_argument, NULL, 0x8100},
955         {"help", no_argument, NULL, 'h'},
956         {"version", no_argument, NULL, 'V'},
957         {0, 0, 0, 0 }
958     };
959
960     char         *p;
961     guint32       snaplen            = 0; /* No limit               */
962     chop_t        chop               = {0, 0, 0, 0, 0, 0}; /* No chop */
963     gboolean      adjlen             = FALSE;
964     wtap_dumper  *pdh                = NULL;
965     unsigned int  count              = 1;
966     unsigned int  duplicate_count    = 0;
967     gint64        data_offset;
968     int           err_type;
969     guint8       *buf;
970     guint32       read_count         = 0;
971     guint32       split_packet_count = 0;
972     int           written_count      = 0;
973     char         *filename           = NULL;
974     gboolean      ts_okay;
975     guint32       secs_per_block     = 0;
976     int           block_cnt          = 0;
977     nstime_t      block_start;
978     gchar        *fprefix            = NULL;
979     gchar        *fsuffix            = NULL;
980     guint32       change_offset      = 0;
981     guint         max_packet_number  = 0;
982     const struct wtap_pkthdr    *phdr;
983     struct wtap_pkthdr           temp_phdr;
984     wtapng_iface_descriptions_t *idb_inf = NULL;
985     GArray                      *shb_hdrs = NULL;
986     GArray                      *nrb_hdrs = NULL;
987     char                        *shb_user_appl;
988     int                          ret = EXIT_SUCCESS;
989
990     cmdarg_err_init(failure_warning_message, failure_message_cont);
991
992 #ifdef _WIN32
993     arg_list_utf_16to8(argc, argv);
994     create_app_running_mutex();
995 #endif /* _WIN32 */
996
997     /* Get the compile-time version information string */
998     comp_info_str = get_compiled_version_info(NULL, NULL);
999
1000     /* Get the run-time version information string */
1001     runtime_info_str = get_runtime_version_info(NULL);
1002
1003     /* Add it to the information to be reported on a crash. */
1004     ws_add_crash_info("Editcap (Wireshark) %s\n"
1005          "\n"
1006          "%s"
1007          "\n"
1008          "%s",
1009       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
1010     g_string_free(comp_info_str, TRUE);
1011     g_string_free(runtime_info_str, TRUE);
1012
1013     /*
1014      * Get credential information for later use.
1015      */
1016     init_process_policies();
1017
1018     /*
1019      * Attempt to get the pathname of the directory containing the
1020      * executable file.
1021      */
1022     init_progfile_dir_error = init_progfile_dir(argv[0], main);
1023     if (init_progfile_dir_error != NULL) {
1024         fprintf(stderr,
1025                 "editcap: Can't get pathname of directory containing the editcap program: %s.\n",
1026                 init_progfile_dir_error);
1027         g_free(init_progfile_dir_error);
1028     }
1029
1030     wtap_init();
1031
1032 #ifdef HAVE_PLUGINS
1033     /* Register wiretap plugins */
1034     init_report_message(failure_warning_message, failure_warning_message,
1035                         NULL, NULL, NULL);
1036
1037     /* Scan for plugins.  This does *not* call their registration routines;
1038        that's done later.
1039
1040        Don't report failures to load plugins because most (non-wiretap)
1041        plugins *should* fail to load (because we're not linked against
1042        libwireshark and dissector plugins need libwireshark). */
1043     scan_plugins(DONT_REPORT_LOAD_FAILURE);
1044
1045     /* Register all libwiretap plugin modules. */
1046     register_all_wiretap_modules();
1047 #endif
1048
1049     /* Process the options */
1050     while ((opt = getopt_long(argc, argv, ":a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) {
1051         switch (opt) {
1052         case 0x8100:
1053         {
1054             rem_vlan = TRUE;
1055             break;
1056         }
1057
1058         case 'a':
1059         {
1060             guint frame_number;
1061             gint string_start_index = 0;
1062
1063             if ((sscanf(optarg, "%u:%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) {
1064                 fprintf(stderr, "editcap: \"%s\" isn't a valid <frame>:<comment>\n\n",
1065                         optarg);
1066                 ret = INVALID_OPTION;
1067                 goto clean_exit;
1068             }
1069
1070             /* Lazily create the table */
1071             if (!frames_user_comments) {
1072                 frames_user_comments = g_tree_new_full(framenum_compare, NULL, NULL, g_free);
1073             }
1074
1075             /* Insert this entry (framenum -> comment) */
1076             g_tree_replace(frames_user_comments, GUINT_TO_POINTER(frame_number), g_strdup(optarg+string_start_index));
1077             break;
1078         }
1079
1080         case 'A':
1081         {
1082             struct tm starttm;
1083
1084             memset(&starttm,0,sizeof(struct tm));
1085
1086             if (!strptime(optarg,"%Y-%m-%d %T", &starttm)) {
1087                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1088                         optarg);
1089                 ret = INVALID_OPTION;
1090                 goto clean_exit;
1091             }
1092
1093             check_startstop = TRUE;
1094             starttm.tm_isdst = -1;
1095
1096             starttime = mktime(&starttm);
1097             break;
1098         }
1099
1100         case 'B':
1101         {
1102             struct tm stoptm;
1103
1104             memset(&stoptm,0,sizeof(struct tm));
1105
1106             if (!strptime(optarg,"%Y-%m-%d %T", &stoptm)) {
1107                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1108                         optarg);
1109                 ret = INVALID_OPTION;
1110                 goto clean_exit;
1111             }
1112             check_startstop = TRUE;
1113             stoptm.tm_isdst = -1;
1114             stoptime = mktime(&stoptm);
1115             break;
1116         }
1117
1118         case 'c':
1119             split_packet_count = get_nonzero_guint32(optarg, "packet count");
1120             break;
1121
1122         case 'C':
1123         {
1124             int choplen = 0, chopoff = 0;
1125
1126             switch (sscanf(optarg, "%d:%d", &chopoff, &choplen)) {
1127             case 1: /* only the chop length was specififed */
1128                 choplen = chopoff;
1129                 chopoff = 0;
1130                 break;
1131
1132             case 2: /* both an offset and chop length was specified */
1133                 break;
1134
1135             default:
1136                 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length or offset:length\n",
1137                         optarg);
1138                 ret = INVALID_OPTION;
1139                 goto clean_exit;
1140                 break;
1141             }
1142
1143             if (choplen > 0) {
1144                 chop.len_begin += choplen;
1145                 if (chopoff > 0)
1146                     chop.off_begin_pos += chopoff;
1147                 else
1148                     chop.off_begin_neg += chopoff;
1149             } else if (choplen < 0) {
1150                 chop.len_end += choplen;
1151                 if (chopoff > 0)
1152                     chop.off_end_pos += chopoff;
1153                 else
1154                     chop.off_end_neg += chopoff;
1155             }
1156             break;
1157         }
1158
1159         case 'd':
1160             dup_detect = TRUE;
1161             dup_detect_by_time = FALSE;
1162             dup_window = DEFAULT_DUP_DEPTH;
1163             break;
1164
1165         case 'D':
1166             dup_detect = TRUE;
1167             dup_detect_by_time = FALSE;
1168             dup_window = get_guint32(optarg, "duplicate window");
1169             if (dup_window > MAX_DUP_DEPTH) {
1170                 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
1171                         dup_window, MAX_DUP_DEPTH);
1172                 ret = INVALID_OPTION;
1173                 goto clean_exit;
1174             }
1175             break;
1176
1177         case 'E':
1178             err_prob = g_ascii_strtod(optarg, &p);
1179             if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
1180                 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
1181                         optarg);
1182                 ret = INVALID_OPTION;
1183                 goto clean_exit;
1184             }
1185             srand( (unsigned int) (time(NULL) + ws_getpid()) );
1186             break;
1187
1188         case 'F':
1189             out_file_type_subtype = wtap_short_string_to_file_type_subtype(optarg);
1190             if (out_file_type_subtype < 0) {
1191                 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
1192                         optarg);
1193                 list_capture_types(stderr);
1194                 ret = INVALID_OPTION;
1195                 goto clean_exit;
1196             }
1197             break;
1198
1199         case 'h':
1200             printf("Editcap (Wireshark) %s\n"
1201                    "Edit and/or translate the format of capture files.\n"
1202                    "See https://www.wireshark.org for more information.\n",
1203                get_ws_vcs_version_info());
1204             print_usage(stdout);
1205             goto clean_exit;
1206             break;
1207
1208         case 'i': /* break capture file based on time interval */
1209             secs_per_block = get_nonzero_guint32(optarg, "time interval");
1210             break;
1211
1212         case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
1213             ignored_bytes = get_guint32(optarg, "number of bytes to ignore");
1214             break;
1215
1216         case 'L':
1217             adjlen = TRUE;
1218             break;
1219
1220         case 'o':
1221             change_offset = get_guint32(optarg, "change offset");
1222             break;
1223
1224         case 'r':
1225             keep_em = !keep_em;  /* Just invert */
1226             break;
1227
1228         case 's':
1229             snaplen = get_nonzero_guint32(optarg, "snapshot length");
1230             break;
1231
1232         case 'S':
1233             if (!set_strict_time_adj(optarg)) {
1234                 ret = INVALID_OPTION;
1235                 goto clean_exit;
1236             }
1237             do_strict_time_adjustment = TRUE;
1238             break;
1239
1240         case 't':
1241             if (!set_time_adjustment(optarg)) {
1242                 ret = INVALID_OPTION;
1243                 goto clean_exit;
1244             }
1245             break;
1246
1247         case 'T':
1248             out_frame_type = wtap_short_string_to_encap(optarg);
1249             if (out_frame_type < 0) {
1250                 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1251                         optarg);
1252                 list_encap_types(stderr);
1253                 ret = INVALID_OPTION;
1254                 goto clean_exit;
1255             }
1256             break;
1257
1258         case 'v':
1259             verbose = !verbose;  /* Just invert */
1260             break;
1261
1262         case 'V':
1263             comp_info_str = get_compiled_version_info(NULL, NULL);
1264             runtime_info_str = get_runtime_version_info(NULL);
1265             show_version("Editcap (Wireshark)", comp_info_str, runtime_info_str);
1266             g_string_free(comp_info_str, TRUE);
1267             g_string_free(runtime_info_str, TRUE);
1268             goto clean_exit;
1269             break;
1270
1271         case 'w':
1272             dup_detect = FALSE;
1273             dup_detect_by_time = TRUE;
1274             dup_window = MAX_DUP_DEPTH;
1275             if (!set_rel_time(optarg)) {
1276                 ret = INVALID_OPTION;
1277                 goto clean_exit;
1278             }
1279             break;
1280
1281         case '?':              /* Bad options if GNU getopt */
1282         case ':':              /* missing option argument */
1283             switch(optopt) {
1284             case'F':
1285                 list_capture_types(stdout);
1286                 break;
1287             case'T':
1288                 list_encap_types(stdout);
1289                 break;
1290             default:
1291                 if (opt == '?') {
1292                     fprintf(stderr, "editcap: invalid option -- '%c'\n", optopt);
1293                 } else {
1294                     fprintf(stderr, "editcap: option requires an argument -- '%c'\n", optopt);
1295                 }
1296                 print_usage(stderr);
1297                 ret = INVALID_OPTION;
1298                 break;
1299             }
1300             goto clean_exit;
1301             break;
1302         }
1303     } /* processing commmand-line options */
1304
1305 #ifdef DEBUG
1306     fprintf(stderr, "Optind = %i, argc = %i\n", optind, argc);
1307 #endif
1308
1309     if ((argc - optind) < 1) {
1310         print_usage(stderr);
1311         ret = INVALID_OPTION;
1312         goto clean_exit;
1313     }
1314
1315     if (check_startstop && !stoptime) {
1316         struct tm stoptm;
1317
1318         /* XXX: will work until 2035 */
1319         memset(&stoptm,0,sizeof(struct tm));
1320         stoptm.tm_year = 135;
1321         stoptm.tm_mday = 31;
1322         stoptm.tm_mon = 11;
1323
1324         stoptime = mktime(&stoptm);
1325     }
1326
1327     nstime_set_unset(&block_start);
1328
1329     if (starttime > stoptime) {
1330         fprintf(stderr, "editcap: start time is after the stop time\n");
1331         ret = INVALID_OPTION;
1332         goto clean_exit;
1333     }
1334
1335     if (split_packet_count != 0 && secs_per_block != 0) {
1336         fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1337         fprintf(stderr, "editcap: at the same time\n");
1338         ret = INVALID_OPTION;
1339         goto clean_exit;
1340     }
1341
1342     wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE);
1343
1344     if (!wth) {
1345         cfile_open_failure_message("editcap", argv[optind], read_err,
1346                                    read_err_info);
1347         ret = INVALID_FILE;
1348         goto clean_exit;
1349     }
1350
1351     if (verbose) {
1352         fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1353                 wtap_file_type_subtype_string(wtap_file_type_subtype(wth)));
1354     }
1355
1356     shb_hdrs = wtap_file_get_shb_for_new_file(wth);
1357     idb_inf = wtap_file_get_idb_info(wth);
1358     nrb_hdrs = wtap_file_get_nrb_for_new_file(wth);
1359
1360     /*
1361      * Now, process the rest, if any ... we only write if there is an extra
1362      * argument or so ...
1363      */
1364
1365     if ((argc - optind) >= 2) {
1366         if (out_frame_type == -2)
1367             out_frame_type = wtap_file_encap(wth);
1368
1369         for (i = optind + 2; i < argc; i++)
1370             if (add_selection(argv[i], &max_packet_number) == FALSE)
1371                 break;
1372
1373         if (keep_em == FALSE)
1374             max_packet_number = G_MAXUINT;
1375
1376         if (dup_detect || dup_detect_by_time) {
1377             for (i = 0; i < dup_window; i++) {
1378                 memset(&fd_hash[i].digest, 0, 16);
1379                 fd_hash[i].len = 0;
1380                 nstime_set_unset(&fd_hash[i].frame_time);
1381             }
1382         }
1383
1384         /* Read all of the packets in turn */
1385         while (wtap_read(wth, &read_err, &read_err_info, &data_offset)) {
1386             if (max_packet_number <= read_count)
1387                 break;
1388
1389             read_count++;
1390
1391             phdr = wtap_phdr(wth);
1392
1393             /* Extra actions for the first packet */
1394             if (read_count == 1) {
1395                 if (split_packet_count != 0 || secs_per_block != 0) {
1396                     if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix)) {
1397                         ret = CANT_EXTRACT_PREFIX;
1398                         goto clean_exit;
1399                     }
1400
1401                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1402                 } else {
1403                     filename = g_strdup(argv[optind+1]);
1404                 }
1405                 g_assert(filename);
1406
1407                 /* If we don't have an application name add Editcap */
1408                 if (wtap_block_get_string_option_value(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) {
1409                     wtap_block_add_string_option_format(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, "Editcap " VERSION);
1410                 }
1411
1412                 pdh = editcap_dump_open(filename,
1413                                         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1414                                         shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1415
1416                 if (pdh == NULL) {
1417                     cfile_dump_open_failure_message("editcap", filename,
1418                                                     write_err,
1419                                                     out_file_type_subtype);
1420                     ret = INVALID_FILE;
1421                     goto clean_exit;
1422                 }
1423             } /* first packet only handling */
1424
1425
1426             buf = wtap_buf_ptr(wth);
1427
1428             /*
1429              * Not all packets have time stamps. Only process the time
1430              * stamp if we have one.
1431              */
1432             if (phdr->presence_flags & WTAP_HAS_TS) {
1433                 if (nstime_is_unset(&block_start)) {
1434                     block_start = phdr->ts;
1435                 }
1436                 if (secs_per_block != 0) {
1437                     while (((guint32)(phdr->ts.secs - block_start.secs) >  secs_per_block)
1438                            || ((guint32)(phdr->ts.secs - block_start.secs) == secs_per_block
1439                                && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1440
1441                         if (!wtap_dump_close(pdh, &write_err)) {
1442                             cfile_close_failure_message(filename, write_err);
1443                             ret = WRITE_ERROR;
1444                             goto clean_exit;
1445                         }
1446                         block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1447                         g_free(filename);
1448                         filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1449                         g_assert(filename);
1450
1451                         if (verbose)
1452                             fprintf(stderr, "Continuing writing in file %s\n", filename);
1453
1454                         pdh = editcap_dump_open(filename,
1455                                                 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1456                                                 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1457
1458                         if (pdh == NULL) {
1459                             cfile_dump_open_failure_message("editcap", filename,
1460                                                             write_err,
1461                                                             out_file_type_subtype);
1462                             ret = INVALID_FILE;
1463                             goto clean_exit;
1464                         }
1465                     }
1466                 }
1467             }  /* time stamp handling */
1468
1469             if (split_packet_count != 0) {
1470                 /* time for the next file? */
1471                 if (written_count > 0 && (written_count % split_packet_count) == 0) {
1472                     if (!wtap_dump_close(pdh, &write_err)) {
1473                         cfile_close_failure_message(filename, write_err);
1474                         ret = WRITE_ERROR;
1475                         goto clean_exit;
1476                     }
1477
1478                     g_free(filename);
1479                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1480                     g_assert(filename);
1481
1482                     if (verbose)
1483                         fprintf(stderr, "Continuing writing in file %s\n", filename);
1484
1485                     pdh = editcap_dump_open(filename,
1486                                             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1487                                             shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1488                     if (pdh == NULL) {
1489                         cfile_dump_open_failure_message("editcap", filename,
1490                                                         write_err,
1491                                                         out_file_type_subtype);
1492                         ret = INVALID_FILE;
1493                         goto clean_exit;
1494                     }
1495                 }
1496             } /* split packet handling */
1497
1498             if (check_startstop) {
1499                 /*
1500                  * Is the packet in the selected timeframe?
1501                  * If the packet has no time stamp, the answer is "no".
1502                  */
1503                 if (phdr->presence_flags & WTAP_HAS_TS)
1504                     ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime);
1505                 else
1506                     ts_okay = FALSE;
1507             } else {
1508                 /*
1509                  * No selected timeframe, so all packets are "in the
1510                  * selected timeframe".
1511                  */
1512                 ts_okay = TRUE;
1513             }
1514
1515             if (ts_okay && ((!selected(count) && !keep_em)
1516                             || (selected(count) && keep_em))) {
1517
1518                 if (verbose && !dup_detect && !dup_detect_by_time)
1519                     fprintf(stderr, "Packet: %u\n", count);
1520
1521                 /* We simply write it, perhaps after truncating it; we could
1522                  * do other things, like modify it. */
1523
1524                 phdr = wtap_phdr(wth);
1525
1526                 if (snaplen != 0) {
1527                     /* Limit capture length to snaplen */
1528                     if (phdr->caplen > snaplen) {
1529                         /* Copy and change rather than modify returned phdr */
1530                         temp_phdr = *phdr;
1531                         temp_phdr.caplen = snaplen;
1532                         phdr = &temp_phdr;
1533                     }
1534                     /* If -L, also set reported length to snaplen */
1535                     if (adjlen && phdr->len > snaplen) {
1536                         /* Copy and change rather than modify returned phdr */
1537                         temp_phdr = *phdr;
1538                         temp_phdr.len = snaplen;
1539                         phdr = &temp_phdr;
1540                     }
1541                 }
1542
1543                 /* CHOP */
1544                 temp_phdr = *phdr;
1545                 handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen);
1546                 phdr = &temp_phdr;
1547
1548                 if (phdr->presence_flags & WTAP_HAS_TS) {
1549                     /* Do we adjust timestamps to ensure strict chronological
1550                      * order? */
1551                     if (do_strict_time_adjustment) {
1552                         if (previous_time.secs || previous_time.nsecs) {
1553                             if (!strict_time_adj.is_negative) {
1554                                 nstime_t current;
1555                                 nstime_t delta;
1556
1557                                 current = phdr->ts;
1558
1559                                 nstime_delta(&delta, &current, &previous_time);
1560
1561                                 if (delta.secs < 0 || delta.nsecs < 0) {
1562                                     /*
1563                                      * A negative delta indicates that the current packet
1564                                      * has an absolute timestamp less than the previous packet
1565                                      * that it is being compared to.  This is NOT a normal
1566                                      * situation since trace files usually have packets in
1567                                      * chronological order (oldest to newest).
1568                                      */
1569                                     /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
1570                                     temp_phdr = *phdr;
1571                                     temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1572                                     temp_phdr.ts.nsecs = previous_time.nsecs;
1573                                     if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1574                                         /* carry */
1575                                         temp_phdr.ts.secs++;
1576                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1577                                     } else {
1578                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1579                                     }
1580                                     phdr = &temp_phdr;
1581                                 }
1582                             } else {
1583                                 /*
1584                                  * A negative strict time adjustment is requested.
1585                                  * Unconditionally set each timestamp to previous
1586                                  * packet's timestamp plus delta.
1587                                  */
1588                                 temp_phdr = *phdr;
1589                                 temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1590                                 temp_phdr.ts.nsecs = previous_time.nsecs;
1591                                 if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1592                                     /* carry */
1593                                     temp_phdr.ts.secs++;
1594                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1595                                 } else {
1596                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1597                                 }
1598                                 phdr = &temp_phdr;
1599                             }
1600                         }
1601                         previous_time = phdr->ts;
1602                     }
1603
1604                     if (time_adj.tv.secs != 0) {
1605                         temp_phdr = *phdr;
1606                         if (time_adj.is_negative)
1607                             temp_phdr.ts.secs -= time_adj.tv.secs;
1608                         else
1609                             temp_phdr.ts.secs += time_adj.tv.secs;
1610                         phdr = &temp_phdr;
1611                     }
1612
1613                     if (time_adj.tv.nsecs != 0) {
1614                         temp_phdr = *phdr;
1615                         if (time_adj.is_negative) { /* subtract */
1616                             if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
1617                                 temp_phdr.ts.secs--;
1618                                 temp_phdr.ts.nsecs += ONE_BILLION;
1619                             }
1620                             temp_phdr.ts.nsecs -= time_adj.tv.nsecs;
1621                         } else {                  /* add */
1622                             if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) {
1623                                 /* carry */
1624                                 temp_phdr.ts.secs++;
1625                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
1626                             } else {
1627                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs;
1628                             }
1629                         }
1630                         phdr = &temp_phdr;
1631                     }
1632                 } /* time stamp adjustment */
1633
1634                 /* remove vlan info */
1635                 if (rem_vlan) {
1636                     /* TODO: keep casting const like this? change pointer instead of value? */
1637                     remove_vlan_info(phdr, buf, (guint32 *) &phdr->caplen);
1638                 }
1639
1640                 /* suppress duplicates by packet window */
1641                 if (dup_detect) {
1642                     if (is_duplicate(buf, phdr->caplen)) {
1643                         if (verbose) {
1644                             fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1645                                     count, phdr->caplen);
1646                             for (i = 0; i < 16; i++)
1647                                 fprintf(stderr, "%02x",
1648                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1649                             fprintf(stderr, "\n");
1650                         }
1651                         duplicate_count++;
1652                         count++;
1653                         continue;
1654                     } else {
1655                         if (verbose) {
1656                             fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1657                                     count, phdr->caplen);
1658                             for (i = 0; i < 16; i++)
1659                                 fprintf(stderr, "%02x",
1660                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1661                             fprintf(stderr, "\n");
1662                         }
1663                     }
1664                 } /* suppression of duplicates */
1665
1666                 if (phdr->presence_flags & WTAP_HAS_TS) {
1667                     /* suppress duplicates by time window */
1668                     if (dup_detect_by_time) {
1669                         nstime_t current;
1670
1671                         current.secs  = phdr->ts.secs;
1672                         current.nsecs = phdr->ts.nsecs;
1673
1674                         if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1675                             if (verbose) {
1676                                 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1677                                         count, phdr->caplen);
1678                                 for (i = 0; i < 16; i++)
1679                                     fprintf(stderr, "%02x",
1680                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1681                                 fprintf(stderr, "\n");
1682                             }
1683                             duplicate_count++;
1684                             count++;
1685                             continue;
1686                         } else {
1687                             if (verbose) {
1688                                 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1689                                         count, phdr->caplen);
1690                                 for (i = 0; i < 16; i++)
1691                                     fprintf(stderr, "%02x",
1692                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1693                                 fprintf(stderr, "\n");
1694                             }
1695                         }
1696                     }
1697                 } /* suppress duplicates by time window */
1698
1699                 if (change_offset > phdr->caplen) {
1700                     fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
1701                         change_offset, phdr->caplen, count);
1702                 }
1703
1704                 /* Random error mutation */
1705                 if (err_prob > 0.0 && change_offset <= phdr->caplen) {
1706                     int real_data_start = 0;
1707
1708                     /* Protect non-protocol data */
1709                     if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
1710                         real_data_start = find_dct2000_real_data(buf);
1711
1712                     real_data_start += change_offset;
1713
1714                     for (i = real_data_start; i < (int) phdr->caplen; i++) {
1715                         if (rand() <= err_prob * RAND_MAX) {
1716                             err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1717
1718                             if (err_type < ERR_WT_BIT) {
1719                                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1720                                 err_type = ERR_WT_TOTAL;
1721                             } else {
1722                                 err_type -= ERR_WT_BYTE;
1723                             }
1724
1725                             if (err_type < ERR_WT_BYTE) {
1726                                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1727                                 err_type = ERR_WT_TOTAL;
1728                             } else {
1729                                 err_type -= ERR_WT_BYTE;
1730                             }
1731
1732                             if (err_type < ERR_WT_ALNUM) {
1733                                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1734                                 err_type = ERR_WT_TOTAL;
1735                             } else {
1736                                 err_type -= ERR_WT_ALNUM;
1737                             }
1738
1739                             if (err_type < ERR_WT_FMT) {
1740                                 if ((unsigned int)i < phdr->caplen - 2)
1741                                     g_strlcpy((char*) &buf[i], "%s", 2);
1742                                 err_type = ERR_WT_TOTAL;
1743                             } else {
1744                                 err_type -= ERR_WT_FMT;
1745                             }
1746
1747                             if (err_type < ERR_WT_AA) {
1748                                 for (j = i; j < (int) phdr->caplen; j++)
1749                                     buf[j] = 0xAA;
1750                                 i = phdr->caplen;
1751                             }
1752                         }
1753                     }
1754                 } /* random error mutation */
1755
1756                 /* Find a packet comment we may need to write */
1757                 if (frames_user_comments) {
1758                     const char *comment =
1759                         (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count));
1760                     /* XXX: What about comment changed to no comment? */
1761                     if (comment != NULL) {
1762                         /* Copy and change rather than modify returned phdr */
1763                         temp_phdr = *phdr;
1764                         temp_phdr.opt_comment = g_strdup(comment);
1765                         temp_phdr.has_comment_changed = TRUE;
1766                         phdr = &temp_phdr;
1767                     } else {
1768                         temp_phdr = *phdr;
1769                         temp_phdr.has_comment_changed = FALSE;
1770                         phdr = &temp_phdr;
1771                     }
1772                 }
1773
1774                 /* Attempt to dump out current frame to the output file */
1775                 if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) {
1776                     cfile_write_failure_message("editcap", argv[optind],
1777                                                 filename,
1778                                                 write_err, write_err_info,
1779                                                 read_count,
1780                                                 out_file_type_subtype);
1781                     ret = DUMP_ERROR;
1782                     goto clean_exit;
1783                 }
1784                 written_count++;
1785             }
1786             count++;
1787         }
1788
1789         g_free(fprefix);
1790         g_free(fsuffix);
1791
1792         if (read_err != 0) {
1793             /* Print a message noting that the read failed somewhere along the
1794              * line. */
1795             cfile_read_failure_message("editcap", argv[optind], read_err,
1796                                        read_err_info);
1797         }
1798
1799         if (!pdh) {
1800             /* No valid packages found, open the outfile so we can write an
1801              * empty header */
1802             g_free (filename);
1803             filename = g_strdup(argv[optind+1]);
1804
1805             pdh = editcap_dump_open(filename,
1806                                     snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1807                                     shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1808             if (pdh == NULL) {
1809                 cfile_dump_open_failure_message("editcap", filename,
1810                                                 write_err,
1811                                                 out_file_type_subtype);
1812                 ret = INVALID_FILE;
1813                 goto clean_exit;
1814             }
1815         }
1816
1817         if (!wtap_dump_close(pdh, &write_err)) {
1818             cfile_close_failure_message(filename, write_err);
1819             ret = WRITE_ERROR;
1820             goto clean_exit;
1821         }
1822         g_free(filename);
1823
1824         if (frames_user_comments) {
1825             g_tree_destroy(frames_user_comments);
1826         }
1827     }
1828
1829     if (dup_detect) {
1830         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate window of %i packets.\n",
1831                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1832                 plurality(duplicate_count, "", "s"), dup_window);
1833     } else if (dup_detect_by_time) {
1834         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1835                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1836                 plurality(duplicate_count, "", "s"),
1837                 (long)relative_time_window.secs,
1838                 (long int)relative_time_window.nsecs);
1839     }
1840
1841 clean_exit:
1842     wtap_block_array_free(shb_hdrs);
1843     wtap_block_array_free(nrb_hdrs);
1844     g_free(idb_inf);
1845     if (wth != NULL)
1846         wtap_close(wth);
1847     wtap_cleanup();
1848     free_progdirs();
1849 #ifdef HAVE_PLUGINS
1850     plugins_cleanup();
1851 #endif
1852     return ret;
1853 }
1854
1855 /* Skip meta-information read from file to return offset of real
1856  * protocol data */
1857 static int
1858 find_dct2000_real_data(guint8 *buf)
1859 {
1860     int n = 0;
1861
1862     for (n = 0; buf[n] != '\0'; n++);   /* Context name */
1863     n++;
1864     n++;                                /* Context port number */
1865     for (; buf[n] != '\0'; n++);        /* Timestamp */
1866     n++;
1867     for (; buf[n] != '\0'; n++);        /* Protocol name */
1868     n++;
1869     for (; buf[n] != '\0'; n++);        /* Variant number (as string) */
1870     n++;
1871     for (; buf[n] != '\0'; n++);        /* Outhdr (as string) */
1872     n++;
1873     n += 2;                             /* Direction & encap */
1874
1875     return n;
1876 }
1877
1878 /*
1879  * We support up to 2 chopping regions in a single pass: one specified by the
1880  * positive chop length, and one by the negative chop length.
1881  */
1882 static void
1883 handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
1884                 const struct wtap_pkthdr *in_phdr, guint8 **buf,
1885                 gboolean adjlen)
1886 {
1887     /* Only packets can be chopped. */
1888     if (in_phdr->rec_type != REC_TYPE_PACKET)
1889         return;
1890
1891     /* If we're not chopping anything from one side, then the offset for that
1892      * side is meaningless. */
1893     if (chop.len_begin == 0)
1894         chop.off_begin_pos = chop.off_begin_neg = 0;
1895     if (chop.len_end == 0)
1896         chop.off_end_pos = chop.off_end_neg = 0;
1897
1898     if (chop.off_begin_neg < 0) {
1899         chop.off_begin_pos += in_phdr->caplen + chop.off_begin_neg;
1900         chop.off_begin_neg = 0;
1901     }
1902     if (chop.off_end_pos > 0) {
1903         chop.off_end_neg += chop.off_end_pos - in_phdr->caplen;
1904         chop.off_end_pos = 0;
1905     }
1906
1907     /* If we've crossed chopping regions, swap them */
1908     if (chop.len_begin && chop.len_end) {
1909         if (chop.off_begin_pos > ((int)in_phdr->caplen + chop.off_end_neg)) {
1910             int tmp_len, tmp_off;
1911
1912             tmp_off = in_phdr->caplen + chop.off_end_neg + chop.len_end;
1913             tmp_len = -chop.len_end;
1914
1915             chop.off_end_neg = chop.len_begin + chop.off_begin_pos - in_phdr->caplen;
1916             chop.len_end = -chop.len_begin;
1917
1918             chop.len_begin = tmp_len;
1919             chop.off_begin_pos = tmp_off;
1920         }
1921     }
1922
1923     /* Make sure we don't chop off more than we have available */
1924     if (in_phdr->caplen < (guint32)(chop.off_begin_pos - chop.off_end_neg)) {
1925         chop.len_begin = 0;
1926         chop.len_end = 0;
1927     }
1928     if ((guint32)(chop.len_begin - chop.len_end) >
1929         (in_phdr->caplen - (guint32)(chop.off_begin_pos - chop.off_end_neg))) {
1930         chop.len_begin = in_phdr->caplen - (chop.off_begin_pos - chop.off_end_neg);
1931         chop.len_end = 0;
1932     }
1933
1934     /* Handle chopping from the beginning.  Note that if a beginning offset
1935      * was specified, we need to keep that piece */
1936     if (chop.len_begin > 0) {
1937         *out_phdr = *in_phdr;
1938
1939         if (chop.off_begin_pos > 0) {
1940             memmove(*buf + chop.off_begin_pos,
1941                     *buf + chop.off_begin_pos + chop.len_begin,
1942                     out_phdr->caplen - chop.len_begin);
1943         } else {
1944             *buf += chop.len_begin;
1945         }
1946         out_phdr->caplen -= chop.len_begin;
1947
1948         if (adjlen) {
1949             if (in_phdr->len > (guint32)chop.len_begin)
1950                 out_phdr->len -= chop.len_begin;
1951             else
1952                 out_phdr->len = 0;
1953         }
1954         in_phdr = out_phdr;
1955     }
1956
1957     /* Handle chopping from the end.  Note that if an ending offset was
1958      * specified, we need to keep that piece */
1959     if (chop.len_end < 0) {
1960         *out_phdr = *in_phdr;
1961
1962         if (chop.off_end_neg < 0) {
1963             memmove(*buf + (gint)out_phdr->caplen + (chop.len_end + chop.off_end_neg),
1964                     *buf + (gint)out_phdr->caplen + chop.off_end_neg,
1965                     -chop.off_end_neg);
1966         }
1967         out_phdr->caplen += chop.len_end;
1968
1969         if (adjlen) {
1970             if (((signed int) in_phdr->len + chop.len_end) > 0)
1971                 out_phdr->len += chop.len_end;
1972             else
1973                 out_phdr->len = 0;
1974         }
1975         /*in_phdr = out_phdr;*/
1976     }
1977 }
1978
1979 /*
1980  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1981  *
1982  * Local variables:
1983  * c-basic-offset: 4
1984  * tab-width: 8
1985  * indent-tabs-mode: nil
1986  * End:
1987  *
1988  * vi: set shiftwidth=4 tabstop=8 expandtab:
1989  * :indentSize=4:tabSize=8:noTabs=true:
1990  */