X-Git-Url: http://git.samba.org/samba.git/?p=obnox%2Fwireshark%2Fwip.git;a=blobdiff_plain;f=editcap.c;h=d643ea45c6ead4f3bed4bcd898fe64f7768ea80e;hp=c7ec2d71470e89460b5416a980ec5ccd8a11645f;hb=f71d7b8cb4b53b1d7e6981cc1e510d0d15c88334;hpb=2d606b36c8520910b504dc0ca0bbef4ec57cdcbc diff --git a/editcap.c b/editcap.c index c7ec2d7147..d643ea45c6 100644 --- a/editcap.c +++ b/editcap.c @@ -42,22 +42,28 @@ #include "wtap.h" -#ifdef NEED_GETOPT_H -#include "getopt.h" +#ifndef HAVE_GETOPT +#include "wsutil/wsgetopt.h" #endif #ifdef _WIN32 +#include #include /* getpid */ +#ifdef HAVE_WINSOCK2_H +#include +#endif #endif #ifdef NEED_STRPTIME_H -# include "strptime.h" +# include "wsutil/strptime.h" #endif -#include "epan/crypt/crypt-md5.h" +#include "epan/crypt/md5.h" #include "epan/plugins.h" #include "epan/report_err.h" #include "epan/filesystem.h" +#include +#include "epan/nstime.h" #include "svnversion.h" @@ -79,13 +85,18 @@ struct select_item { typedef struct _fd_hash_t { md5_byte_t digest[16]; guint32 len; + nstime_t time; } fd_hash_t; -#define DUP_DEPTH 5 -fd_hash_t fd_hash[DUP_DEPTH]; -int cur_dup = 0; +#define DEFAULT_DUP_DEPTH 5 /* Used with -d */ +#define MAX_DUP_DEPTH 1000000 /* the maximum window (and actual size of fd_hash[]) for de-duplication */ + +fd_hash_t fd_hash[MAX_DUP_DEPTH]; +int dup_window = DEFAULT_DUP_DEPTH; +int cur_dup_entry = 0; #define ONE_MILLION 1000000 +#define ONE_BILLION 1000000000 /* Weights of different errors we can introduce */ /* We should probably make these command-line arguments */ @@ -110,15 +121,111 @@ struct time_adjustment { static struct select_item selectfrm[MAX_SELECTIONS]; static int max_selected = -1; static int keep_em = 0; -static int out_file_type = WTAP_FILE_PCAP; /* default to "libpcap" */ +#ifdef PCAP_NG_DEFAULT +static int out_file_type = WTAP_FILE_PCAPNG; /* default to pcapng */ +#else +static int out_file_type = WTAP_FILE_PCAP; /* default to pcap */ +#endif static int out_frame_type = -2; /* Leave frame type alone */ static int verbose = 0; /* Not so verbose */ static struct time_adjustment time_adj = {{0, 0}, 0}; /* no adjustment */ +static nstime_t relative_time_window = {0, 0}; /* de-dup time window */ static double err_prob = 0.0; static time_t starttime = 0; static time_t stoptime = 0; static gboolean check_startstop = FALSE; static gboolean dup_detect = FALSE; +static gboolean dup_detect_by_time = FALSE; + +static int do_strict_time_adjustment = FALSE; +static struct time_adjustment strict_time_adj = {{0, 0}, 0}; /* strict time adjustment */ +static nstime_t previous_time = {0, 0}; /* previous time */ + +static int find_dct2000_real_data(guint8 *buf); + +static gchar * +abs_time_to_str_with_sec_resolution(const struct wtap_nstime *abs_time) +{ + struct tm *tmp; + gchar *buf = g_malloc(16); + +#ifdef _MSC_VER + /* calling localtime() on MSVC 2005 with huge values causes it to crash */ + /* XXX - find the exact value that still does work */ + /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */ + if(abs_time->secs > 2000000000) { + tmp = NULL; + } else +#endif + tmp = localtime(&abs_time->secs); + if (tmp) { + g_snprintf(buf, 16, "%d%02d%02d%02d%02d%02d", + tmp->tm_year + 1900, + tmp->tm_mon+1, + tmp->tm_mday, + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec); + } else + buf[0] = '\0'; + + return buf; +} + +static gchar* +fileset_get_filename_by_pattern(guint idx, const struct wtap_nstime *time_val, + gchar *fprefix, gchar *fsuffix) +{ + gchar filenum[5+1]; + gchar *timestr; + gchar *abs_str; + + timestr = abs_time_to_str_with_sec_resolution(time_val); + g_snprintf(filenum, sizeof(filenum), "%05u", idx); + abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL); + g_free(timestr); + + return abs_str; +} + +static gboolean +fileset_extract_prefix_suffix(const char *fname, gchar **fprefix, gchar **fsuffix) +{ + char *pfx, *last_pathsep; + gchar *save_file; + + save_file = g_strdup(fname); + if (save_file == NULL) { + fprintf(stderr, "editcap: Out of memory\n"); + return FALSE; + } + + last_pathsep = strrchr(save_file, G_DIR_SEPARATOR); + pfx = strrchr(save_file,'.'); + if (pfx != NULL && (last_pathsep == NULL || pfx > last_pathsep)) { + /* The pathname has a "." in it, and it's in the last component + of the pathname (because there is either only one component, + i.e. last_pathsep is null as there are no path separators, + or the "." is after the path separator before the last + component. + + Treat it as a separator between the rest of the file name and + the file name suffix, and arrange that the names given to the + ring buffer files have the specified suffix, i.e. put the + changing part of the name *before* the suffix. */ + pfx[0] = '\0'; + *fprefix = g_strdup(save_file); + pfx[0] = '.'; /* restore capfile_name */ + *fsuffix = g_strdup(pfx); + } else { + /* Either there's no "." in the pathname, or it's in a directory + component, so the last component has no suffix. */ + *fprefix = g_strdup(save_file); + *fsuffix = NULL; + } + g_free(save_file); + return TRUE; +} /* Add a selection item, a simple parser for now */ static gboolean @@ -172,11 +279,11 @@ selected(int recno) if (selectfrm[i].inclusive) { if (selectfrm[i].first <= recno && selectfrm[i].second >= recno) - return 1; + return 1; } else { if (recno == selectfrm[i].first) - return 1; + return 1; } } @@ -188,52 +295,46 @@ selected(int recno) static gboolean check_timestamp(wtap *wth) { - static int i = 0; struct wtap_pkthdr* pkthdr = wtap_phdr(wth); - if (!((i++)%250)) - printf("== %d starttime=%lu stoptime=%lu ts=%lu\n",i, - (unsigned long)starttime, - (unsigned long)stoptime, - (unsigned long)pkthdr->ts.secs); - return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs <= stoptime ); + return ( pkthdr->ts.secs >= starttime ) && ( pkthdr->ts.secs < stoptime ); } static void -set_time_adjustment(char *optarg) +set_time_adjustment(char *optarg_str_p) { char *frac, *end; long val; - int frac_digits; + size_t frac_digits; - if (!optarg) + if (!optarg_str_p) return; /* skip leading whitespace */ - while (*optarg == ' ' || *optarg == '\t') { - optarg++; + while (*optarg_str_p == ' ' || *optarg_str_p == '\t') { + optarg_str_p++; } /* check for a negative adjustment */ - if (*optarg == '-') { + if (*optarg_str_p == '-') { time_adj.is_negative = 1; - optarg++; + optarg_str_p++; } /* collect whole number of seconds, if any */ - if (*optarg == '.') { /* only fractional (i.e., .5 is ok) */ + if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ val = 0; - frac = optarg; + frac = optarg_str_p; } else { - val = strtol(optarg, &frac, 10); - if (frac == NULL || frac == optarg || val == LONG_MIN || val == LONG_MAX) { + val = strtol(optarg_str_p, &frac, 10); + if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) { fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", - optarg); + optarg_str_p); exit(1); } if (val < 0) { /* implies '--' since we caught '-' above */ fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", - optarg); + optarg_str_p); exit(1); } } @@ -242,10 +343,15 @@ set_time_adjustment(char *optarg) /* now collect the partial seconds, if any */ if (*frac != '\0') { /* chars left, so get fractional part */ val = strtol(&(frac[1]), &end, 10); + /* if more than 6 fractional digits truncate to 6 */ + if((end - &(frac[1])) > 6) { + frac[7] = 't'; /* 't' for truncate */ + 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\" isn't a valid time adjustment\n", - optarg); + optarg_str_p); exit(1); } } @@ -265,29 +371,280 @@ set_time_adjustment(char *optarg) time_adj.tv.tv_usec = val; } +static void +set_strict_time_adj(char *optarg_str_p) +{ + char *frac, *end; + long val; + size_t frac_digits; + + if (!optarg_str_p) + return; + + /* skip leading whitespace */ + while (*optarg_str_p == ' ' || *optarg_str_p == '\t') { + optarg_str_p++; + } + + /* + * check for a negative adjustment + * A negative strict adjustment value is a flag + * to adjust all frames by the specifed delta time. + */ + if (*optarg_str_p == '-') { + strict_time_adj.is_negative = 1; + optarg_str_p++; + } + + /* collect whole number of seconds, if any */ + if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ + val = 0; + frac = optarg_str_p; + } else { + val = strtol(optarg_str_p, &frac, 10); + if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) { + fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", + optarg_str_p); + exit(1); + } + if (val < 0) { /* implies '--' since we caught '-' above */ + fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n", + optarg_str_p); + exit(1); + } + } + strict_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 more than 6 fractional digits truncate to 6 */ + if((end - &(frac[1])) > 6) { + frac[7] = 't'; /* 't' for truncate */ + 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\" isn't a valid time adjustment\n", + optarg_str_p); + 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++; + } + } + strict_time_adj.tv.tv_usec = val; +} + +static void +set_rel_time(char *optarg_str_p) +{ + char *frac, *end; + long val; + size_t frac_digits; + + if (!optarg_str_p) + return; + + /* skip leading whitespace */ + while (*optarg_str_p == ' ' || *optarg_str_p == '\t') { + optarg_str_p++; + } + + /* ignore negative adjustment */ + if (*optarg_str_p == '-') { + optarg_str_p++; + } + + /* collect whole number of seconds, if any */ + if (*optarg_str_p == '.') { /* only fractional (i.e., .5 is ok) */ + val = 0; + frac = optarg_str_p; + } else { + val = strtol(optarg_str_p, &frac, 10); + if (frac == NULL || frac == optarg_str_p || val == LONG_MIN || val == LONG_MAX) { + fprintf(stderr, "1: editcap: \"%s\" isn't a valid rel time value\n", + optarg_str_p); + exit(1); + } + if (val < 0) { /* implies '--' since we caught '-' above */ + fprintf(stderr, "2: editcap: \"%s\" isn't a valid rel time value\n", + optarg_str_p); + exit(1); + } + } + relative_time_window.secs = val; + + /* now collect the partial seconds, if any */ + if (*frac != '\0') { /* chars left, so get fractional part */ + val = strtol(&(frac[1]), &end, 10); + /* if more than 9 fractional digits truncate to 9 */ + if((end - &(frac[1])) > 9) { + frac[10] = 't'; /* 't' for truncate */ + val = strtol(&(frac[1]), &end, 10); + } + if (*frac != '.' || end == NULL || end == frac + || val < 0 || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) { + fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n", + optarg_str_p); + exit(1); + } + } + else { + return; /* no fractional digits */ + } + + /* adjust fractional portion from fractional to numerator + * e.g., in "1.5" from 5 to 500000000 since .5*10^9 = 500000000 */ + if (frac && end) { /* both are valid */ + frac_digits = end - frac - 1; /* fractional digit count (remember '.') */ + while(frac_digits < 9) { /* this is frac of 10^9 */ + val *= 10; + frac_digits++; + } + } + relative_time_window.nsecs = val; +} + static gboolean is_duplicate(guint8* fd, guint32 len) { int i; md5_state_t ms; - cur_dup++; - if (cur_dup >= DUP_DEPTH) - cur_dup = 0; + cur_dup_entry++; + if (cur_dup_entry >= dup_window) + cur_dup_entry = 0; /* Calculate our digest */ md5_init(&ms); md5_append(&ms, fd, len); - md5_finish(&ms, fd_hash[cur_dup].digest); + md5_finish(&ms, fd_hash[cur_dup_entry].digest); - fd_hash[cur_dup].len = len; + fd_hash[cur_dup_entry].len = len; /* Look for duplicates */ - for (i = 0; i < DUP_DEPTH; i++) { - if (i == cur_dup) + for (i = 0; i < dup_window; i++) { + if (i == cur_dup_entry) + continue; + + if (fd_hash[i].len == fd_hash[cur_dup_entry].len && + memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +is_duplicate_rel_time(guint8* fd, guint32 len, const nstime_t *current) { + int i; + md5_state_t ms; + + cur_dup_entry++; + if (cur_dup_entry >= dup_window) + cur_dup_entry = 0; + + /* Calculate our digest */ + md5_init(&ms); + md5_append(&ms, fd, len); + md5_finish(&ms, fd_hash[cur_dup_entry].digest); + + fd_hash[cur_dup_entry].len = len; + fd_hash[cur_dup_entry].time.secs = current->secs; + fd_hash[cur_dup_entry].time.nsecs = current->nsecs; + + /* + * Look for relative time related duplicates. + * This is hopefully a reasonably efficient mechanism for + * finding duplicates by rel time in the fd_hash[] cache. + * We check starting from the most recently added hash + * entries and work backwards towards older packets. + * This approach allows the dup test to be terminated + * when the relative time of a cached entry is found to + * be beyond the dup time window. + * + * Of course this assumes that the input trace file is + * "well-formed" in the sense that the packet timestamps are + * in strict chronologically increasing order (which is NOT + * always the case!!). + * + * The fd_hash[] table was deliberatly created large (1,000,000). + * Looking for time related duplicates in large trace files with + * non-fractional dup time window values can potentially take + * a long time to complete. + */ + + for (i = cur_dup_entry - 1;; i--) { + nstime_t delta; + int cmp; + + if (i < 0) { + i = dup_window - 1; + } + + if (i == cur_dup_entry) { + /* + * We've decremented back to where we started. + * Check no more! + */ + break; + } + + if (nstime_is_unset(&(fd_hash[i].time))) { + /* + * We've decremented to an unused fd_hash[] entry. + * Check no more! + */ + break; + } + + nstime_delta(&delta, current, &fd_hash[i].time); + + if(delta.secs < 0 || delta.nsecs < 0) + { + /* + * A negative delta implies that the current packet + * has an absolute timestamp less than the cached packet + * that it is being compared to. This is NOT a normal + * situation since trace files usually have packets in + * chronological order (oldest to newest). + * + * There are several possible ways to deal with this: + * 1. 'continue' dup checking with the next cached frame. + * 2. 'break' from looking for a duplicate of the current frame. + * 3. Take the absolute value of the delta and see if that + * falls within the specifed dup time window. + * + * Currently this code does option 1. But it would pretty + * easy to add yet-another-editcap-option to select one of + * the other behaviors for dealing with out-of-sequence + * packets. + */ continue; + } - if (fd_hash[i].len == fd_hash[cur_dup].len && - memcmp(fd_hash[i].digest, fd_hash[cur_dup].digest, 16) == 0) { + cmp = nstime_cmp(&delta, &relative_time_window); + + if(cmp > 0) { + /* + * The delta time indicates that we are now looking at + * cached packets beyond the specified dup time window. + * Check no more! + */ + break; + } else if (fd_hash[i].len == fd_hash[cur_dup_entry].len && + memcmp(fd_hash[i].digest, fd_hash[cur_dup_entry].digest, 16) == 0) { return TRUE; } } @@ -295,130 +652,230 @@ is_duplicate(guint8* fd, guint32 len) { return FALSE; } -static void usage(void) +static void +usage(gboolean is_error) { - fprintf(stderr, "Editcap %s" + FILE *output; + + if (!is_error) + output = stdout; + else + output = stderr; + + fprintf(output, "Editcap %s" #ifdef SVNVERSION - " (" SVNVERSION ")" + " (" SVNVERSION " from " SVNPATH ")" #endif - "\n", VERSION); - fprintf(stderr, "Edit and/or translate the format of capture files.\n"); - fprintf(stderr, "See http://www.wireshark.org for more information.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Usage: editcap [options] ... [ [-] ... ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "A single packet or a range of packets can be selected.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Packet selection:\n"); - fprintf(stderr, " -r keep the selected packets, default is to delete them\n"); - fprintf(stderr, " -A don't output packets whose timestamp is before the\n"); - fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss)\n"); - fprintf(stderr, " -B don't output packets whose timestamp is after the\n"); - fprintf(stderr, " given time (format as YYYY-MM-DD hh:mm:ss)\n"); - fprintf(stderr, " -d remove duplicate packets\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Packet manipulation:\n"); - fprintf(stderr, " -s truncate each packet to max. bytes of data\n"); - fprintf(stderr, " -C chop each packet at the end by bytes\n"); - fprintf(stderr, " -t