From 4c6bac000f9283f07c2990465d99a8ffcf521b4c Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Thu, 14 Jul 2011 18:55:41 -0600 Subject: [PATCH] add p4split utility --- Makefile | 5 +- p4split.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ pcap.c | 2 + pmerge.c | 8 ++-- 4 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 p4split.c diff --git a/Makefile b/Makefile index e7dffcb..47c9095 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,11 @@ CFLAGS = -Wall -Werror -TARGETS = pmerge puniq +TARGETS = pmerge puniq p4split all: $(TARGETS) pmerge: pmerge.o pcap.o puniq: puniq.o pcap.o +p4split: p4split.c pcap.o clean: - rm -f $(TARGETS) + rm -f $(TARGETS) *.o diff --git a/p4split.c b/p4split.c new file mode 100644 index 0000000..3ba2e64 --- /dev/null +++ b/p4split.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include "pcap.h" + +/* Gaah so much crap */ +#include +#include +#include +#include +#include + + +int +usage(int ret) +{ + fprintf(stderr, "Usage: pip4split CIDR\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Splits pcap on stdin into up to 256 files, based on CIDR.\n"); + return ret; +} + + +int +parse_cidr(char *s, uint32_t *addr, uint8_t *bits) +{ + char *slash = index(s, '/'); + struct in_addr inp; + + if (slash) { + *slash = 0; + *bits = atoi(slash + 1); + } else { + *bits = 0; + } + + if (0 == inet_aton(s, &inp)) return -1; + *addr = ntohl(inp.s_addr); + + return 0; +} + + +int +main(int argc, char *argv[]) +{ + struct pcap_file p; + struct pcap_file out[256]; + int ok = 0; + uint32_t addr; + uint32_t mask; + uint8_t bits; + uint8_t shr; + int i; + + if (argc != 2) return usage(0); + if (-1 == parse_cidr(argv[1], &addr, &bits)) return usage(0); + if (bits > 24) return usage(0); + if (bits % 8) { + fprintf(stderr, "Warning: routing prefix is not a multiple of 8.\n"); + } + + mask = ~((1 << (32 - bits)) - 1); + addr &= mask; + shr = bits - 8; + + for (i = 0; i < 256; i += 1) { + out[i].f = NULL; + } + + if (-1 == pcap_open_in(&p, stdin)) return usage(0); + + while (1) { + struct pcap_pkthdr hdr; + uint8_t octet; + char frame[MAXFRAME]; + + ok = 1; + if (-1 == pcap_read_pkthdr(&p, &hdr)) break; + if (1 != fread(frame, hdr.caplen, 1, p.f)) break; + + + { + struct ether_header *eh = (struct ether_header *)frame; + struct iphdr *ih = (struct iphdr *)(frame + sizeof(struct ether_header)); + uint32_t a; + + /* VLAN tag */ + if (ntohs(eh->ether_type) == 0x8100) { + ih = (struct iphdr *)((char *)ih + 4); + } + + a = ntohl(ih->saddr); + if ((a & mask) != addr) { + a = ntohl(ih->daddr); + if ((a & mask) != addr) { + fprintf(stderr, "Warning: dropping unmatched packet %08x -> %08x\n", + ntohl(ih->saddr), ntohl(ih->daddr)); + continue; + } + } + octet = (a & ~mask) >> shr; + } + + ok = 0; + if (! out[octet].f) { + char fn[9]; + FILE *f; + + sfprintf(stderr, fn, "%03d.pcap", octet); + + if (NULL == (f = fopen(fn, "wb"))) break; + if (-1 == pcap_open_out(&out[octet], f)) break; + } + + if (-1 == pcap_write_pkthdr(&out[octet], &hdr)) break; + if (1 != fwrite(frame, hdr.caplen, 1, out[octet].f)) break; + } + + if (! ok) { + perror("Error"); + return 1; + } + + for (i = 0; i < 256; i += 1) { + if (out[i].f) { + pcap_close(&p); + } + } + + return 0; +} diff --git a/pcap.c b/pcap.c index e3e6ae9..1eb7309 100644 --- a/pcap.c +++ b/pcap.c @@ -54,6 +54,8 @@ pcap_read_pkthdr(struct pcap_file *ctx, struct pcap_pkthdr *hdr) hdr->len = bswap32(hdr->len); } + if (hdr->caplen > MAXFRAME) return -1; + return 0; } diff --git a/pmerge.c b/pmerge.c index 94c0c13..6c0d71d 100644 --- a/pmerge.c +++ b/pmerge.c @@ -12,9 +12,9 @@ struct input_file { int usage(int ret) { - printf("Usage: pmerge FILE ...\n"); - printf("\n"); - printf("Merges pcap files, outputting time-ordered pcap stream\n"); + fprintf(stderr, "Usage: pmerge FILE ...\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Merges pcap files, outputting time-ordered pcap stream\n"); return ret; } @@ -93,7 +93,7 @@ main(int argc, char *argv[]) /* Make sure it'll fit */ if (cur->next.caplen > sizeof(frame)) { - fprintf(stderr, "error: huge frame (size %u)\n", len); + fprintf(stderr, "error: huge frame (size %u)\n", (unsigned int)len); return EX_SOFTWARE; }