wm: dnsparser

Download patch

ref: eea3e7f97185f0c6ac097bad8009f23eee9b7b20
parent: 74185653ad7928a482a46eb125f2a630c5049d5a
author: mkf <mkf@cloud9p.org>
date: Wed Jul 31 08:23:44 EDT 2024

refactor

--- /dev/null
+++ b/common.c
@@ -1,0 +1,36 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void
+err(int fatal, char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	
+	fprintf(stderr, fatal ? "FATAL: " : "WARN: ");
+	vfprintf(stderr, fmt, args);
+	fprintf(stderr, "\n");
+	
+	va_end(args);
+
+	if(fatal)
+	{
+		fflush(stdout);
+		fclose(stdout);
+		abort();
+	}
+}
+
+uint16_t
+get2(const u_char *octet)
+{
+	return octet[0] << 8 | octet[1];
+}
+
+uint32_t
+get4(const u_char *octet)
+{
+	return get2(octet) << 8 * 2 | get2(octet + 2);
+}
\ No newline at end of file
--- /dev/null
+++ b/common.h
@@ -1,0 +1,296 @@
+#define debug 0
+
+enum
+{
+	/* sizes and stuff */
+	ETHER_LEN = 14,
+	ETHER_ADDR_LEN = 6,
+	
+	UDP_SIZE = 8,
+
+	/* sizes of each field in header */
+	ETHER_DST = ETHER_ADDR_LEN,
+	ETHER_SRC = ETHER_ADDR_LEN,
+	ETHER_TYPE = 2,
+
+	PKT_VHL = 2,
+	PKT_LEN = 2,
+	PKT_ID = 4,
+	PKT_TTL = 1,
+	PKT_PROTO = 1,
+	PKT_SUM = 2,
+	PKT_SRC = 4,
+	PKT_DST = 4,
+
+	/* udp stuff */
+	UDP_SRCPORT = 2,
+	UDP_DSTPORT = 2,
+	UDP_LEN = 2,
+	UDP_SUM = 2,
+	
+	/* tcp stuff */
+	TCP_SRCPORT = 2,
+	TCP_DSTPORT = 2,
+	TCP_SEQNUM = 4,
+	TCP_ACKNUM = 4,
+	TCP_OFFSET = 1, /* half a byte is used */
+	TCP_FLAGS = 1,
+	TCP_WINSIZE = 2,
+	TCP_SUM = 2,
+	TCP_URGPTR = 2,
+	TCP_OPTS = 2,
+
+	/* tcp flags @ 13 */
+	TCP_FLAG_ACK = 0x010,
+	TCP_FLAG_PSH = 0x008,
+	TCP_FLAG_SYN = 0x002,
+	TCP_FLAG_FIN = 0x001,
+	
+	/* dns */
+	DNS_ID = 2,
+	DNS_FLAGS = 2,
+	DNS_COUNT_QUERIES = 2,
+	DNS_COUNT_ANSWERS = 2,
+	DNS_COUNT_AUTH_RR = 2,
+	DNS_COUNT_ADD_RR = 2,
+	DNS_TYPE = 2,
+	DNS_CLASS = 2,
+	DNS_BACKREF = 2, /* that c0 ff thingi which back references */
+	DNS_TTL = 4,
+	DNS_LEN = 2,
+	
+	/* dns flags bits @ 2 */
+	DNS_ISRESP = 0x8000,
+	DNS_OPCODE = 0x7800,
+	
+	DNS_FLAGS_OPCODE_QUERY = 0x4000,
+	DNS_FLAGS_OPCODE_IQUERY = 0x2000,
+	DNS_FLAGS_OPCODE_STATUS = 0x1000,	/* 2 bits */
+	DNS_FLAGS_OPCODE_NOTIFY = 0x0800,
+	
+	DNS_AUTH = 0x0400,
+	DNS_TRUNCATED = 0x0200,
+	DNS_RD = 0x0100,
+	DNS_RA = 0x0080,
+	DNS_Z = 0x0040,
+	DNS_AD = 0x0020,
+	DNS_CD = 0x0010,
+	DNS_RCODE = 0x000F,
+	
+	/* tls record */
+	TLS_RECORD_CONTENTTYPE = 1,
+	TLS_RECORD_VERSION = 1,
+	TLS_RECORD_LEN = 2,
+	
+	/* tls 1.2 handshake */
+	TLS_HANDSHAKE_TYPE = 1,
+	TLS_HANDSHAKE_LEN = 3,
+	TLS_HANDSHAKE_VERSION = 2,
+	TLS_HANDSHAKE_RANDOM = 32,
+	TLS_HANDSHAKE_SESSIONID_LEN = 1,
+	TLS_HANDSHAKE_SESSIONID = 32,
+	TLS_HANDSHAKE_CIPHERS_LEN = 2,
+	TLS_HANDSHAKE_CIPHERS = 54,
+	TLS_HANDSHAKE_COMP_LEN = 1,
+	TLS_HANDSHAKE_COMPS = 1,
+	TLS_HANDSHAKE_EXTS_LEN = 2, /* number of all extensions */
+	TLS_HANDSHAKE_EXT_TYPE = 2,
+	TLS_HANDSHAKE_EXT_LEN = 2, /* (data) length of a specfic extension */
+		
+	/* ether types */
+	ETHER_IP4 = 0x800,
+	ETHER_IP6 = 0x86dd,
+
+	/* packet types */
+	PKT_TCP = 6,
+	PKT_UDP = 17,
+
+	/* dns types */
+	DNS_TYPE_A = 1,
+	DNS_TYPE_CNAME = 5,
+	DNS_TYPE_MX = 15,
+	DNS_TYPE_TXT = 16,
+	DNS_TYPE_AAAA = 28,
+	
+	/* dns classes */
+	DNS_CLASS_IN = 1, /* lonely :( */
+	
+	/* tls handshake types */
+	TLS_HELLO_REQ = 0,
+	TLS_CLIENT_HELLO = 1,
+	TLS_SERVER_HELLO = 2,
+	TLS_NEW_TICKET = 4,
+	TLS_END_OF_EARLY_DATA = 5,
+	TLS_CERT = 11,
+	TLS_CERT_REQ = 13,
+	TLS_FINISHED = 20,
+	
+	/* tls content types */
+	TLS_ALERT = 21,
+	TLS_HANDSHAKE = 22,
+	TLS_APPLICATION_DATA = 23,
+	TLS_HEARTBEAT = 24,
+	TLS_CID = 25, /* ? */
+	TLS_ACK = 26,
+	TLS_RTC = 27, /* ? */
+};
+
+/*
+ * each parser have at least these two
+ * they may have more functions internally and externally
+ */
+typedef struct
+{
+	int (*parse)();
+	void (*print)();
+}Parser;
+
+extern pcap_t *handle;
+extern struct bpf_program dnsfilter;
+
+/* common.c */
+uint16_t get2(const u_char *octet);
+uint32_t get4(const u_char *octet);
+void err(int fatal, char *fmt, ...);
+
+/* ether.c */
+typedef struct
+{
+	uint8_t dst[ETHER_ADDR_LEN];
+	uint8_t src[ETHER_ADDR_LEN];
+	int type;
+}Ether;
+
+char* etherTypeToStr(uint16_t frame);
+int parseEther(const u_char *pkt, Ether *e);
+void printEther(Ether e);
+
+extern Parser etherParser;
+
+/* (ipv4) pkt.c */
+typedef struct
+{
+	uint8_t version;
+
+	uint8_t headerlen;
+	uint8_t len;
+
+	uint8_t ttl;
+	uint8_t proto; /* UDP, TCP */
+	uint16_t sum; /* checksum of packet */
+
+	uint32_t srcip;
+	uint32_t dstip;
+}Pkt;
+
+#define IP4_HL(octet)	(octet & 0x0f)
+#define IP4_V(octet)	(octet >> 4) 
+
+int parsePkt(const u_char *pkt, Pkt *p);
+char* pktTypeToStr(const u_char pkt);
+void printPkt(Pkt p);
+
+extern Parser pktParser;
+
+/* udp.c */
+typedef struct
+{
+	uint16_t srcport;
+	uint16_t dstport;
+
+	uint16_t len;
+	uint16_t sum;
+}Udp;
+
+int parseUdp(const u_char *pkt, Udp *udp);
+void printUdp(Udp udp);
+
+extern Parser udpParser;
+
+/* tcp.c */
+typedef struct
+{
+	uint16_t srcport;
+	uint16_t dstport;
+
+	uint32_t seqnum;
+	uint32_t acknum;
+	
+	uint16_t offset;
+	uint16_t flags;
+	
+	uint16_t winsize;
+	uint8_t sum;
+	
+	uint16_t urgentptr;
+	/* we don't care about options */
+}Tcp;
+
+int parseTcp(const u_char *pkt, Tcp *tcp);
+void printTcp(Tcp tcp);
+
+extern Parser tcpParser;
+
+/*
+ * dns.c
+ * a maximum size of 255 for strings is assumed
+ */
+typedef struct
+{
+	/* is it response or request */
+	uint16_t id;
+	uint16_t flags;
+	
+	/* count(s) */
+	uint16_t nQueries;
+	uint16_t nAnswers;
+	uint16_t nAuthRR;
+	uint16_t nAddRR;
+	
+	char domain[255];
+	
+	uint8_t type;
+	uint8_t class;
+	uint32_t ttl;
+	uint32_t len;
+	union
+	{
+		/* A */
+		uint8_t ip[4];
+
+		/* AAAA */
+		uint16_t ip6[8];
+
+		/* CNAME */
+		u_char cname[255];
+	};
+}Dns;
+
+int parseDnsCname(const u_char *pkt, u_char cname[255], uint pos, uint len);
+int parseDns(const u_char *pkt, Dns *dns);
+char* dnsClassToStr(uint16_t class);
+char* dnsTypeToStr(uint16_t type);
+void printDns(Dns dns);
+extern Parser dnsParser;
+
+/* tls.c */
+typedef struct
+{
+	uint16_t srcport;
+	uint16_t dstport;
+
+	uint32_t seqnum;
+	uint32_t acknum;
+	
+	uint16_t offset;
+	uint16_t flags;
+	
+	uint16_t winsize;
+	uint8_t sum;
+	
+	uint16_t urgentptr;
+	/* we don't care about options */
+}Tls;
+
+extern Parser tlsParser;
+
--- /dev/null
+++ b/dns.c
@@ -1,0 +1,222 @@
+/*
+ * notes:
+ * we dont parse compressed names very well.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <pcap.h>
+#include "common.h"
+
+/* 
+ * pos must be after data length, before size of first string
+ * len must be dns.len
+ */
+int
+parseDnsCname(const u_char *pkt, u_char cname[255], uint pos, uint len)
+{
+	int section_header, cname_head = 0;
+	const u_char *pkt_head;
+	
+	pkt_head = pkt + pos;
+	for(int i = 0 ; i < len ; i++)
+	{
+		section_header = pkt_head[i];
+		
+		/* compressed, we'r too lazy to handle it */
+		if(section_header == 0xc0 || section_header == 0x0)
+			break;
+		
+		/* not compressed, regular size */
+		strncpy(cname + cname_head, pkt_head + i + 1, section_header);
+		
+		i += section_header;
+		cname_head += section_header;
+		cname[cname_head++] = '.';
+	}
+	return 1;
+}
+
+/*
+ * dns have some variable length fields,
+ * we need to keep our positon somewhere
+ */
+int
+parseDns(const u_char *pkt, Dns *dns)
+{
+	int section_header;
+	int pos = 0;
+	int name_head = 0;
+	
+	dns->id = get2(pkt + pos);
+	pos += DNS_ID;
+	
+	dns->flags = get2(pkt + pos);
+	pos += DNS_FLAGS;
+	
+	dns->nQueries = get2(pkt + pos);
+	pos += DNS_COUNT_QUERIES;
+	
+	dns->nAnswers = get2(pkt + pos);
+	pos += DNS_COUNT_ANSWERS;
+	
+	dns->nAuthRR = get2(pkt + pos);
+	pos += DNS_COUNT_AUTH_RR;
+	
+	dns->nAddRR = get2(pkt + pos);
+	pos += DNS_COUNT_ADD_RR;
+	
+	memset(dns->domain, '\0', sizeof(dns->domain));
+	for(int i = 0 ; i < sizeof(dns->domain) ; i++)
+	{
+		section_header = pkt[pos];
+		pos++;
+		
+		if(section_header == 0x0)
+			break;
+		
+		strncpy(dns->domain + name_head, pkt + pos, section_header);
+		name_head += section_header;
+		dns->domain[name_head++] = '.';
+		pos += section_header;
+	}
+
+	dns->type = get2(pkt + pos);
+	pos += DNS_TYPE;
+	dns->class = get2(pkt + pos);
+	pos += DNS_CLASS;
+		
+	if(dns->flags & DNS_ISRESP)
+	{
+		/* a resposnse, should have answers */
+		pos += DNS_BACKREF; /* skip domain name */
+		pos += DNS_TYPE; /* skip type */
+		pos += DNS_CLASS; /* skip class */
+		
+		/* we are in next packet */
+		dns->ttl = get4(pkt + pos);
+		pos += DNS_TTL;
+		
+		dns->len = get2(pkt + pos);
+		pos += DNS_LEN;
+	}
+	else
+		return 1;
+
+	switch(dns->type)
+	{
+		case DNS_TYPE_A:
+			dns->ip[0] = pkt[pos++];
+			dns->ip[1] = pkt[pos++];
+			dns->ip[2] = pkt[pos++];
+			dns->ip[3] = pkt[pos++];
+			break;
+		case DNS_TYPE_AAAA:
+			dns->ip6[0] = get2(pkt + pos);
+			pos += 2;		
+			dns->ip6[1] = get2(pkt + pos);
+			pos += 2;
+			dns->ip6[2] = get2(pkt + pos);
+			pos += 2;
+			dns->ip6[3] = get2(pkt + pos);
+			pos += 2;
+			dns->ip6[4] = get2(pkt + pos);
+			pos += 2;		
+			dns->ip6[5] = get2(pkt + pos);
+			pos += 2;
+			dns->ip6[6] = get2(pkt + pos);
+			pos += 2;
+			dns->ip6[7] = get2(pkt + pos);
+			pos += 2;			
+			break;
+		case DNS_TYPE_CNAME:
+			memset(dns->cname, '\0', sizeof(dns->domain));
+			parseDnsCname(pkt, dns->cname, pos, dns->len);
+			break;
+		case DNS_TYPE_MX:
+			break;
+		default:
+			err(1, "parseDnsQuery(%d) unknown type", dns->type);
+	}
+	return 1;
+}
+
+void
+printDns(Dns dns)
+{
+	printf("dns query:\n"
+	"\tid: %d\tflags: %b (%x)\n"
+	"\tnQueries: %d\tnAnswers: %d\tnAuthRR: %d\tnAddRR: %d\n"
+	"\tdomain: %s (%p)\n"
+	"\ttype: %d (%s)\tclass: %s\n"
+	"\tttl: %x (%d)\tlen: %x (%d)\n",
+	
+	dns.id, dns.flags, dns.flags,
+	dns.nQueries, dns.nAnswers, dns.nAuthRR, dns.nAddRR,
+	dns.domain, dns.domain,
+	dns.type, dnsTypeToStr(dns.type), dnsClassToStr(dns.class),
+	dns.ttl, dns.ttl, dns.len, dns.len);
+	
+	if(dns.flags & DNS_ISRESP)
+	{
+		switch(dns.type)
+		{
+		case DNS_TYPE_A:
+			printf("\tip: %d.%d.%d.%d\n",
+			dns.ip[0], dns.ip[1], dns.ip[2], dns.ip[3]);
+			break;
+		case DNS_TYPE_AAAA:
+			printf("\tip6: %x:%x:%x:%x:%x:%x:%x:%x\n",
+			dns.ip6[0], dns.ip6[1], dns.ip6[2], dns.ip6[3],
+			dns.ip6[4], dns.ip6[5], dns.ip6[6], dns.ip6[7]);
+			break;
+		case DNS_TYPE_CNAME:
+			printf("\tcname: %s\n", dns.cname);
+			break;
+		case DNS_TYPE_MX:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+char*
+dnsClassToStr(uint16_t class)
+{
+	switch(class)
+	{
+		case DNS_CLASS_IN:
+			return "IN";
+		default:
+			err(1, "dnsClassToStr(%d): unkown class", class);
+			return NULL;
+	}
+}
+
+char*
+dnsTypeToStr(uint16_t type)
+{
+	switch(type)
+	{
+		case DNS_TYPE_A:
+			return "A";
+		case DNS_TYPE_CNAME:
+			return "CNAME";
+		case DNS_TYPE_TXT:
+			return "TXT";
+		case DNS_TYPE_AAAA:
+			return "AAAA";
+		case DNS_TYPE_MX:
+			return "MX";
+		default:
+			err(1, "dnsTypeToStr(%d): unkown type", type);
+			return NULL;
+	}
+}
+
+Parser dnsParser = {
+	.parse = parseDns,
+	.print = printDns,
+};
\ No newline at end of file
--- a/dnsparser.c
+++ b/dnsparser.c
@@ -7,557 +7,12 @@
 #include <stdio.h>
 #include <pcap.h>
 #include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdarg.h>
 #include <string.h>
+#include "common.h"
 
-#define debug 0
-
-/* /etc/protocols */
-enum
-{
-	/* sizes */
-	ETHER_LEN = 14,
-	ETHER_ADDR_LEN = 6,
-	
-	UDP_SIZE = 8,
-
-	/* relative position of each field in packet */
-	ETHER_DST = 0,
-	ETHER_SRC = 6,
-	ETHER_TYPE = 12,
-
-	PKT_VHL = 0,
-	PKT_LEN = 2,
-	PKT_ID = 4,
-	PKT_TTL = 8,
-	PKT_PROTO = 9,
-	PKT_SUM = 10,
-	PKT_SRC = 12,
-	PKT_DST = 14,
-
-	/* udp stuff */
-	UDP_SRCPORT = 0,
-	UDP_DSTPORT = 2,
-	UDP_LEN = 4,
-	UDP_SUM = 6,
-	
-	/* tcp stuff */
-	TCP_SRCPORT = 0,
-	TCP_DSTPORT = 2,
-	TCP_SEQNUM = 4,
-	TCP_ACKNUM = 8,
-	TCP_OFFSET = 12, /* half a byte is used */
-	TCP_FLAGS = 13,
-	TCP_WINSIZE = 14,
-	TCP_SUM = 16,
-	TCP_URGPTR = 18,
-	TCP_OPTS = 20,
-
-	/* tcp flags @ 13 */
-	TCP_FLAG_ACK = 0x010,
-	TCP_FLAG_PSH = 0x008,
-	TCP_FLAG_SYN = 0x002,
-	TCP_FLAG_FIN = 0x001,
-	
-	/* dns fields */
-	DNS_ID = 0,
-	DNS_FLAGS = 2,
-	DNS_COUNT_QUERIES = 4,
-	DNS_COUNT_ANSWERS = 6,
-	DNS_COUNT_AUTH_RR = 8,
-	DNS_COUNT_ADD_RR = 10,
-	DNS_QUERY = 12,
-
-	/* dns flags bits @ 2 */
-	DNS_ISRESP = 0x8000,
-	DNS_OPCODE = 0x7800,
-	
-	DNS_FLAGS_OPCODE_QUERY = 0x4000,
-	DNS_FLAGS_OPCODE_IQUERY = 0x2000,
-	DNS_FLAGS_OPCODE_STATUS = 0x1000,	/* 2 bits */
-	DNS_FLAGS_OPCODE_NOTIFY = 0x0800,
-	
-	DNS_AUTH = 0x0400,
-	DNS_TRUNCATED = 0x0200,
-	DNS_RD = 0x0100,
-	DNS_RA = 0x0080,
-	DNS_Z = 0x0040,
-	DNS_AD = 0x0020,
-	DNS_CD = 0x0010,
-	DNS_RCODE = 0x000F,
-	
-	/* ether types */
-	IP4 = 0x800,
-	IP6 = 0x86dd,
-
-	/* packet types */
-	TCP = 6,
-	UDP = 17,
-
-	/* dns types */
-	A = 1,
-	CNAME = 5,
-	MX = 15,
-	TXT = 16,
-	AAAA = 28,
-	
-	/* dns classes */
-	IN = 1,
-};
-
-typedef struct
-{
-	uint8_t dst[ETHER_ADDR_LEN];
-	uint8_t src[ETHER_ADDR_LEN];
-	int type;
-}Ether;
-
-typedef struct
-{
-	uint8_t version;
-
-	uint8_t headerlen;
-	uint8_t len;
-
-	uint8_t ttl;
-	uint8_t proto; /* UDP, TCP */
-	uint16_t sum; /* checksum of packet */
-
-	uint32_t srcip;
-	uint32_t dstip;
-}Packet;
-
-#define IP4_HL(octet)	(octet & 0x0f)
-#define IP4_V(octet)	(octet >> 4) 
-
-typedef struct
-{
-	uint16_t srcport;
-	uint16_t dstport;
-
-	uint16_t len;
-	uint16_t sum;
-}UdpPkt;
-
-typedef struct
-{
-	uint16_t srcport;
-	uint16_t dstport;
-
-	uint32_t seqnum;
-	uint32_t acknum;
-	
-	uint16_t offset;
-	uint16_t flags;
-	
-	uint16_t winsize;
-	uint8_t sum;
-	
-	uint16_t urgentptr;
-	/* we don't care about options */
-}TcpPkt;
-
-typedef struct
-{
-	/* is it response or request */
-	uint16_t id;
-	uint16_t flags;
-	
-	/* count(s) */
-	uint16_t nQueries;
-	uint16_t nAnswers;
-	uint16_t nAuthRR;
-	uint16_t nAddRR;
-	
-	char domain[255];
-	
-	uint8_t type;
-	uint8_t class;
-	uint32_t ttl;
-	uint32_t len;
-	union
-	{
-		/* A */
-		uint8_t ip[4];
-
-		/* AAAA */
-		uint16_t ip6[8];
-
-		/* CNAME */
-		u_char cname[255];
-	};
-}DnsQuery;
-
-pcap_t *handle;
 struct bpf_program dnsfilter;
+char errbuf[PCAP_ERRBUF_SIZE];
 
-char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
-
-/* aux */
-void
-err(int fatal, char *fmt, ...)
-{
-	va_list args;
-	va_start(args, fmt);
-	
-	fprintf(stderr, fatal ? "FATAL" : "WARN" ": ");
-	vfprintf(stderr, fmt, args);
-	fprintf(stderr, "\n");
-	
-	va_end(args);
-	fflush(stdout);
-	fclose(stdout);
-	
-	if(fatal)
-		abort();
-}
-
-static uint16_t
-get2(const u_char *octet)
-{
-	return octet[0] << 8 | octet[1];
-}
-
-static uint32_t
-get4(const u_char *octet)
-{
-	return get2(octet) << 8 * 2 | get2(octet + 2);
-}
-
-char*
-etherTypeToStr(uint16_t frame)
-{
-	switch(frame)
-	{
-		case IP4:
-			return "IPv4";
-		case IP6:
-			return "IPv6";
-		default:
-			err(1, "etherTypeToStr(%d): unkown type", frame);
-			return "unkown";
-	}
-}
-
-char*
-pktTypeToStr(const u_char pkt)
-{
-	switch(pkt)
-	{
-		case IPPROTO_UDP:
-			return "UDP";
-		case IPPROTO_TCP:
-			return "TCP";
-		default:
-			err(1, "pktTypeToStr(%d): unkown type", pkt);
-			return NULL;
-	}
-}
-
-char*
-dnsTypeToStr(uint16_t type)
-{
-	switch(type)
-	{
-		case A:
-			return "A";
-		case CNAME:
-			return "CNAME";
-		case TXT:
-			return "TXT";
-		case AAAA:
-			return "AAAA";
-		case MX:
-			return "MX";
-		default:
-			err(1, "dnsTypeToStr(%d): unkown type", type);
-			return NULL;
-	}
-}
-
-char*
-dnsClassToStr(uint16_t class)
-{
-	switch(class)
-	{
-		case IN:
-			return "IN";
-		default:
-			err(1, "dnsClassToStr(%d): unkown class", class);
-			return NULL;
-	}
-}
-
-void
-parseEther(const u_char *pkt, Ether *e)
-{
-	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
-		e->dst[i] = pkt[i];
-
-	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
-		e->src[i] = pkt[i+ETHER_ADDR_LEN];
-
-	e->type = get2(pkt + ETHER_TYPE);
-}
-
-void
-parsePacket(const u_char *pkt, Packet *p)
-{
-	p->version = IP4_V(pkt[0]);
-	p->headerlen = IP4_HL(pkt[0]) * 4;
-
-	p->len = get2(pkt + PKT_LEN);
-	p->ttl = pkt[PKT_TTL];
-	p->proto = pkt[PKT_PROTO];
-	p->sum = get2(pkt + PKT_SUM);
-
-	p->srcip = get4(pkt + PKT_SRC);
-	p->dstip = get4(pkt + PKT_DST);
-}
-
-void
-parseUdp(const u_char *pkt, UdpPkt *udp)
-{
-	udp->srcport = get2(pkt + UDP_SRCPORT);
-	udp->dstport = get2(pkt + UDP_DSTPORT);
-
-	udp->len = get2(pkt + UDP_LEN);
-	udp->sum = get2(pkt + UDP_SUM);
-}
-
-void
-parseTcp(const u_char *pkt, TcpPkt *tcp)
-{
-	tcp->srcport = get2(pkt + TCP_SRCPORT);
-	tcp->dstport = get2(pkt + TCP_DSTPORT);
-
-	tcp->seqnum = get4(pkt + TCP_SEQNUM);
-	tcp->acknum = get4(pkt + TCP_ACKNUM);
-	
-	/* offsets are multiplies of 4 (32-bit) values */
-	tcp->offset = (pkt[TCP_OFFSET] >> 4) * 4;
-	tcp->flags = pkt[TCP_FLAGS];
-	
-	tcp->winsize = get2(pkt + TCP_WINSIZE);
-	tcp->sum = pkt[TCP_SUM];
-	
-	tcp->urgentptr = get2(pkt + TCP_URGPTR);
-}
-
-/* 
- * pos must be after data length, before size of first string
- * len must be dq.len
- */
-int
-parseDnsCname(const u_char *pkt, u_char cname[255], uint pos, uint len)
-{
-	int section_header, cname_head = 0;
-	const u_char *pkt_head;
-	
-	pkt_head = pkt + DNS_QUERY + pos;
-	for(int i = 0 ; i < len ; i++)
-	{
-		section_header = pkt_head[i];
-		
-		/* compressed, we'r too lazy to handle it */
-		if(section_header == 0xc0 || section_header == 0x0)
-			break;
-		
-		/* not compressed, regular size */
-		strncpy(cname + cname_head, pkt_head + i + 1, section_header);
-		
-		i += section_header;
-		cname_head += section_header;
-		cname[cname_head++] = '.';
-	}
-	return 1;
-}
-
-/*
- * dns have some variable length fields,
- * we need to keep our positon somewhere
- */
-int
-parseDnsQuery(const u_char *pkt, DnsQuery *dq)
-{
-	int section_header;
-	int head = 0;
-	int name_head = 0;
-	
-	dq->id = get2(pkt + DNS_ID);
-	dq->flags = get2(pkt + DNS_FLAGS);
-	dq->nQueries = get2(pkt + DNS_COUNT_QUERIES);
-	dq->nAnswers = get2(pkt + DNS_COUNT_ANSWERS);
-	dq->nAuthRR = get2(pkt + DNS_COUNT_AUTH_RR);
-	dq->nAddRR = get2(pkt + DNS_COUNT_ADD_RR);
-	
-	head += DNS_QUERY;
-	memset(dq->domain, '\0', sizeof(dq->domain));
-	
-	for(int i = 0 ; i < sizeof(dq->domain) ; i++)
-	{
-		section_header = pkt[head];
-		head++;
-		
-		if(section_header == 0x0)
-			break;
-		
-		strncpy(dq->domain + name_head, pkt + head, section_header);
-		name_head += section_header;
-		dq->domain[name_head++] = '.';
-		head += section_header;
-	}
-
-	dq->type = get2(pkt + head);
-	head += 2;
-	dq->class = get2(pkt + head);
-	head += 2;
-		
-	if(dq->flags & DNS_ISRESP)
-	{
-		/* a resposnse, should have answers */
-		head += 2; /* skip domain name */
-		head += 2; /* skip type */
-		head += 2; /* skip class */
-		
-		/* we are in next packet */
-		dq->ttl = get4(pkt + head);
-		head += 4;
-		
-		dq->len = get2(pkt + head);
-		head += 2;
-	}
-	else
-		return 1;
-
-	switch(dq->type)
-	{
-		case A:
-			dq->ip[0] = pkt[head++];
-			dq->ip[1] = pkt[head++];
-			dq->ip[2] = pkt[head++];
-			dq->ip[3] = pkt[head++];
-			break;
-		case AAAA:
-			dq->ip6[0] = get2(pkt + head);
-			head += 2;		
-			dq->ip6[1] = get2(pkt + head);
-			head += 2;
-			dq->ip6[2] = get2(pkt + head);
-			head += 2;
-			dq->ip6[3] = get2(pkt + head);
-			head += 2;
-			dq->ip6[4] = get2(pkt + head);
-			head += 2;		
-			dq->ip6[5] = get2(pkt + head);
-			head += 2;
-			dq->ip6[6] = get2(pkt + head);
-			head += 2;
-			dq->ip6[7] = get2(pkt + head);
-			head += 2;			
-			break;
-		case CNAME:
-			memset(dq->cname, '\0', sizeof(dq->domain));
-			parseDnsCname(pkt, dq->cname, head, dq->len);
-			break;
-		case MX:
-			break;
-		default:
-			err(1, "parseDnsQuery(%d) unknown type", dq->type);
-	}
-	return 1;
-}
-
-void
-printEther(Ether e)
-{
-	printf("ether info:\n\tdst:");
-	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
-		printf("%x:", e.dst[i]);
-
-	printf("\tsrc: ");
-	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
-		printf("%x:", e.src[i]);
-
-	printf("\ttype: 0x%x (%s)\n", e.type, etherTypeToStr(e.type));
-}
-
-void
-printPacket(Packet p)
-{
-	printf("ip packet info:\n"
-	"\tversion: 0x%x\theaderlen: 0x%x\tlen: 0x%x\n",
-	p.version, p.headerlen, p.len);
-
-	printf("\tttl: 0%x (%d)\tproto 0%x (%s)\tsum: 0x%x\n",
-	p.ttl, p.ttl, p.proto, pktTypeToStr(p.proto), p.sum);
-
-	printf("\tsrcip: 0x%x\tdstip: 0x%x\n", p.srcip, p.dstip);
-}
-
-void
-printUdpPkt(UdpPkt udp)
-{
-		printf("udp pkt:\n"
-		"\tsrcport: %d\tdstport: %d\n"
-		"\tlen: %d\tsum 0x%x\n",
-		udp.srcport, udp.dstport, udp.len, udp.sum);
-}
-
-void
-printTcpPkt(TcpPkt tcp)
-{
-		printf("tcp pkt:\n"
-		"\tsrcport: %d\tdstport: %d\n"
-		"\tseqnum: %d\tacknum: %d\n"
-		"\toffset: %d\tflags: %b (%x)\n"
-		"\twinsize: %d (%x)\tsum: %d\n",
-		
-		tcp.srcport, tcp.dstport,
-		tcp.seqnum, tcp.acknum,
-		tcp.offset, tcp.flags, tcp.flags,
-		tcp.winsize, tcp.winsize, tcp.sum);
-}
-
-void
-printDnsQuery(DnsQuery dq)
-{
-	printf("dns query:\n"
-	"\tid: %d\tflags: %b (%x)\n"
-	"\tnQueries: %d\tnAnswers: %d\tnAuthRR: %d\tnAddRR: %d\n"
-	"\tdomain: %s (%p)\n"
-	"\ttype: %d (%s)\tclass: %s\n"
-	"\tttl: %x (%d)\tlen: %x (%d)\n",
-	
-	dq.id, dq.flags, dq.flags,
-	dq.nQueries, dq.nAnswers, dq.nAuthRR, dq.nAddRR,
-	dq.domain, dq.domain,
-	dq.type, dnsTypeToStr(dq.type), dnsClassToStr(dq.class),
-	dq.ttl, dq.ttl, dq.len, dq.len);
-	
-	if(dq.flags & DNS_ISRESP)
-	{
-		switch(dq.type)
-		{
-		case A:
-			printf("\tip: %d.%d.%d.%d\n", dq.ip[0], dq.ip[1], dq.ip[2], dq.ip[3]);
-			break;
-		case AAAA:
-			printf("\tip6: %x:%x:%x:%x:%x:%x:%x:%x\n", dq.ip6[0], dq.ip6[1], dq.ip6[2], dq.ip6[3], dq.ip6[4], dq.ip6[5], dq.ip6[6], dq.ip6[7]);
-			break;
-		case CNAME:
-			printf("\tcname: %s\n", dq.cname);
-			break;
-		case MX:
-			break;
-		default:
-			err(1, "parseDnsQuery: unknown type: %d");
-		}
-	}
-}
-
 /* magic happens here! */
 void
 dns_reader(u_char *args, const struct pcap_pkthdr *header, const u_char *pkt)
@@ -565,18 +20,27 @@
 	static int packets = 1;
 	int head = 0;
 	Ether e;
-	Packet p;
-	UdpPkt udp;
-	TcpPkt tcp;
-	DnsQuery dq;
+	Pkt p;
+	Udp udp;
+	Tcp tcp;
+	Dns dns;
 
 	printf("\n==================%3d  ==================\n", packets++);
+		
+	/* XXX */
+	printf("frame info:\n"
+	"\tlen: %d\tcaplen: %d\n"
+	"\ttimeval.tv_sec: %ld\ttimeval.tv_usec: %ld\n",
+	header->len, header->caplen,
+	header->ts.tv_sec, header->ts.tv_usec);
 	
-	
 	parseEther(pkt + head, &e);
 	head += ETHER_LEN;
 	
-	parsePacket(pkt + head, &p);
+	printEther(e);
+	
+	parsePkt(pkt + head, &p);
+	printPkt(p);
 	head += p.headerlen;
 
 	if(p.proto == IPPROTO_UDP)
@@ -611,7 +75,7 @@
 		fprintf(stderr, "\n");
 	}
 
-	parseDnsQuery(pkt + head, &dq);
+	parseDns(pkt + head, &dns);
 
 	printf("frame info:\n"
 	"\tlen: %d\tcaplen: %d\n"
@@ -620,19 +84,21 @@
 	header->ts.tv_sec, header->ts.tv_usec);
 	
 	printEther(e);
-	printPacket(p);
+	printPkt(p);
 	
 	if(p.proto == IPPROTO_UDP)
-		printUdpPkt(udp);
+		printUdp(udp);
 	else if(p.proto == IPPROTO_TCP)
-		printTcpPkt(tcp);
+		printTcp(tcp);
 	
-	printDnsQuery(dq);
+	printDns(dns);
 }
 
 int
 main(int argc, char **argv)
 {
+	pcap_t *handle;
+	
 	if(argc != 2)
 		err(1, "%s: usage: %s file.pcap", argv[0], argv[0]);
 
--- /dev/null
+++ b/ether.c
@@ -1,0 +1,57 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <pcap/pcap.h>
+#include "common.h"
+
+char*
+etherTypeToStr(uint16_t frame)
+{
+	switch(frame)
+	{
+		case ETHER_IP4:
+			return "IPv4";
+		case ETHER_IP6:
+			return "IPv6";
+		default:
+			err(1, "etherTypeToStr(%d): unkown type", frame);
+			return "unkown";
+	}
+}
+
+int
+parseEther(const u_char *pkt, Ether *e)
+{
+	int pos = 0;
+	
+	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
+		e->dst[i] = pkt[i];
+		
+	pos += ETHER_DST;
+	
+	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
+		e->src[i] = pkt[i+ETHER_ADDR_LEN];
+
+	pos += ETHER_SRC;
+	e->type = get2(pkt + pos);
+	
+	return 1;
+}
+
+void
+printEther(Ether e)
+{
+	printf("ether info:\n\tdst:");
+	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
+		printf("%x:", e.dst[i]);
+
+	printf("\tsrc: ");
+	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
+		printf("%x:", e.src[i]);
+
+	printf("\ttype: 0x%x (%s)\n", e.type, etherTypeToStr(e.type));
+}
+
+Parser etherParser = {
+	.parse = parseEther,
+	.print = printEther,
+};
\ No newline at end of file
--- /dev/null
+++ b/pkt.c
@@ -1,0 +1,57 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <pcap.h>
+#include "common.h"
+
+/*
+ * todo: replace IPROTO with our own
+ */
+char*
+pktTypeToStr(const u_char pkt)
+{
+	switch(pkt)
+	{
+		case IPPROTO_UDP:
+			return "UDP";
+		case IPPROTO_TCP:
+			return "TCP";
+		default:
+			err(1, "pktTypeToStr(%d): unkown type", pkt);
+			return NULL;
+	}
+}
+
+int
+parsePkt(const u_char *pkt, Pkt *p)
+{
+	p->version = IP4_V(pkt[0]);
+	p->headerlen = IP4_HL(pkt[0]) * 4;
+
+	p->len = get2(pkt + PKT_LEN);
+	p->ttl = pkt[PKT_TTL];
+	p->proto = pkt[PKT_PROTO];
+	p->sum = get2(pkt + PKT_SUM);
+
+	p->srcip = get4(pkt + PKT_SRC);
+	p->dstip = get4(pkt + PKT_DST);
+	
+	return 1;
+}
+
+void
+printPkt(Pkt p)
+{
+	printf("ip packet info:\n"
+	"\tversion: 0x%x\theaderlen: 0x%x\tlen: 0x%x\n",
+	p.version, p.headerlen, p.len);
+
+	printf("\tttl: 0%x (%d)\tproto 0%x (%s)\tsum: 0x%x\n",
+	p.ttl, p.ttl, p.proto, pktTypeToStr(p.proto), p.sum);
+
+	printf("\tsrcip: 0x%x\tdstip: 0x%x\n", p.srcip, p.dstip);
+}
+
+Parser pktParser = {
+	.parse = parsePkt,
+	.print = printPkt,
+};
\ No newline at end of file
--- /dev/null
+++ b/tcp.c
@@ -1,0 +1,59 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <pcap.h>
+#include "common.h"
+
+int
+parseTcp(const u_char *pkt, Tcp *tcp)
+{
+	int pos = 0;
+	
+	tcp->srcport = get2(pkt + pos);
+	pos += TCP_SRCPORT;
+	
+	tcp->dstport = get2(pkt + pos);
+	pos += TCP_DSTPORT;
+
+	tcp->seqnum = get4(pkt + pos);
+	pos += TCP_SEQNUM;
+	
+	tcp->acknum = get4(pkt + pos);
+	pos += TCP_ACKNUM;
+	
+	/* offsets are multiplies of 4 (32-bit) values */
+	tcp->offset = (pkt[pos] >> 4) * 4;
+	pos += TCP_OFFSET;
+	
+	tcp->flags = pkt[pos];
+	pos += TCP_FLAGS;
+	
+	tcp->winsize = get2(pkt + pos);
+	pos += TCP_WINSIZE;
+	
+	tcp->sum = pkt[pos];
+	pos += TCP_SUM;
+	
+	tcp->urgentptr = get2(pkt + pos);
+	pos += TCP_URGPTR;
+	return 1;
+}
+
+void
+printTcp(Tcp tcp)
+{
+		printf("tcp pkt:\n"
+		"\tsrcport: %d\tdstport: %d\n"
+		"\tseqnum: %d\tacknum: %d\n"
+		"\toffset: %d\tflags: %b (%x)\n"
+		"\twinsize: %d (%x)\tsum: %d\n",
+		
+		tcp.srcport, tcp.dstport,
+		tcp.seqnum, tcp.acknum,
+		tcp.offset, tcp.flags, tcp.flags,
+		tcp.winsize, tcp.winsize, tcp.sum);
+}
+
+Parser tcpParser = {
+	.parse = parseTcp,
+	.print = printTcp,
+};
\ No newline at end of file
--- /dev/null
+++ b/udp.c
@@ -1,0 +1,38 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <pcap.h>
+#include "common.h"
+
+int
+parseUdp(const u_char *pkt, Udp *udp)
+{
+	int pos = 0;
+	
+	udp->srcport = get2(pkt + pos);
+	pos += UDP_SRCPORT;
+	
+	udp->dstport = get2(pkt + pos);
+	pos += UDP_DSTPORT;
+
+	udp->len = get2(pkt + pos);
+	pos += UDP_LEN;
+	
+	udp->sum = get2(pkt + pos);
+	pos += UDP_SUM;
+	
+	return 1;
+}
+
+void
+printUdp(Udp udp)
+{
+		printf("udp pkt:\n"
+		"\tsrcport: %d\tdstport: %d\n"
+		"\tlen: %d\tsum 0x%x\n",
+		udp.srcport, udp.dstport, udp.len, udp.sum);
+}
+
+Parser udpParser = {
+	.parse = parseUdp,
+	.print = printDns,
+};
\ No newline at end of file