commit 722b3776cb10ff7bd6810fc1a20e0fc882394313 Author: Neale Pickett Date: Thu Apr 21 16:12:01 2011 -0600 Working pmerge command diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..29db8d2 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +CFLAGS = -Wall -Werror + +pmerge: pmerge.o pcap.o \ No newline at end of file diff --git a/pcap.c b/pcap.c new file mode 100644 index 0000000..7e1770c --- /dev/null +++ b/pcap.c @@ -0,0 +1,76 @@ +#include +#include +#include "pcap.h" + +int +pcap_read_header(FILE *f) +{ + struct pcap_file_header h; + int swap; + + if (1 != fread(&h, sizeof(h), 1, f)) { + h.magic = 0; + } + + if (MAGIC == h.magic) { + swap = 0; + } else if (bswap32(MAGIC) == h.magic) { + swap = 1; + } else { + return -1; + } + if ((h.version_major != 2) || (h.version_minor != 4)) return -1; + + if (swap) h.snaplen = bswap32(h.snaplen); + if (h.snaplen > MAXFRAME) return -1; + + return swap; +} + +int +pcap_write_header(FILE *f) +{ + struct pcap_file_header h = { MAGIC, 2, 4, 0, 0, MAXFRAME, 1 }; + + if (1 != fwrite(&h, sizeof(h), 1, stdout)) { + return -1; + } + + return 0; +} + +int +pcap_open_in(struct pcap_file *ctx, FILE *f) +{ + int ret; + + ret = pcap_read_header(f); + if (-1 == ret) return -1; + + ctx->swap = ret; + ctx->f = f; + return 0; +} + +int +pcap_read_pkthdr(struct pcap_file *ctx, struct pcap_pkthdr *hdr) +{ + if (1 != fread(hdr, sizeof(*hdr), 1, ctx->f)) { + return -1; + } + + if (ctx->swap) { + hdr->ts.tv_sec = bswap32(hdr->ts.tv_sec); + hdr->ts.tv_usec = bswap32(hdr->ts.tv_usec); + hdr->caplen = bswap32(hdr->caplen); + hdr->len = bswap32(hdr->len); + } + + return 0; +} + +void +pcap_close(struct pcap_file *ctx) +{ + fclose(ctx->f); +} diff --git a/pcap.h b/pcap.h new file mode 100644 index 0000000..0c08feb --- /dev/null +++ b/pcap.h @@ -0,0 +1,66 @@ +#ifndef __PCAP_H__ +#define __PCAP_H__ + +#include +#include + +#define MAGIC 0xa1b2c3d4 +#define MAXFRAME 9000 + +struct pcap_file { + FILE *f; + int swap; +}; + +struct pcap_file_header { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; /* gmt to local correction */ + uint32_t sigfigs; /* accuracy of timestamps */ + int32_t snaplen; /* max length saved portion of each pkt */ + int32_t linktype; /* data link type (LINKTYPE_*) */ +}; + +struct pcap_pkthdr { + struct pcap_timeval { + uint32_t tv_sec; + uint32_t tv_usec; + } ts; /* time stamp */ + uint32_t caplen; /* length of portion present */ + uint32_t len; /* length this packet (off wire) */ +}; + +#ifndef max +# define max(a, b) ((a)>(b)?(a):(b)) +#endif + +#ifndef min +# define min(a, b) ((a)<(b)?(a):(b)) +#endif + +#define bswap32(i) (((i & 0xff000000) >> 030) | \ + ((i & 0x00ff0000) >> 010) | \ + ((i & 0x0000ff00) << 010) | \ + ((i & 0x000000ff) << 030)) +#define bswap16(i) (((i & 0xff00) >> 010) | \ + ((i & 0x00ff) << 010)) + + +/* Debugging help */ +#define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#define DUMP() DUMPf("") +#define DUMP_d(v) DUMPf("%s = %d", #v, v) +#define DUMP_u(v) DUMPf("%s = %u", #v, v) +#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v) +#define DUMP_s(v) DUMPf("%s = %s", #v, v) +#define DUMP_c(v) DUMPf("%s = %c", #v, v) +#define DUMP_p(v) DUMPf("%s = %p", #v, v) + +int pcap_read_header(FILE *f); +int pcap_write_header(FILE *f); +int pcap_open_in(struct pcap_file *ctx, FILE *f); +int pcap_read_pkthdr(struct pcap_file *ctx, struct pcap_pkthdr *hdr); +void pcap_close(struct pcap_file *ctx); + +#endif /* __PCAP_H__ */ diff --git a/pmerge.c b/pmerge.c new file mode 100644 index 0000000..dae49a9 --- /dev/null +++ b/pmerge.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include "pcap.h" + +struct input_file { + int active; + struct pcap_file p; + struct pcap_pkthdr next; +}; + +int +usage(int ret) +{ + printf("Usage: pmerge FILE ...\n"); + printf("\n"); + printf("Merges pcap files, outputting time-ordered pcap stream\n"); + return ret; +} + +int +read_next(struct input_file *file) +{ + if (! file->active) return -1; + + if (-1 == pcap_read_pkthdr(&file->p, &file->next)) { + pcap_close(&file->p); + file->active = 0; + file->next.ts.tv_sec = 0xffffffff; + file->next.ts.tv_usec = 0xffffffff; + return -1; + } + + return 0; +} + +int +main(int argc, char *argv[]) +{ + struct input_file files[argc-1]; + int nfiles = 0; + int nopen; + int i, ret; + + if (1 == argc) return usage(0); + + /* Open input files */ + for (i = 0; i < argc-1; i += 1) { + char *fn = argv[i+1]; + struct input_file *cur = &files[nfiles]; + FILE *f; + + if ('-' == fn[0]) return usage(0); + + f = fopen(fn, "rb"); + if (NULL == f) { + perror(fn); + return EX_NOINPUT; + } + + ret = pcap_open_in(&cur->p, f); + if (-1 == ret) { + fprintf(stderr, "%s: unable to process\n", fn); + return EX_IOERR; + } + cur->active = 1; + + if (0 == read_next(cur)) { + nfiles += 1; + } + } + + ret = pcap_write_header(stdout); + if (-1 == ret) { + perror("writing header"); + return EX_IOERR; + } + + nopen = nfiles; + DUMP_d(nopen); + while (nopen) { + struct input_file *cur = &files[0]; + char frame[MAXFRAME]; + size_t len; + + /* Find next oldest frame */ + for (i = 0; i < nfiles; i += 1) { + if (files[i].active && + ((files[i].next.ts.tv_sec < cur->next.ts.tv_sec) || + ((files[i].next.ts.tv_sec == cur->next.ts.tv_sec) && + (files[i].next.ts.tv_usec < cur->next.ts.tv_usec)))) { + cur = &files[i]; + } + } + + /* Make sure it'll fit */ + if (cur->next.caplen > sizeof(frame)) { + fprintf(stderr, "error: huge frame (size %u)\n", len); + return EX_SOFTWARE; + } + + /* Read it */ + len = fread(frame, 1, cur->next.caplen, cur->p.f); + if (len < cur->next.caplen) { + /* Short read */ + cur->next.caplen = len; + pcap_close(&cur->p); + cur->active = 0; + } + + /* Write header + frame */ + if (len) { + if (1 != fwrite(&cur->next, sizeof(cur->next), 1, stdout)) { + perror("error"); + return EX_IOERR; + } + if (len != fwrite(frame, 1, len, stdout)) { + perror("error"); + return EX_IOERR; + } + } + + if (-1 == read_next(cur)) { + nopen -= 1; + } + } + + return 0; +}