head 1.9; access; symbols; locks; strict; comment @ * @; 1.9 date 2010.03.04.22.59.21; author wessels; state Exp; branches; next 1.8; 1.8 date 2010.01.28.06.15.58; author wessels; state Exp; branches; next 1.7; 1.7 date 2010.01.28.05.54.56; author wessels; state Exp; branches; next 1.6; 1.6 date 2010.01.28.05.51.05; author wessels; state Exp; branches; next 1.5; 1.5 date 2009.08.07.22.58.55; author wessels; state Exp; branches; next 1.4; 1.4 date 2009.08.03.19.59.54; author wessels; state Exp; branches; next 1.3; 1.3 date 2008.10.30.00.56.18; author wessels; state Exp; branches; next 1.2; 1.2 date 2008.04.22.15.55.43; author wessels; state Exp; branches; next 1.1; 1.1 date 2008.04.21.23.39.06; author wessels; state Exp; branches; next ; desc @@ 1.9 log @print the file that we're writing @ text @#include #include #include #include #include #include #include #include #include #include #include #include #include #define DEF_FMT "%s" #define START_OPT 1001 #define STOP_OPT 1002 static const char *kick_cmd = NULL; static const char *ProgramName = "tcpdump-split"; static const char *gzext = ".gz"; static int opt_gzip = 0; /* Prototypes */ static void usage(const char *) __attribute__((noreturn)); static void help(void); #ifdef __linux__ extern char *strptime(const char *s, const char *format, struct tm *tm); extern int asprintf(char **strp, const char *fmt, ...); #endif int main(int argc, char *argv[]) { pcap_t *in = NULL; pcap_dumper_t *out = NULL; char errbuf[PCAP_ERRBUF_SIZE + 1]; struct pcap_pkthdr hdr; time_t this_bin; time_t last_bin = -1; time_t modulus = 0; uint64_t count = 0; uint64_t npkts = 0; const u_char *data; int ch; char *p; unsigned long ul; char *fmt = NULL; /* Track of starting and ending time */ static time_t start_time = 0; static time_t stop_time = 0; char fname[128]; char fifoname[128]; char *pcapname = fname; while ((ch = getopt(argc, argv, "?hB:E:t:n:f:k:z")) != -1) { switch (ch) { case 't': /* Validate that is a integer */ ul = strtoul(optarg, &p, 0); if (*p != '\0') usage("argument to -t must be an integer"); modulus = (unsigned) ul; break; case 'n': if (1 != sscanf(optarg, "%"PRIu64, &count)) usage("argument to -n must be an integer"); break; case 'f': fmt = strdup(optarg); break; case 'k': kick_cmd = strdup(optarg); break; case '?': case 'h': help(); exit(0); break; case 'B': { struct tm tm; memset(&tm, '\0', sizeof(tm)); if (NULL == strptime(optarg, "%F %T", &tm)) usage("-B arg must have format YYYY-MM-DD HH:MM:SS"); start_time = timegm(&tm); } break; case 'E': { struct tm tm; memset(&tm, '\0', sizeof(tm)); if (NULL == strptime(optarg, "%F %T", &tm)) usage("-E arg must have format YYYY-MM-DD HH:MM:SS"); stop_time = timegm(&tm); } break; case 'z': opt_gzip = 1; break; default: usage("unrecognized command line option"); } } if (0 == modulus && 0 == count) { help(); exit(1); } if (start_time && stop_time && start_time > stop_time) usage("start time must be before stop time"); /* If not format given, use the default */ if (NULL == fmt) fmt = strdup(DEF_FMT); in = pcap_open_offline("-", errbuf); if (NULL == in) { fprintf(stderr, "stdin: %s", errbuf); exit(1); } while ((data = pcap_next(in, &hdr))) { if (modulus) this_bin = hdr.ts.tv_sec - (hdr.ts.tv_sec % modulus); else this_bin = (time_t) (npkts++ / count); /* Check if the packet is within the time window we are * interested */ if (start_time && hdr.ts.tv_sec < start_time) continue; if (stop_time && hdr.ts.tv_sec >= stop_time) break; if (this_bin != last_bin) { if (out) { char *cmd = NULL; pcap_dump_close(out); if (opt_gzip) { int s; waitpid(-1, &s, 0); } if (kick_cmd != NULL) { if (asprintf(&cmd, "%s %s &", kick_cmd, fname) < 0){ perror("asprintf"); cmd = NULL; } else { system(cmd); free(cmd); } } } if (modulus) strftime(fname, sizeof(fname)-sizeof(gzext), fmt, gmtime(&this_bin)); else snprintf(fname, sizeof(fname)-sizeof(gzext), fmt, (int) this_bin); if (opt_gzip) { static int fifocount = 0; int gzfd = -1; strcat(fname, gzext); gzfd = open(fname, O_WRONLY|O_CREAT, 0666); if (gzfd < 0) { perror(fname); exit(1); } snprintf(fifoname, sizeof(fifoname), "/tmp/%s.fifo.%d.%d", ProgramName, (int) getpid(), fifocount++); if (mkfifo(fifoname, 0600) < 0) { perror(fifoname); exit(1); } if (0 == fork()) { /* child */ int i; close(0); if (0 != open(fifoname, O_RDONLY)) { perror(fifoname); exit(1); } if (dup2(gzfd, 1) < 0) { perror("dup2"); exit(1); } close(gzfd); for (i=3; i<20; i++) close(i); execlp("gzip", "gzip", "-9c", NULL); } else { close(gzfd); pcapname = fifoname; } } fprintf(stderr, "writing %s\n", fname); out = pcap_dump_open(in, pcapname); if (opt_gzip) { /* * no race condition on unlink because open-for-write * blocks until open-for-read happens first? */ unlink(fifoname); } if (NULL == out) { perror(fname); exit(1); } last_bin = this_bin; } pcap_dump((void *)out, &hdr, data); } if (out) { char *cmd = NULL; pcap_dump_close(out); if (opt_gzip) { int s; waitpid(-1, &s, 0); } if (kick_cmd != NULL) { if (asprintf(&cmd, "%s %s &", kick_cmd, fname) < 0){ perror("asprintf"); cmd = NULL; } else { system(cmd); free(cmd); } } } exit(0); } static void usage(const char *msg) { fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg); fprintf(stderr, "\n"); exit(1); } static void help(void) { fprintf(stderr, "%s\n", ProgramName); fprintf(stderr, "\noptions:\n" "\t-? or -\? print these instructions and exit\n" "\t-B YYYY-MM-DD HH:MM:SS select packets starting on that date\n" "\t-E YYYY-MM-DD HH:MM:SS select packets until this time/date\n" "\t-t each seconds since\n" "\t the start time indicated by '-B'\n" "\t will close the old destination file\n" "\t and create a new one.\n" "\t-n make new output file every packets\n" "\t-f receives a format accepted by\n" "\t strftime to name the files created.\n" "\t Default %%s (UNIX timestamp)\n" "\t-k After closing an old destination\n" "\t file, will execute this command with\n" "\t the file name as first parameter\n" ); } @ 1.8 log @better gzip features @ text @d191 1 @ 1.7 log @remove fifo after we open it @ text @d13 1 d21 1 d53 2 d140 1 d153 1 a153 1 strftime(fname, sizeof(fname), fmt, gmtime(&this_bin)); d155 1 a155 1 snprintf(fname, sizeof(fname), fmt, (int) this_bin); a156 2 char fifoname[256]; char gzfname[140]; d159 2 a160 2 snprintf(gzfname, sizeof(gzfname), "%s.gz", fname); gzfd = open(gzfname, O_WRONLY|O_CREAT, 0666); d162 1 a162 1 perror(gzfname); d165 1 a165 1 snprintf(fifoname, sizeof(fifoname), "/tmp/tcpdump-split.fifo.%d.%d", (int) getpid(), fifocount++); d188 1 a188 1 strncpy(fname, fifoname, sizeof(fname)); d191 1 a191 1 out = pcap_dump_open(in, fname); d193 5 a197 1 unlink(fname); d210 1 @ 1.6 log @add -z option to compress output @ text @d189 3 @ 1.5 log @put back -n feature @ text @d10 3 d20 1 d52 1 a52 1 while ((ch = getopt(argc, argv, "?hB:E:t:n:f:k:")) != -1) d95 3 d148 1 a148 1 strftime(fname, 128, fmt, gmtime(&this_bin)); d150 38 a187 1 snprintf(fname, 128, fmt, (int) this_bin); @ 1.4 log @version from DITL 2009 that adds start/stop times and -k kick cmd this version loses "will not overwrite existing" feature, which I might regret @ text @d9 1 d35 3 a37 1 time_t modulus = 300; d48 1 a48 1 while ((ch = getopt(argc, argv, "?hB:E:t:f:k:")) != -1) d58 4 d95 6 d114 4 a117 1 this_bin = hdr.ts.tv_sec - (hdr.ts.tv_sec % modulus); d140 4 a143 1 strftime(fname, 128, fmt, gmtime(&this_bin)); d188 2 a189 1 "\t and create a new one. Default 300.\n" @ 1.3 log @be more persistent about filename clashes @ text @d10 14 a23 6 void usage(void) { fprintf(stderr, "usage: tcpdump-split [-t seconds | -n count] format\n"); exit(1); } d32 3 a34 4 int this_bin; int last_bin = -1; time_t window = 0; int count = 0; a35 1 char *fmt; d37 7 a43 1 uint64_t npkts = 0; d45 42 a86 12 while ((ch = getopt(argc, argv, "t:n:")) != -1) { switch(ch) { case 't': window = (time_t) atoi(optarg); break; case 'n': count = atoi(optarg); break; default: usage(); break; } d88 2 a89 2 argc -= optind; argv += optind; d91 3 a93 6 if (0 == window && 0 == count) usage(); if (1 != argc) usage(); fmt = strdup(argv[0]); d97 2 a98 2 fprintf(stderr, "stdin: %s", errbuf); exit(1); d101 28 a128 22 if (window) { this_bin = hdr.ts.tv_sec - (hdr.ts.tv_sec % window); } else { this_bin = npkts++ / count; } if (this_bin != last_bin) { char fname[128]; if (out) pcap_dump_close(out); if (window) { time_t tt = this_bin; strftime(fname, 128, fmt, gmtime(&tt)); } else { snprintf(fname, 128, fmt, this_bin); } while (0 == access(fname, F_OK)) { struct timeval tvnow; fprintf(stderr, "tcpdump-split: will not overwrite existing %s\n", fname); gettimeofday(&tvnow, NULL); snprintf(fname, 128, "%ld.%06ld.pcap", (unsigned long) tvnow.tv_sec, (unsigned long) tvnow.tv_usec); d130 17 a146 8 out = pcap_dump_open(in, fname); if (NULL == out) { perror(fname); exit(1); } last_bin = this_bin; } pcap_dump((void *)out, &hdr, data); a147 2 if (out) pcap_dump_close(out); d150 28 @ 1.2 log @On a 64 bit system my previous cast from int to time_t was a bad idea because it made more than 32 bits available to the called function. better to make a copy. @ text @d77 8 a84 4 if (0 == access(fname, F_OK)) { fprintf(stderr, "tcpdump-split: will not overwrite existing %s\n", fname); exit(2); } @ 1.1 log @Initial revision @ text @d72 2 a73 1 strftime(fname, 128, fmt, gmtime((time_t*)&this_bin)); @