diff --git a/Makefile b/Makefile index bfb59c9..382a264 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,13 @@ CFLAGS = -Wall -Werror TARGETS = pmerge puniq p4split hd -TARGETS += pyesc printfesc +TARGETS += pyesc printfesc pcat all: $(TARGETS) pmerge: pmerge.o pcap.o puniq: puniq.o pcap.o p4split: p4split.c pcap.o +pcat: pcat.c pcap.o stream.o clean: rm -f $(TARGETS) *.o diff --git a/pcat.c b/pcat.c new file mode 100644 index 0000000..00d2db9 --- /dev/null +++ b/pcat.c @@ -0,0 +1,199 @@ +#include +#include +#include "pcap.h" +#include "stream.h" + +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + +void +ip4_addr(char *addr_s, uint32_t addr) +{ + snprintf(addr_s, 16, "%u.%u.%u.%u", + (addr >> 24) & 0xff, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + (addr >> 0) & 0xff); +} + +void +print_payload(struct stream *s) +{ + while (s->len) { + printf("%02x", read_uint8(s)); + } +} + +void +process_tcp(struct stream *s, char *saddr_s, char *daddr_s) +{ + uint16_t sport = read_uint16be(s); + uint16_t dport = read_uint16be(s); + uint32_t seq = read_uint32be(s); + uint32_t ack = read_uint32be(s); + uint8_t off = read_uint8(s); + uint8_t hlen = (off >> 4) * 4; + uint8_t flags = read_uint8(s); + uint16_t window = read_uint16be(s); + uint16_t chksum = read_uint16be(s); + uint16_t urgent = read_uint16be(s); + + if (hlen < 20) { + printf("!"); + } + + printf("TCP4 %s:%u %s:%u ", saddr_s, sport, daddr_s, dport); + + // shut the compiler up + if (false && + urgent && + chksum && + window && + flags && + ack && + seq && + false); +} + +void +process_udp(struct stream *s, char *saddr_s, char *daddr_s) +{ + uint16_t sport = read_uint16be(s); + uint16_t dport = read_uint16be(s); + uint16_t len = read_uint16be(s); + uint16_t chksum = read_uint16be(s); + + printf("UDP4 %s:%u %s:%u ", saddr_s, sport, daddr_s, dport); + + // Now, do some shit! + if (false && + len && + chksum && + false); +} + +void +process_ip4(struct stream *s) +{ + uint8_t vhl = read_uint8(s); + uint8_t ihl = (vhl & 0x0f) * 4; + uint8_t tos = read_uint8(s); + uint16_t length = read_uint16be(s); + uint16_t id = read_uint16be(s); + uint16_t off = read_uint16be(s); + uint8_t ttl = read_uint8(s); + uint8_t proto = read_uint8(s); + uint16_t chksum = read_uint16be(s); + uint32_t saddr = read_uint32be(s); + uint32_t daddr = read_uint32be(s); + + char saddr_s[20]; + char daddr_s[20]; + + ip4_addr(saddr_s, saddr); + ip4_addr(daddr_s, daddr); + + // Ignore options + sskip(s, 20 - ihl); + + // Force stream length to IP payload length + s->len = length - ihl; + + switch (proto) { + case IPPROTO_TCP: + process_tcp(s, saddr_s, daddr_s); + break; + case IPPROTO_UDP: + process_udp(s, saddr_s, daddr_s); + break; + default: + printf("P%d %s %s ", proto, saddr_s, daddr_s); + break; + } + + print_payload(s); + + /* Placate compiler */ + if (false && + chksum && + id && + tos && + ttl && + off && + false); +} + + +void +print_ethernet(struct stream *s) +{ + uint8_t saddr[6]; + uint8_t daddr[6]; + uint16_t ethertype; + + sread(s, &saddr, sizeof(saddr)); + sread(s, &daddr, sizeof(daddr)); + ethertype = read_uint16be(s); + + if (ethertype == 0x8100) { + // VLAN + read_uint16be(s); + ethertype = read_uint16be(s); + } + + switch (ethertype) { + case 0x0800: // IPv4 + process_ip4(s); + break; + } +} + +void +print_frame(struct pcap_pkthdr *hdr, char const *frame) +{ + struct stream streambuf; + struct stream *s = &streambuf; + + sinit(s, frame, hdr->caplen); + printf("%u,%u ", hdr->ts.tv_sec, hdr->ts.tv_usec); + print_ethernet(s); + printf("\n"); +} + +void +pcat(FILE *f) +{ + struct pcap_file p; + + if (-1 == pcap_open_in(&p, f)) return; + + for (;;) { + struct pcap_pkthdr hdr; + char frame[MAXFRAME]; + + if (-1 == pcap_read_pkthdr(&p, &hdr)) { + break; + } + + if (1 != fread(frame, hdr.caplen, 1, f)) { + break; + } + + print_frame(&hdr, frame); + } +} + + +int +main(int argc, char *argv[]) +{ + pcat(stdin); + + return 0; +} \ No newline at end of file diff --git a/stream.c b/stream.c new file mode 100644 index 0000000..b1b2f57 --- /dev/null +++ b/stream.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include "stream.h" + +void +sinit(struct stream *s, char const *buf, size_t buflen) +{ + s->buf = buf; + s->len = buflen; +} + +bool +sskip(struct stream *s, size_t count) +{ + if (count > s->len) { + s->len = 0; + return false; + } + + s->buf += count; + s->len -= count; + return true; +} + +bool +sread(struct stream *s, void *buf, size_t count) +{ + void const *d = s->buf; + + if (! sskip(s, count)) { + return false; + } + memcpy(buf, d, count); + + return true; +} + +uint8_t +read_uint8(struct stream *s) +{ + uint8_t *d = (uint8_t *)s->buf; + + if (! sskip(s, 1)) { + return 0; + } + return d[0]; +} + +uint16_t +read_uint16be(struct stream *s) +{ + uint8_t *d = (uint8_t *)s->buf; + + if (! sskip(s, 2)) { + return 0; + } + return ( + (d[0] << 8) | + (d[1] << 0)); +} + +uint16_t +read_uint16le(struct stream *s) +{ + uint8_t *d = (uint8_t *)s->buf; + + if (! sskip(s, 2)) { + return 0; + } + return ( + (d[0] << 0) | + (d[1] << 8)); +} + +uint32_t +read_uint32be(struct stream *s) +{ + uint8_t *d = (uint8_t *)s->buf; + + if (! sskip(s, 4)) { + return 0; + } + return ( + (d[0] << 24) | + (d[1] << 16) | + (d[2] << 8) | + (d[3] << 0)); +} + +uint32_t +read_uint32le(struct stream *s) +{ + uint8_t *d = (uint8_t *)s->buf; + + if (! sskip(s, 4)) { + return 0; + } + return ( + (d[0] << 0) | + (d[1] << 8) | + (d[2] << 16) | + (d[3] << 24)); +} + diff --git a/stream.h b/stream.h new file mode 100644 index 0000000..c734c28 --- /dev/null +++ b/stream.h @@ -0,0 +1,22 @@ +#ifndef _STREAM_H +#define _STREAM_H + +#include +#include +#include + +struct stream { + char const *buf; + size_t len; +}; + +void sinit(struct stream *s, char const *buf, size_t len); +bool sskip(struct stream *s, size_t count); +bool sread(struct stream *s, void *buf, size_t count); +uint8_t read_uint8(struct stream *s); +uint16_t read_uint16be(struct stream *s); +uint16_t read_uint16le(struct stream *s); +uint32_t read_uint32be(struct stream *s); +uint32_t read_uint32le(struct stream *s); + +#endif