Qt+WiX: Skip translations.
[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     init_report_message(failure_warning_message, failure_warning_message,
1031                         NULL, NULL, NULL);
1032
1033     wtap_init(TRUE);
1034
1035     /* Process the options */
1036     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) {
1037         switch (opt) {
1038         case 0x8100:
1039         {
1040             rem_vlan = TRUE;
1041             break;
1042         }
1043
1044         case 'a':
1045         {
1046             guint frame_number;
1047             gint string_start_index = 0;
1048
1049             if ((sscanf(optarg, "%u:%n", &frame_number, &string_start_index) < 1) || (string_start_index == 0)) {
1050                 fprintf(stderr, "editcap: \"%s\" isn't a valid <frame>:<comment>\n\n",
1051                         optarg);
1052                 ret = INVALID_OPTION;
1053                 goto clean_exit;
1054             }
1055
1056             /* Lazily create the table */
1057             if (!frames_user_comments) {
1058                 frames_user_comments = g_tree_new_full(framenum_compare, NULL, NULL, g_free);
1059             }
1060
1061             /* Insert this entry (framenum -> comment) */
1062             g_tree_replace(frames_user_comments, GUINT_TO_POINTER(frame_number), g_strdup(optarg+string_start_index));
1063             break;
1064         }
1065
1066         case 'A':
1067         {
1068             struct tm starttm;
1069
1070             memset(&starttm,0,sizeof(struct tm));
1071
1072             if (!strptime(optarg,"%Y-%m-%d %T", &starttm)) {
1073                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1074                         optarg);
1075                 ret = INVALID_OPTION;
1076                 goto clean_exit;
1077             }
1078
1079             check_startstop = TRUE;
1080             starttm.tm_isdst = -1;
1081
1082             starttime = mktime(&starttm);
1083             break;
1084         }
1085
1086         case 'B':
1087         {
1088             struct tm stoptm;
1089
1090             memset(&stoptm,0,sizeof(struct tm));
1091
1092             if (!strptime(optarg,"%Y-%m-%d %T", &stoptm)) {
1093                 fprintf(stderr, "editcap: \"%s\" isn't a valid time format\n\n",
1094                         optarg);
1095                 ret = INVALID_OPTION;
1096                 goto clean_exit;
1097             }
1098             check_startstop = TRUE;
1099             stoptm.tm_isdst = -1;
1100             stoptime = mktime(&stoptm);
1101             break;
1102         }
1103
1104         case 'c':
1105             split_packet_count = get_nonzero_guint32(optarg, "packet count");
1106             break;
1107
1108         case 'C':
1109         {
1110             int choplen = 0, chopoff = 0;
1111
1112             switch (sscanf(optarg, "%d:%d", &chopoff, &choplen)) {
1113             case 1: /* only the chop length was specififed */
1114                 choplen = chopoff;
1115                 chopoff = 0;
1116                 break;
1117
1118             case 2: /* both an offset and chop length was specified */
1119                 break;
1120
1121             default:
1122                 fprintf(stderr, "editcap: \"%s\" isn't a valid chop length or offset:length\n",
1123                         optarg);
1124                 ret = INVALID_OPTION;
1125                 goto clean_exit;
1126                 break;
1127             }
1128
1129             if (choplen > 0) {
1130                 chop.len_begin += choplen;
1131                 if (chopoff > 0)
1132                     chop.off_begin_pos += chopoff;
1133                 else
1134                     chop.off_begin_neg += chopoff;
1135             } else if (choplen < 0) {
1136                 chop.len_end += choplen;
1137                 if (chopoff > 0)
1138                     chop.off_end_pos += chopoff;
1139                 else
1140                     chop.off_end_neg += chopoff;
1141             }
1142             break;
1143         }
1144
1145         case 'd':
1146             dup_detect = TRUE;
1147             dup_detect_by_time = FALSE;
1148             dup_window = DEFAULT_DUP_DEPTH;
1149             break;
1150
1151         case 'D':
1152             dup_detect = TRUE;
1153             dup_detect_by_time = FALSE;
1154             dup_window = get_guint32(optarg, "duplicate window");
1155             if (dup_window > MAX_DUP_DEPTH) {
1156                 fprintf(stderr, "editcap: \"%d\" duplicate window value must be between 0 and %d inclusive.\n",
1157                         dup_window, MAX_DUP_DEPTH);
1158                 ret = INVALID_OPTION;
1159                 goto clean_exit;
1160             }
1161             break;
1162
1163         case 'E':
1164             err_prob = g_ascii_strtod(optarg, &p);
1165             if (p == optarg || err_prob < 0.0 || err_prob > 1.0) {
1166                 fprintf(stderr, "editcap: probability \"%s\" must be between 0.0 and 1.0\n",
1167                         optarg);
1168                 ret = INVALID_OPTION;
1169                 goto clean_exit;
1170             }
1171             srand( (unsigned int) (time(NULL) + ws_getpid()) );
1172             break;
1173
1174         case 'F':
1175             out_file_type_subtype = wtap_short_string_to_file_type_subtype(optarg);
1176             if (out_file_type_subtype < 0) {
1177                 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
1178                         optarg);
1179                 list_capture_types(stderr);
1180                 ret = INVALID_OPTION;
1181                 goto clean_exit;
1182             }
1183             break;
1184
1185         case 'h':
1186             printf("Editcap (Wireshark) %s\n"
1187                    "Edit and/or translate the format of capture files.\n"
1188                    "See https://www.wireshark.org for more information.\n",
1189                get_ws_vcs_version_info());
1190             print_usage(stdout);
1191             goto clean_exit;
1192             break;
1193
1194         case 'i': /* break capture file based on time interval */
1195             secs_per_block = get_nonzero_guint32(optarg, "time interval");
1196             break;
1197
1198         case 'I': /* ignored_bytes at the beginning of the frame for duplications removal */
1199             ignored_bytes = get_guint32(optarg, "number of bytes to ignore");
1200             break;
1201
1202         case 'L':
1203             adjlen = TRUE;
1204             break;
1205
1206         case 'o':
1207             change_offset = get_guint32(optarg, "change offset");
1208             break;
1209
1210         case 'r':
1211             keep_em = !keep_em;  /* Just invert */
1212             break;
1213
1214         case 's':
1215             snaplen = get_nonzero_guint32(optarg, "snapshot length");
1216             break;
1217
1218         case 'S':
1219             if (!set_strict_time_adj(optarg)) {
1220                 ret = INVALID_OPTION;
1221                 goto clean_exit;
1222             }
1223             do_strict_time_adjustment = TRUE;
1224             break;
1225
1226         case 't':
1227             if (!set_time_adjustment(optarg)) {
1228                 ret = INVALID_OPTION;
1229                 goto clean_exit;
1230             }
1231             break;
1232
1233         case 'T':
1234             out_frame_type = wtap_short_string_to_encap(optarg);
1235             if (out_frame_type < 0) {
1236                 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
1237                         optarg);
1238                 list_encap_types(stderr);
1239                 ret = INVALID_OPTION;
1240                 goto clean_exit;
1241             }
1242             break;
1243
1244         case 'v':
1245             verbose = !verbose;  /* Just invert */
1246             break;
1247
1248         case 'V':
1249             comp_info_str = get_compiled_version_info(NULL, NULL);
1250             runtime_info_str = get_runtime_version_info(NULL);
1251             show_version("Editcap (Wireshark)", comp_info_str, runtime_info_str);
1252             g_string_free(comp_info_str, TRUE);
1253             g_string_free(runtime_info_str, TRUE);
1254             goto clean_exit;
1255             break;
1256
1257         case 'w':
1258             dup_detect = FALSE;
1259             dup_detect_by_time = TRUE;
1260             dup_window = MAX_DUP_DEPTH;
1261             if (!set_rel_time(optarg)) {
1262                 ret = INVALID_OPTION;
1263                 goto clean_exit;
1264             }
1265             break;
1266
1267         case '?':              /* Bad options if GNU getopt */
1268         case ':':              /* missing option argument */
1269             switch(optopt) {
1270             case'F':
1271                 list_capture_types(stdout);
1272                 break;
1273             case'T':
1274                 list_encap_types(stdout);
1275                 break;
1276             default:
1277                 if (opt == '?') {
1278                     fprintf(stderr, "editcap: invalid option -- '%c'\n", optopt);
1279                 } else {
1280                     fprintf(stderr, "editcap: option requires an argument -- '%c'\n", optopt);
1281                 }
1282                 print_usage(stderr);
1283                 ret = INVALID_OPTION;
1284                 break;
1285             }
1286             goto clean_exit;
1287             break;
1288         }
1289     } /* processing commmand-line options */
1290
1291 #ifdef DEBUG
1292     fprintf(stderr, "Optind = %i, argc = %i\n", optind, argc);
1293 #endif
1294
1295     if ((argc - optind) < 1) {
1296         print_usage(stderr);
1297         ret = INVALID_OPTION;
1298         goto clean_exit;
1299     }
1300
1301     if (check_startstop && !stoptime) {
1302         struct tm stoptm;
1303
1304         /* XXX: will work until 2035 */
1305         memset(&stoptm,0,sizeof(struct tm));
1306         stoptm.tm_year = 135;
1307         stoptm.tm_mday = 31;
1308         stoptm.tm_mon = 11;
1309
1310         stoptime = mktime(&stoptm);
1311     }
1312
1313     nstime_set_unset(&block_start);
1314
1315     if (starttime > stoptime) {
1316         fprintf(stderr, "editcap: start time is after the stop time\n");
1317         ret = INVALID_OPTION;
1318         goto clean_exit;
1319     }
1320
1321     if (split_packet_count != 0 && secs_per_block != 0) {
1322         fprintf(stderr, "editcap: can't split on both packet count and time interval\n");
1323         fprintf(stderr, "editcap: at the same time\n");
1324         ret = INVALID_OPTION;
1325         goto clean_exit;
1326     }
1327
1328     wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE);
1329
1330     if (!wth) {
1331         cfile_open_failure_message("editcap", argv[optind], read_err,
1332                                    read_err_info);
1333         ret = INVALID_FILE;
1334         goto clean_exit;
1335     }
1336
1337     if (verbose) {
1338         fprintf(stderr, "File %s is a %s capture file.\n", argv[optind],
1339                 wtap_file_type_subtype_string(wtap_file_type_subtype(wth)));
1340     }
1341
1342     shb_hdrs = wtap_file_get_shb_for_new_file(wth);
1343     idb_inf = wtap_file_get_idb_info(wth);
1344     nrb_hdrs = wtap_file_get_nrb_for_new_file(wth);
1345
1346     /*
1347      * Now, process the rest, if any ... we only write if there is an extra
1348      * argument or so ...
1349      */
1350
1351     if ((argc - optind) >= 2) {
1352         if (out_frame_type == -2)
1353             out_frame_type = wtap_file_encap(wth);
1354
1355         for (i = optind + 2; i < argc; i++)
1356             if (add_selection(argv[i], &max_packet_number) == FALSE)
1357                 break;
1358
1359         if (keep_em == FALSE)
1360             max_packet_number = G_MAXUINT;
1361
1362         if (dup_detect || dup_detect_by_time) {
1363             for (i = 0; i < dup_window; i++) {
1364                 memset(&fd_hash[i].digest, 0, 16);
1365                 fd_hash[i].len = 0;
1366                 nstime_set_unset(&fd_hash[i].frame_time);
1367             }
1368         }
1369
1370         /* Read all of the packets in turn */
1371         while (wtap_read(wth, &read_err, &read_err_info, &data_offset)) {
1372             if (max_packet_number <= read_count)
1373                 break;
1374
1375             read_count++;
1376
1377             phdr = wtap_phdr(wth);
1378
1379             /* Extra actions for the first packet */
1380             if (read_count == 1) {
1381                 if (split_packet_count != 0 || secs_per_block != 0) {
1382                     if (!fileset_extract_prefix_suffix(argv[optind+1], &fprefix, &fsuffix)) {
1383                         ret = CANT_EXTRACT_PREFIX;
1384                         goto clean_exit;
1385                     }
1386
1387                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1388                 } else {
1389                     filename = g_strdup(argv[optind+1]);
1390                 }
1391                 g_assert(filename);
1392
1393                 /* If we don't have an application name add Editcap */
1394                 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) {
1395                     wtap_block_add_string_option_format(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, "Editcap " VERSION);
1396                 }
1397
1398                 pdh = editcap_dump_open(filename,
1399                                         snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1400                                         shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1401
1402                 if (pdh == NULL) {
1403                     cfile_dump_open_failure_message("editcap", filename,
1404                                                     write_err,
1405                                                     out_file_type_subtype);
1406                     ret = INVALID_FILE;
1407                     goto clean_exit;
1408                 }
1409             } /* first packet only handling */
1410
1411
1412             buf = wtap_buf_ptr(wth);
1413
1414             /*
1415              * Not all packets have time stamps. Only process the time
1416              * stamp if we have one.
1417              */
1418             if (phdr->presence_flags & WTAP_HAS_TS) {
1419                 if (nstime_is_unset(&block_start)) {
1420                     block_start = phdr->ts;
1421                 }
1422                 if (secs_per_block != 0) {
1423                     while (((guint32)(phdr->ts.secs - block_start.secs) >  secs_per_block)
1424                            || ((guint32)(phdr->ts.secs - block_start.secs) == secs_per_block
1425                                && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
1426
1427                         if (!wtap_dump_close(pdh, &write_err)) {
1428                             cfile_close_failure_message(filename, write_err);
1429                             ret = WRITE_ERROR;
1430                             goto clean_exit;
1431                         }
1432                         block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
1433                         g_free(filename);
1434                         filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1435                         g_assert(filename);
1436
1437                         if (verbose)
1438                             fprintf(stderr, "Continuing writing in file %s\n", filename);
1439
1440                         pdh = editcap_dump_open(filename,
1441                                                 snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1442                                                 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1443
1444                         if (pdh == NULL) {
1445                             cfile_dump_open_failure_message("editcap", filename,
1446                                                             write_err,
1447                                                             out_file_type_subtype);
1448                             ret = INVALID_FILE;
1449                             goto clean_exit;
1450                         }
1451                     }
1452                 }
1453             }  /* time stamp handling */
1454
1455             if (split_packet_count != 0) {
1456                 /* time for the next file? */
1457                 if (written_count > 0 && (written_count % split_packet_count) == 0) {
1458                     if (!wtap_dump_close(pdh, &write_err)) {
1459                         cfile_close_failure_message(filename, write_err);
1460                         ret = WRITE_ERROR;
1461                         goto clean_exit;
1462                     }
1463
1464                     g_free(filename);
1465                     filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
1466                     g_assert(filename);
1467
1468                     if (verbose)
1469                         fprintf(stderr, "Continuing writing in file %s\n", filename);
1470
1471                     pdh = editcap_dump_open(filename,
1472                                             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
1473                                             shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1474                     if (pdh == NULL) {
1475                         cfile_dump_open_failure_message("editcap", filename,
1476                                                         write_err,
1477                                                         out_file_type_subtype);
1478                         ret = INVALID_FILE;
1479                         goto clean_exit;
1480                     }
1481                 }
1482             } /* split packet handling */
1483
1484             if (check_startstop) {
1485                 /*
1486                  * Is the packet in the selected timeframe?
1487                  * If the packet has no time stamp, the answer is "no".
1488                  */
1489                 if (phdr->presence_flags & WTAP_HAS_TS)
1490                     ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime);
1491                 else
1492                     ts_okay = FALSE;
1493             } else {
1494                 /*
1495                  * No selected timeframe, so all packets are "in the
1496                  * selected timeframe".
1497                  */
1498                 ts_okay = TRUE;
1499             }
1500
1501             if (ts_okay && ((!selected(count) && !keep_em)
1502                             || (selected(count) && keep_em))) {
1503
1504                 if (verbose && !dup_detect && !dup_detect_by_time)
1505                     fprintf(stderr, "Packet: %u\n", count);
1506
1507                 /* We simply write it, perhaps after truncating it; we could
1508                  * do other things, like modify it. */
1509
1510                 phdr = wtap_phdr(wth);
1511
1512                 if (snaplen != 0) {
1513                     /* Limit capture length to snaplen */
1514                     if (phdr->caplen > snaplen) {
1515                         /* Copy and change rather than modify returned phdr */
1516                         temp_phdr = *phdr;
1517                         temp_phdr.caplen = snaplen;
1518                         phdr = &temp_phdr;
1519                     }
1520                     /* If -L, also set reported length to snaplen */
1521                     if (adjlen && phdr->len > snaplen) {
1522                         /* Copy and change rather than modify returned phdr */
1523                         temp_phdr = *phdr;
1524                         temp_phdr.len = snaplen;
1525                         phdr = &temp_phdr;
1526                     }
1527                 }
1528
1529                 /*
1530                  * CHOP
1531                  * Copy and change rather than modify returned phdr.
1532                  */
1533                 temp_phdr = *phdr;
1534                 handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen);
1535                 phdr = &temp_phdr;
1536
1537                 if (phdr->presence_flags & WTAP_HAS_TS) {
1538                     /* Do we adjust timestamps to ensure strict chronological
1539                      * order? */
1540                     if (do_strict_time_adjustment) {
1541                         if (previous_time.secs || previous_time.nsecs) {
1542                             if (!strict_time_adj.is_negative) {
1543                                 nstime_t current;
1544                                 nstime_t delta;
1545
1546                                 current = phdr->ts;
1547
1548                                 nstime_delta(&delta, &current, &previous_time);
1549
1550                                 if (delta.secs < 0 || delta.nsecs < 0) {
1551                                     /*
1552                                      * A negative delta indicates that the current packet
1553                                      * has an absolute timestamp less than the previous packet
1554                                      * that it is being compared to.  This is NOT a normal
1555                                      * situation since trace files usually have packets in
1556                                      * chronological order (oldest to newest).
1557                                      * Copy and change rather than modify
1558                                      * returned phdr.
1559                                      */
1560                                     /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
1561                                     temp_phdr = *phdr;
1562                                     temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1563                                     temp_phdr.ts.nsecs = previous_time.nsecs;
1564                                     if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1565                                         /* carry */
1566                                         temp_phdr.ts.secs++;
1567                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1568                                     } else {
1569                                         temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1570                                     }
1571                                     phdr = &temp_phdr;
1572                                 }
1573                             } else {
1574                                 /*
1575                                  * A negative strict time adjustment is requested.
1576                                  * Unconditionally set each timestamp to previous
1577                                  * packet's timestamp plus delta.
1578                                  * Copy and change rather than modify returned
1579                                  * phdr.
1580                                  */
1581                                 temp_phdr = *phdr;
1582                                 temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
1583                                 temp_phdr.ts.nsecs = previous_time.nsecs;
1584                                 if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
1585                                     /* carry */
1586                                     temp_phdr.ts.secs++;
1587                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
1588                                 } else {
1589                                     temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
1590                                 }
1591                                 phdr = &temp_phdr;
1592                             }
1593                         }
1594                         previous_time = phdr->ts;
1595                     }
1596
1597                     if (time_adj.tv.secs != 0) {
1598                         /* Copy and change rather than modify returned phdr */
1599                         temp_phdr = *phdr;
1600                         if (time_adj.is_negative)
1601                             temp_phdr.ts.secs -= time_adj.tv.secs;
1602                         else
1603                             temp_phdr.ts.secs += time_adj.tv.secs;
1604                         phdr = &temp_phdr;
1605                     }
1606
1607                     if (time_adj.tv.nsecs != 0) {
1608                         /* Copy and change rather than modify returned phdr */
1609                         temp_phdr = *phdr;
1610                         if (time_adj.is_negative) { /* subtract */
1611                             if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
1612                                 temp_phdr.ts.secs--;
1613                                 temp_phdr.ts.nsecs += ONE_BILLION;
1614                             }
1615                             temp_phdr.ts.nsecs -= time_adj.tv.nsecs;
1616                         } else {                  /* add */
1617                             if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) {
1618                                 /* carry */
1619                                 temp_phdr.ts.secs++;
1620                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
1621                             } else {
1622                                 temp_phdr.ts.nsecs += time_adj.tv.nsecs;
1623                             }
1624                         }
1625                         phdr = &temp_phdr;
1626                     }
1627                 } /* time stamp adjustment */
1628
1629                 /* remove vlan info */
1630                 if (rem_vlan) {
1631                     /* Copy and change rather than modify returned phdr */
1632                     temp_phdr = *phdr;
1633                     remove_vlan_info(phdr, buf, &temp_phdr.caplen);
1634                     phdr = &temp_phdr;
1635                 }
1636
1637                 /* suppress duplicates by packet window */
1638                 if (dup_detect) {
1639                     if (is_duplicate(buf, phdr->caplen)) {
1640                         if (verbose) {
1641                             fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1642                                     count, phdr->caplen);
1643                             for (i = 0; i < 16; i++)
1644                                 fprintf(stderr, "%02x",
1645                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1646                             fprintf(stderr, "\n");
1647                         }
1648                         duplicate_count++;
1649                         count++;
1650                         continue;
1651                     } else {
1652                         if (verbose) {
1653                             fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1654                                     count, phdr->caplen);
1655                             for (i = 0; i < 16; i++)
1656                                 fprintf(stderr, "%02x",
1657                                         (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1658                             fprintf(stderr, "\n");
1659                         }
1660                     }
1661                 } /* suppression of duplicates */
1662
1663                 if (phdr->presence_flags & WTAP_HAS_TS) {
1664                     /* suppress duplicates by time window */
1665                     if (dup_detect_by_time) {
1666                         nstime_t current;
1667
1668                         current.secs  = phdr->ts.secs;
1669                         current.nsecs = phdr->ts.nsecs;
1670
1671                         if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
1672                             if (verbose) {
1673                                 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
1674                                         count, phdr->caplen);
1675                                 for (i = 0; i < 16; i++)
1676                                     fprintf(stderr, "%02x",
1677                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1678                                 fprintf(stderr, "\n");
1679                             }
1680                             duplicate_count++;
1681                             count++;
1682                             continue;
1683                         } else {
1684                             if (verbose) {
1685                                 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
1686                                         count, phdr->caplen);
1687                                 for (i = 0; i < 16; i++)
1688                                     fprintf(stderr, "%02x",
1689                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
1690                                 fprintf(stderr, "\n");
1691                             }
1692                         }
1693                     }
1694                 } /* suppress duplicates by time window */
1695
1696                 if (change_offset > phdr->caplen) {
1697                     fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
1698                         change_offset, phdr->caplen, count);
1699                 }
1700
1701                 /* Random error mutation */
1702                 if (err_prob > 0.0 && change_offset <= phdr->caplen) {
1703                     int real_data_start = 0;
1704
1705                     /* Protect non-protocol data */
1706                     if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
1707                         real_data_start = find_dct2000_real_data(buf);
1708
1709                     real_data_start += change_offset;
1710
1711                     for (i = real_data_start; i < (int) phdr->caplen; i++) {
1712                         if (rand() <= err_prob * RAND_MAX) {
1713                             err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
1714
1715                             if (err_type < ERR_WT_BIT) {
1716                                 buf[i] ^= 1 << (rand() / (RAND_MAX / 8 + 1));
1717                                 err_type = ERR_WT_TOTAL;
1718                             } else {
1719                                 err_type -= ERR_WT_BYTE;
1720                             }
1721
1722                             if (err_type < ERR_WT_BYTE) {
1723                                 buf[i] = rand() / (RAND_MAX / 255 + 1);
1724                                 err_type = ERR_WT_TOTAL;
1725                             } else {
1726                                 err_type -= ERR_WT_BYTE;
1727                             }
1728
1729                             if (err_type < ERR_WT_ALNUM) {
1730                                 buf[i] = ALNUM_CHARS[rand() / (RAND_MAX / ALNUM_LEN + 1)];
1731                                 err_type = ERR_WT_TOTAL;
1732                             } else {
1733                                 err_type -= ERR_WT_ALNUM;
1734                             }
1735
1736                             if (err_type < ERR_WT_FMT) {
1737                                 if ((unsigned int)i < phdr->caplen - 2)
1738                                     g_strlcpy((char*) &buf[i], "%s", 2);
1739                                 err_type = ERR_WT_TOTAL;
1740                             } else {
1741                                 err_type -= ERR_WT_FMT;
1742                             }
1743
1744                             if (err_type < ERR_WT_AA) {
1745                                 for (j = i; j < (int) phdr->caplen; j++)
1746                                     buf[j] = 0xAA;
1747                                 i = phdr->caplen;
1748                             }
1749                         }
1750                     }
1751                 } /* random error mutation */
1752
1753                 /* Find a packet comment we may need to write */
1754                 if (frames_user_comments) {
1755                     const char *comment =
1756                         (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count));
1757                     /* XXX: What about comment changed to no comment? */
1758                     if (comment != NULL) {
1759                         /* Copy and change rather than modify returned phdr */
1760                         temp_phdr = *phdr;
1761                         temp_phdr.opt_comment = g_strdup(comment);
1762                         temp_phdr.has_comment_changed = TRUE;
1763                         phdr = &temp_phdr;
1764                     } else {
1765                         /* Copy and change rather than modify returned phdr */
1766                         temp_phdr = *phdr;
1767                         temp_phdr.has_comment_changed = FALSE;
1768                         phdr = &temp_phdr;
1769                     }
1770                 }
1771
1772                 /* Attempt to dump out current frame to the output file */
1773                 if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) {
1774                     cfile_write_failure_message("editcap", argv[optind],
1775                                                 filename,
1776                                                 write_err, write_err_info,
1777                                                 read_count,
1778                                                 out_file_type_subtype);
1779                     ret = DUMP_ERROR;
1780                     goto clean_exit;
1781                 }
1782                 written_count++;
1783             }
1784             count++;
1785         }
1786
1787         g_free(fprefix);
1788         g_free(fsuffix);
1789
1790         if (read_err != 0) {
1791             /* Print a message noting that the read failed somewhere along the
1792              * line. */
1793             cfile_read_failure_message("editcap", argv[optind], read_err,
1794                                        read_err_info);
1795         }
1796
1797         if (!pdh) {
1798             /* No valid packages found, open the outfile so we can write an
1799              * empty header */
1800             g_free (filename);
1801             filename = g_strdup(argv[optind+1]);
1802
1803             pdh = editcap_dump_open(filename,
1804                                     snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
1805                                     shb_hdrs, idb_inf, nrb_hdrs, &write_err);
1806             if (pdh == NULL) {
1807                 cfile_dump_open_failure_message("editcap", filename,
1808                                                 write_err,
1809                                                 out_file_type_subtype);
1810                 ret = INVALID_FILE;
1811                 goto clean_exit;
1812             }
1813         }
1814
1815         if (!wtap_dump_close(pdh, &write_err)) {
1816             cfile_close_failure_message(filename, write_err);
1817             ret = WRITE_ERROR;
1818             goto clean_exit;
1819         }
1820         g_free(filename);
1821
1822         if (frames_user_comments) {
1823             g_tree_destroy(frames_user_comments);
1824         }
1825     }
1826
1827     if (dup_detect) {
1828         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate window of %i packets.\n",
1829                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1830                 plurality(duplicate_count, "", "s"), dup_window);
1831     } else if (dup_detect_by_time) {
1832         fprintf(stderr, "%u packet%s seen, %u packet%s skipped with duplicate time window equal to or less than %ld.%09ld seconds.\n",
1833                 count - 1, plurality(count - 1, "", "s"), duplicate_count,
1834                 plurality(duplicate_count, "", "s"),
1835                 (long)relative_time_window.secs,
1836                 (long int)relative_time_window.nsecs);
1837     }
1838
1839 clean_exit:
1840     wtap_block_array_free(shb_hdrs);
1841     wtap_block_array_free(nrb_hdrs);
1842     g_free(idb_inf);
1843     if (wth != NULL)
1844         wtap_close(wth);
1845     wtap_cleanup();
1846     free_progdirs();
1847     return ret;
1848 }
1849
1850 /* Skip meta-information read from file to return offset of real
1851  * protocol data */
1852 static int
1853 find_dct2000_real_data(guint8 *buf)
1854 {
1855     int n = 0;
1856
1857     for (n = 0; buf[n] != '\0'; n++);   /* Context name */
1858     n++;
1859     n++;                                /* Context port number */
1860     for (; buf[n] != '\0'; n++);        /* Timestamp */
1861     n++;
1862     for (; buf[n] != '\0'; n++);        /* Protocol name */
1863     n++;
1864     for (; buf[n] != '\0'; n++);        /* Variant number (as string) */
1865     n++;
1866     for (; buf[n] != '\0'; n++);        /* Outhdr (as string) */
1867     n++;
1868     n += 2;                             /* Direction & encap */
1869
1870     return n;
1871 }
1872
1873 /*
1874  * We support up to 2 chopping regions in a single pass: one specified by the
1875  * positive chop length, and one by the negative chop length.
1876  */
1877 static void
1878 handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
1879                 const struct wtap_pkthdr *in_phdr, guint8 **buf,
1880                 gboolean adjlen)
1881 {
1882     /* Only packets can be chopped. */
1883     if (in_phdr->rec_type != REC_TYPE_PACKET)
1884         return;
1885
1886     /* If we're not chopping anything from one side, then the offset for that
1887      * side is meaningless. */
1888     if (chop.len_begin == 0)
1889         chop.off_begin_pos = chop.off_begin_neg = 0;
1890     if (chop.len_end == 0)
1891         chop.off_end_pos = chop.off_end_neg = 0;
1892
1893     if (chop.off_begin_neg < 0) {
1894         chop.off_begin_pos += in_phdr->caplen + chop.off_begin_neg;
1895         chop.off_begin_neg = 0;
1896     }
1897     if (chop.off_end_pos > 0) {
1898         chop.off_end_neg += chop.off_end_pos - in_phdr->caplen;
1899         chop.off_end_pos = 0;
1900     }
1901
1902     /* If we've crossed chopping regions, swap them */
1903     if (chop.len_begin && chop.len_end) {
1904         if (chop.off_begin_pos > ((int)in_phdr->caplen + chop.off_end_neg)) {
1905             int tmp_len, tmp_off;
1906
1907             tmp_off = in_phdr->caplen + chop.off_end_neg + chop.len_end;
1908             tmp_len = -chop.len_end;
1909
1910             chop.off_end_neg = chop.len_begin + chop.off_begin_pos - in_phdr->caplen;
1911             chop.len_end = -chop.len_begin;
1912
1913             chop.len_begin = tmp_len;
1914             chop.off_begin_pos = tmp_off;
1915         }
1916     }
1917
1918     /* Make sure we don't chop off more than we have available */
1919     if (in_phdr->caplen < (guint32)(chop.off_begin_pos - chop.off_end_neg)) {
1920         chop.len_begin = 0;
1921         chop.len_end = 0;
1922     }
1923     if ((guint32)(chop.len_begin - chop.len_end) >
1924         (in_phdr->caplen - (guint32)(chop.off_begin_pos - chop.off_end_neg))) {
1925         chop.len_begin = in_phdr->caplen - (chop.off_begin_pos - chop.off_end_neg);
1926         chop.len_end = 0;
1927     }
1928
1929     /* Handle chopping from the beginning.  Note that if a beginning offset
1930      * was specified, we need to keep that piece */
1931     if (chop.len_begin > 0) {
1932         *out_phdr = *in_phdr;
1933
1934         if (chop.off_begin_pos > 0) {
1935             memmove(*buf + chop.off_begin_pos,
1936                     *buf + chop.off_begin_pos + chop.len_begin,
1937                     out_phdr->caplen - chop.len_begin);
1938         } else {
1939             *buf += chop.len_begin;
1940         }
1941         out_phdr->caplen -= chop.len_begin;
1942
1943         if (adjlen) {
1944             if (in_phdr->len > (guint32)chop.len_begin)
1945                 out_phdr->len -= chop.len_begin;
1946             else
1947                 out_phdr->len = 0;
1948         }
1949         in_phdr = out_phdr;
1950     }
1951
1952     /* Handle chopping from the end.  Note that if an ending offset was
1953      * specified, we need to keep that piece */
1954     if (chop.len_end < 0) {
1955         *out_phdr = *in_phdr;
1956
1957         if (chop.off_end_neg < 0) {
1958             memmove(*buf + (gint)out_phdr->caplen + (chop.len_end + chop.off_end_neg),
1959                     *buf + (gint)out_phdr->caplen + chop.off_end_neg,
1960                     -chop.off_end_neg);
1961         }
1962         out_phdr->caplen += chop.len_end;
1963
1964         if (adjlen) {
1965             if (((signed int) in_phdr->len + chop.len_end) > 0)
1966                 out_phdr->len += chop.len_end;
1967             else
1968                 out_phdr->len = 0;
1969         }
1970         /*in_phdr = out_phdr;*/
1971     }
1972 }
1973
1974 /*
1975  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1976  *
1977  * Local variables:
1978  * c-basic-offset: 4
1979  * tab-width: 8
1980  * indent-tabs-mode: nil
1981  * End:
1982  *
1983  * vi: set shiftwidth=4 tabstop=8 expandtab:
1984  * :indentSize=4:tabSize=8:noTabs=true:
1985  */