diff --git a/Makefile b/Makefile index 2fe1142..473f4d0 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,20 @@ -CFLAGS = -Wall -Werror -Wno-unused-variable +CFLAGS = -Wall -Werror TARGETS = pmerge puniq p4split pcat TARGETS += hd pyesc printfesc xor unhex all: $(TARGETS) +%: %.go + go build $< + pmerge: pmerge.o pcap.o + puniq: puniq.o pcap.o -p4split: p4split.c pcap.o -pcat: pcat.c pcap.o stream.o + +p4split: p4split.o pcap.o + +pcat: pcat.o pcap.o stream.o +pcat.o: CFLAGS += -Wno-unused-variable clean: rm -f $(TARGETS) *.o diff --git a/README b/README new file mode 100644 index 0000000..52ecd01 --- /dev/null +++ b/README @@ -0,0 +1,97 @@ +The Fluffy Suite +============ + +Fluffy was begun in April 2011 in Tennessee, +as a replacement for the aging "dirtbags.ip" codebase. +It is comprised of multiple small standalone binaries, +which are meant to be chained together, +either on the command-line or from a shell script, +to create a more powerful (and specific) piece of software. + +Usually, a program expects input on stdin, +and produces output on stdout. +Flags are sparse by design. + + +hd -- Hex Dump +-------------- + +Like the normal hd, +but with unicode characters to represent all 256 octets, +instead of using "." for unprintable characters. + + +p4split -- split a pcap file by IPv4 address CIDR +--------------------------- + +Splits a pcap file up ito 256 files, based on a CIDR. For example: + + p4split 32 < foo.pcap + +Will create [0-255].pcap + + +pcat -- print text representation of pcap file +------------------------------ + +Prints a (lossy) text representation of a pcap file to stdout. +This program is the keystone of the Fluffy Suite. +By representing everything as text, +programmers can use any number of standard Unix text processing tools, +such as sed, awk, cut, grep, or head. + + +pmerge -- merge pcap files +------------------------------------------- + +Takes a list of pcap files, assuming they are sorted by time +(you would have to work hard to create any other kind), +and merges them into a single sorted output. + + +printfesc -- printf escape input +-------------------------------- + +Reads octets, +writes a string suitable for copy-paste into printf. + + +puniq -- omit repeated frames +-------------------------------- + +Removes duplicate frames from input, +writing to output. + + +pyesc -- python escape input +--------------------------------- + +Escapes input octets for pasting into a python "print" statement. + + + +unhex -- unescape hex +--------------------------------- + +Reads ASCII hex codes on stdin, +writes those octets to stdout. + +The following pipe is equivalent to "cat": + + ./hd | cut -b 11-58 | ./unhex + + +xor -- xor mask octets +-------------------------------- + +Applies the given mask as an xor to input. +The mask will be repeated, +so for a 1-value mask, every octet is xored against that value. +For a 16-value mask, the mask is applied to 16-octet chunks at a time. + +The "-x" option treats values as hex. + +The following pipe is equivalent to "cat": + + ./xor 42 | ./xor -x 2A + diff --git a/hd.go b/hd.go new file mode 100644 index 0000000..f488738 --- /dev/null +++ b/hd.go @@ -0,0 +1,77 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "io" +) + +const charset = "" + + "·☺☻♥♦♣♠•◘○◙♂♀♪♫☼" + + "►◄↕‼¶§▬↨↑↓→←∟↔▲▼" + + " !\"#$%&'()*+,-./" + + "0123456789:;<=>?" + + "@ABCDEFGHIJKLMNO" + + "PQRSTUVWXYZ[\\]^_" + + "`abcdefghijklmno" + + "pqrstuvwxyz{|}~⌂" + + + "ÇüéâäàåçêëèïîìÄÅ" + + "ÉæÆôöòûùÿÖÜ¢£¥€ƒ" + + "áíóúñѪº½⅓¼⅕⅙⅛«»" + + "░▒▓│┤╡╢╖╕╣║╗╝╜╛┐" + + "└┴┬├─┼╞╟╚╔╩╦╠═╬╧" + + "╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀" + + "αßΓπΣσµτΦΘΩδ∞φε∩" + + "⁰¹²³⁴⁵⁶⁷⁸⁹ⁱⁿ⁽⁼⁾¤" + +func main() { + offset := 0 + b := make([]byte, 16) + lb := make([]byte, 16) + chars := []rune(charset) + skipping := false + + for ;; { + n, err := os.Stdin.Read(b) + if err != nil { + if err != io.EOF { + fmt.Println("read failed:", err) + } + break + } + + if (offset > 0) && (bytes.Equal(lb, b)) { + if ! skipping { + fmt.Println("*") + } + skipping = true + continue + } + copy(lb, b) + skipping = false + + fmt.Printf("%08x ", offset) + offset += n + + for i := 0; i < 16; i += 1 { + if i % 8 == 0 { + fmt.Printf(" ") + } + if i < n { + fmt.Printf("%02x ", b[i]) + } else { + fmt.Printf(" ") + } + } + + fmt.Printf("ǀ") + for i := 0; i < n; i += 1 { + fmt.Printf("%c", chars[b[i]]) + } + fmt.Printf("ǀ\n") + } + + fmt.Printf("%08x\n", offset) +} diff --git a/pcat.c b/pcat.c index 28ea284..bdc9c31 100644 --- a/pcat.c +++ b/pcat.c @@ -1,3 +1,17 @@ +/* + * pcat.c -- pcap to text + * + * Reads pcap on stdin, dumps text representation to stdout. + * This discards or ignores some parts of packets. If fidelity is a concern, + * deal directly with the original pcap. + * + * Output lines are of the form: + * + * PROTO SRC DST OPTS PAYLOAD + * + + */ + #include #include #include "pcap.h" @@ -31,33 +45,33 @@ print_payload(struct stream *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); + uint16_t sport = read_uint16(s); + uint16_t dport = read_uint16(s); + uint32_t seq = read_uint32(s); + uint32_t ack = read_uint32(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); + uint16_t window = read_uint16(s); + uint16_t chksum = read_uint16(s); + uint16_t urgent = read_uint16(s); if (hlen < 20) { printf("!"); } - printf("TCP %s,%u,%u %s,%u,%u ", saddr_s, sport, seq, daddr_s, dport, ack); + printf("TCP %s,%u %s,%u %u,%u,%d ", saddr_s, sport, daddr_s, dport, seq, ack, flags); } 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); + uint16_t sport = read_uint16(s); + uint16_t dport = read_uint16(s); + uint16_t len = read_uint16(s); + uint16_t chksum = read_uint16(s); - printf("UDP %s,%u %s,%u ", saddr_s, sport, daddr_s, dport); + printf("UDP %s,%u %s,%u 0 ", saddr_s, sport, daddr_s, dport); } void @@ -65,7 +79,7 @@ process_icmp(struct stream *s, char *saddr_s, char *daddr_s) { uint8_t type = read_uint8(s); uint8_t code = read_uint8(s); - uint16_t checksum = read_uint16be(s); + uint16_t checksum = read_uint16(s); printf("ICMP %s %s %d ", saddr_s, daddr_s, code); } @@ -76,14 +90,14 @@ 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); + uint16_t length = read_uint16(s); + uint16_t id = read_uint16(s); + uint16_t off = read_uint16(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); + uint16_t chksum = read_uint16(s); + uint32_t saddr = read_uint32(s); + uint32_t daddr = read_uint32(s); char saddr_s[20]; char daddr_s[20]; @@ -125,12 +139,12 @@ print_ethernet(struct stream *s) sread(s, &saddr, sizeof(saddr)); sread(s, &daddr, sizeof(daddr)); - ethertype = read_uint16be(s); + ethertype = read_uint16(s); if (ethertype == 0x8100) { // VLAN - read_uint16be(s); - ethertype = read_uint16be(s); + read_uint16(s); + ethertype = read_uint16(s); } switch (ethertype) { @@ -146,7 +160,7 @@ print_frame(struct pcap_file *p, struct pcap_pkthdr *hdr, char const *frame) struct stream streambuf; struct stream *s = &streambuf; - sinit(s, frame, hdr->caplen); + sinit(s, frame, hdr->caplen, ENDIAN_BIG); printf("%u.%u ", hdr->ts.tv_sec, hdr->ts.tv_usec); switch (p->linktype) { case LINKTYPE_ETHERNET: diff --git a/printfesc.c b/printfesc.c index e4f84bf..aae7904 100644 --- a/printfesc.c +++ b/printfesc.c @@ -1,4 +1,5 @@ #include +#include int main(int argc, char *argv[]) @@ -11,13 +12,24 @@ main(int argc, char *argv[]) switch (c) { case EOF: break; - case '0' ... '9': - case 'A' ... 'Z': - case 'a' ... 'z': - putchar(c); + case '\n': + printf("\\n"); + break; + case '\r': + printf("\\r"); + break; + case '\t': + printf("\\t"); + break; + case '"': + printf("\\\""); break; default: - printf("\\\\%03o", c); + if (isprint(c)) { + putchar(c); + } else { + printf("\\%03o", c); + } break; } } diff --git a/stream.c b/stream.c index 293155d..48b83ef 100644 --- a/stream.c +++ b/stream.c @@ -5,10 +5,11 @@ #include "stream.h" void -sinit(struct stream *s, char const *buf, size_t buflen) +sinit(struct stream *s, char const *buf, size_t buflen, enum endianness endian) { s->buf = buf; s->len = buflen; + s->endian = endian; } bool @@ -25,7 +26,7 @@ sskip(struct stream *s, size_t count) } bool -sread(struct stream * s, void *buf, size_t count) +sread(struct stream *s, void *buf, size_t count) { void const *d = s->buf; @@ -37,8 +38,10 @@ sread(struct stream * s, void *buf, size_t count) return true; } + + uint8_t -read_uint8(struct stream * s) +read_uint8(struct stream *s) { uint8_t *d = (uint8_t *) s->buf; @@ -48,8 +51,10 @@ read_uint8(struct stream * s) return d[0]; } + + uint16_t -read_uint16be(struct stream * s) +read_uint16be(struct stream *s) { uint8_t *d = (uint8_t *) s->buf; @@ -59,8 +64,9 @@ read_uint16be(struct stream * s) return ((d[0] << 8) | (d[1] << 0)); } + uint16_t -read_uint16le(struct stream * s) +read_uint16le(struct stream *s) { uint8_t *d = (uint8_t *) s->buf; @@ -70,11 +76,21 @@ read_uint16le(struct stream * s) return ((d[0] << 0) | (d[1] << 8)); } +uint16_t +read_uint16(struct stream *s) +{ + if (s->endian == ENDIAN_BIG) { + return read_uint16be(s); + } else { + return read_uint16le(s); + } +} + + uint32_t -read_uint32be(struct stream * s) +read_uint32be(struct stream *s) { uint8_t *d = (uint8_t *) s->buf; - if (!sskip(s, 4)) { return 0; } @@ -82,12 +98,21 @@ read_uint32be(struct stream * s) } uint32_t -read_uint32le(struct stream * s) +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)); } + +uint32_t +read_uint32(struct stream *s) +{ + if (s->endian == ENDIAN_BIG) { + return read_uint32be(s); + } else { + return read_uint32le(s); + } +} diff --git a/stream.h b/stream.h index 6115003..03de2a5 100644 --- a/stream.h +++ b/stream.h @@ -5,18 +5,26 @@ #include #include +enum endianness { + ENDIAN_BIG, + ENDIAN_LITTLE +}; + struct stream { char const *buf; size_t len; + enum endianness endian; }; -void sinit(struct stream *s, char const *buf, size_t len); +void sinit(struct stream *s, char const *buf, size_t len, enum endianness endian); 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); +uint16_t read_uint16(struct stream *s); uint32_t read_uint32be(struct stream *s); uint32_t read_uint32le(struct stream *s); +uint32_t read_uint32(struct stream *s); #endif