/* Edit capture files. We can delete records, adjust timestamps, or * simply convert from one format to another format. * * $Id: editcap.c,v 1.18 2001/10/04 08:30:33 guy Exp $ * * Originally written by Richard Sharpe. * Improved by Guy Harris. * Further improved by Richard Sharpe. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_WINSOCK_H #include #endif #include #include "wtap.h" #ifdef NEED_GETOPT_H #include "getopt.h" #endif /* * Some globals so we can pass things to various routines */ struct select_item { int inclusive; int first, second; } select_item; #define ONE_MILLION 1000000 struct time_adjustment { struct timeval tv; int is_negative; }; struct select_item selectfrm[100]; int max_selected = -1; static int count = 1; static int keep_em = 0; static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */ static int out_frame_type = -2; /* Leave frame type alone */ static int verbose = 0; /* Not so verbose */ static unsigned int snaplen = 0; /* No limit */ static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */ /* Add a selection item, a simple parser for now */ void add_selection(char *sel) { char *locn; char *next; if (max_selected == (sizeof(selectfrm)/sizeof(struct select_item)) - 1) return; printf("Add_Selected: %s\n", sel); if ((locn = strchr(sel, '-')) == NULL) { /* No dash, so a single number? */ printf("Not inclusive ..."); max_selected++; selectfrm[max_selected].inclusive = 0; selectfrm[max_selected].first = atoi(sel); printf(" %i\n", selectfrm[max_selected].first); } else { printf("Inclusive ..."); next = locn + 1; max_selected++; selectfrm[max_selected].inclusive = 1; selectfrm[max_selected].first = atoi(sel); selectfrm[max_selected].second = atoi(next); printf(" %i, %i\n", selectfrm[max_selected].first, selectfrm[max_selected].second); } } /* Was the record selected? */ int selected(int recno) { int i = 0; for (i = 0; i<= max_selected; i++) { if (selectfrm[i].inclusive) { if (selectfrm[i].first <= recno && selectfrm[i].second >= recno) return 1; } else { if (recno == selectfrm[i].first) return 1; } } return 0; } /* An argument to the callback routine */ typedef struct { char *filename; wtap_dumper *pdh; } callback_arg; /* *The callback routine that is called for each frame in the input file */ static void edit_callback(u_char *user, const struct wtap_pkthdr *phdr, long offset, union wtap_pseudo_header *pseudo_header, const u_char *buf) { callback_arg *argp = (callback_arg *)user; int err; struct wtap_pkthdr snap_phdr; if ((!selected(count) && !keep_em) || (selected(count) && keep_em)) { if (verbose) printf("Record: %u\n", count); /* We simply write it, perhaps after truncating it; we could do other things, like modify it. */ if (snaplen != 0 && phdr->caplen > snaplen) { snap_phdr = *phdr; snap_phdr.caplen = snaplen; phdr = &snap_phdr; } /* assume that if the frame's tv_sec is 0, then * the timestamp isn't supported */ if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_sec != 0) { snap_phdr = *phdr; if (time_adj.is_negative) snap_phdr.ts.tv_sec -= time_adj.tv.tv_sec; else snap_phdr.ts.tv_sec += time_adj.tv.tv_sec; phdr = &snap_phdr; } /* assume that if the frame's tv_sec is 0, then * the timestamp isn't supported */ if (phdr->ts.tv_sec > 0 && time_adj.tv.tv_usec != 0) { snap_phdr = *phdr; if (time_adj.is_negative) { /* subtract */ if (snap_phdr.ts.tv_usec < time_adj.tv.tv_usec) { /* borrow */ snap_phdr.ts.tv_sec--; snap_phdr.ts.tv_usec += ONE_MILLION; } snap_phdr.ts.tv_usec -= time_adj.tv.tv_usec; } else { /* add */ if (snap_phdr.ts.tv_usec + time_adj.tv.tv_usec > ONE_MILLION) { /* carry */ snap_phdr.ts.tv_sec++; snap_phdr.ts.tv_usec += time_adj.tv.tv_usec - ONE_MILLION; } else { snap_phdr.ts.tv_usec += time_adj.tv.tv_usec; } } phdr = &snap_phdr; } if (!wtap_dump(argp->pdh, phdr, pseudo_header, buf, &err)) { fprintf(stderr, "editcap: Error writing to %s: %s\n", argp->filename, wtap_strerror(err)); exit(1); } } count++; } static void set_time_adjustment(char *optarg) { char *frac, *end; long val; int frac_digits; if (!optarg) return; /* skip leading whitespace */ while (*optarg == ' ' || *optarg == '\t') { optarg++; } /* check for a negative adjustment */ if (*optarg == '-') { time_adj.is_negative = 1; optarg++; } /* collect whole number of seconds, if any */ if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */ val = 0; frac = optarg; } else { val = strtol(optarg, &frac, 10); if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) { fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n", optarg); exit(1); } if (val < 0) { /* implies '--' since we caught '-' above */ fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n", optarg); exit(1); } } time_adj.tv.tv_sec = val; /* now collect the partial seconds, if any */ if (*frac != '\0') { /* chars left, so get fractional part */ val = strtol(&(frac[1]), &end, 10); if (*frac != '.' || end == NULL || end == frac || val < 0 || val > ONE_MILLION || val == LONG_MIN || val == LONG_MAX) { fprintf(stderr, "editcap: \"%s\" is not a valid time adjustment\n", optarg); exit(1); } } else { return; /* no fractional digits */ } /* adjust fractional portion from fractional to numerator * e.g., in "1.5" from 5 to 500000 since .5*10^6 = 500000 */ if (frac && end) { /* both are valid */ frac_digits = end - frac - 1; /* fractional digit count (remember '.') */ while(frac_digits < 6) { /* this is frac of 10^6 */ val *= 10; frac_digits++; } } time_adj.tv.tv_usec = val; } void usage() { int i; const char *string; fprintf(stderr, "Usage: editcap [-r] [-h] [-v] [-T ] [-F ]\n"); fprintf(stderr, " [-s ] [-t