wm: dnsparser

Download patch

ref: 16d016b87e7783cecedb1078c1327fa1244da4d7
parent: 1766db24dfb733bd1f574bf0882527356f177397
author: mkf <mkf@cloud9p.org>
date: Sat Nov 16 09:57:36 EST 2024

very little changes

--- a/common.c
+++ b/common.c
@@ -2,7 +2,11 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 
+ulong pos;
+ulong pktlen;
+
 void
 err(int fatal, char *fmt, ...)
 {
@@ -33,4 +37,77 @@
 get4(const u_char *octet)
 {
 	return get2(octet) << 8 * 2 | get2(octet + 2);
-}
\ No newline at end of file
+}
+
+void*
+emalloc(ulong len)
+{
+	void *m;
+	
+	m = malloc(len);
+	
+	if(m == NULL)
+		err(1, "emalloc(%d): malloc failed, unable to allocate memory", len);
+		
+	return m;
+}
+
+void*
+ecalloc(ulong len, ulong size)
+{
+	void *m;
+	
+	m = calloc(len, size);
+	
+	if(m == NULL)
+		err(1, "ecalloc(%d, %d): calloc failed, unable to allocate memory", len, size);
+		
+	return m;
+}
+
+void*
+memdup(const void *src, ulong len)
+{
+	void *dst;
+	
+	dst = emalloc(len);
+	memmove(dst, src, len);
+	
+	return dst;
+}
+
+void
+get(const u_char *pkt, long size, ...)
+{
+	uint8_t *u8;
+	uint16_t *u16;
+	uint32_t *u32;
+	
+	va_list args;
+	va_start(args, size);
+	
+	switch(size)
+	{
+		case 1:
+			u8 = va_arg(args, u_char*);
+			*u8 = pkt[pos];
+			break;
+		case 2:
+			u16 = va_arg(args, uint16_t*);
+			*u16 = get2(pkt + pos);
+			break;
+		case 3:
+			u32 = va_arg(args, uint32_t*);
+			*u32 = get4(pkt + pos) >> 8;
+			// *u32 &= 0x00ffffff;
+			break;
+		case 4:
+			u32 = va_arg(args, uint32_t*);
+			*u32 = get4(pkt + pos);
+			break;
+		default:
+			err(1, "get(%p, %ld, ...): unsupported size", pkt, size);
+	}
+	pos += size;
+	va_end(args);
+}
--- a/common.h
+++ b/common.h
@@ -1,150 +1,6 @@
-#define debug 0
+#include <openssl/x509v3.h>
+#include <pcap.h>
 
-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 = 1,
-	PKT_DSFIELD = 1,
-	PKT_LEN = 2,
-	PKT_ID = 2,
-	// PKT_FLAGS = 1, /* 3 bits */
-	PKT_FRAGOFFSET = 2, /* 12 bits */
-	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 = 4,
-	TLS_RECORD_CONTENTTYPE = 1,
-	TLS_RECORD_VERSION = 1,
-	TLS_RECORD_LEN = 2,
-	
-	/* tls record versions */
-	TLS_RECORD_10 = 0x301,
-	TLS_RECORD_11 = 0x302,
-	TLS_RECORD_12 = 0x303,
-	TLS_RECORD_13 = 0x304,
-	
-	/* 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
@@ -154,22 +10,49 @@
 	char *name;
 	int (*parse)();
 	void (*print)();
+	void (*free)();
 }Parser;
 
 extern pcap_t *handle;
-extern struct bpf_program dnsfilter;
+extern struct bpf_program filter;
+extern int debug;
 
 /* common.c */
+extern unsigned long pos;
+extern const u_char *pkt;
+extern ulong pktlen;
+#define PKTHEAD pkt + pos
+
 uint16_t get2(const u_char *octet);
 uint32_t get4(const u_char *octet);
+void get(const u_char *pkt, int size, ...);
+
 void err(int fatal, char *fmt, ...);
+void *emalloc(ulong size);
+void *memdup(const void *src, ulong len);
 
 /* ether.c */
+enum
+{
+	ETHER_LEN = 14,
+	ETHER_ADDR_LEN = 6,
+
+	/* sizes of each field in header */
+	ETHER_DST = ETHER_ADDR_LEN,
+	ETHER_SRC = ETHER_ADDR_LEN,
+	ETHER_TYPE = 2,
+
+	/* ether types */
+	ETHER_IP4 = 0x800,
+	ETHER_IP6 = 0x86dd,
+};
+
 typedef struct
 {
+	uint32_t start;
 	uint8_t dst[ETHER_ADDR_LEN];
 	uint8_t src[ETHER_ADDR_LEN];
-	int type;
+	uint16_t type;
 }Ether;
 
 char* etherTypeToStr(uint16_t frame);
@@ -179,8 +62,29 @@
 extern Parser etherParser;
 
 /* (ipv4) pkt.c */
+enum
+{
+	PKT_VHL = 1,
+	PKT_DSFIELD = 1,
+	PKT_LEN = 2,
+	PKT_ID = 2,
+	// PKT_FLAGS = 1, /* 3 bits */
+	PKT_FRAGOFFSET = 2, /* 12 bits */
+	PKT_TTL = 1,
+	PKT_PROTO = 1,
+	PKT_SUM = 2,
+	PKT_SRC = 4,
+	PKT_DST = 4,
+	
+	/* packet types */
+	PKT_TCP = 6,
+	PKT_UDP = 17,
+};
+
 typedef struct
 {
+	uint32_t start;
+	
 	uint8_t version;
 	uint8_t headerlen;
 	uint8_t dsfield;
@@ -206,11 +110,24 @@
 extern Parser pktParser;
 
 /* udp.c */
-typedef struct
+enum
 {
-	uint16_t srcport;
-	uint16_t dstport;
+	/* udp stuff */
+	UDP_SIZE = 8,
+	
+	UDP_SRCPORT = 2,
+	UDP_DSTPORT = 2,
+	UDP_LEN = 2,
+	UDP_SUM = 2,
+};
 
+typedef struct
+{
+	uint32_t start;
+	
+	uint16_t src;
+	uint16_t dst;
+	
 	uint16_t len;
 	uint16_t sum;
 }Udp;
@@ -221,13 +138,36 @@
 extern Parser udpParser;
 
 /* tcp.c */
+enum
+{
+	/* tcp sizes */
+	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,
+};
+
 typedef struct
 {
-	uint16_t srcport;
-	uint16_t dstport;
+	uint32_t start;
+	
+	uint16_t src;
+	uint16_t dst;
 
-	uint32_t seqnum;
-	uint32_t acknum;
+	uint32_t seq;
+	uint32_t ack;
 	
 	uint16_t offset;
 	uint16_t flags;
@@ -248,8 +188,57 @@
  * dns.c
  * a maximum size of 255 for strings is assumed
  */
+enum
+{
+	/* 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,
+	
+	/* dns types */
+	DNS_TYPE_A = 1,
+	DNS_TYPE_CNAME = 5,
+	DNS_TYPE_SOA = 6,
+	DNS_TYPE_MX = 15,
+	DNS_TYPE_TXT = 16,
+	DNS_TYPE_AAAA = 28,
+	
+	/* dns classes */
+	DNS_CLASS_IN = 1, /* lonely :( */
+	
+	DNS_MAX_LEN = 255,
+};
+
 typedef struct
 {
+	uint32_t start;
+	
 	/* is it response or request */
 	uint16_t id;
 	uint16_t flags;
@@ -260,10 +249,10 @@
 	uint16_t nAuthRR;
 	uint16_t nAddRR;
 	
-	char domain[255];
+	char domain[DNS_MAX_LEN+1];
 	
-	uint8_t type;
-	uint8_t class;
+	uint16_t type;
+	uint16_t class;
 	uint32_t ttl;
 	uint32_t len;
 	union
@@ -275,46 +264,259 @@
 		uint16_t ip6[8];
 
 		/* CNAME */
-		u_char cname[255];
+		u_char cname[DNS_MAX_LEN+1];
 	};
 }Dns;
 
-int parseDnsCname(const u_char *pkt, u_char cname[255], uint pos, uint len);
+int parseDnsName(const u_char *pkt, char *buf, u_char len);
+int parseDnsCname(const u_char *pkt, Dns *d, 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;
 
+/* der.c */
+enum
+{
+	/* der tags */
+	DER_TAG_INT = 0x2,
+	DER_TAG_BITSTR = 0x3,
+	DER_TAG_OCTSTR = 0x4,
+	DER_TAG_NULL = 0x5,
+	DER_TAG_OID = 0x6,
+	DER_TAG_UTF8STR = 0xc,
+	DER_TAG_SEQ = 0x10,
+	DER_TAG_SET = 0x11,
+	DER_TAG_PRINTSTR = 0x13,
+	DER_TAG_IA5STR = 0x16,
+	DER_TAG_UTCTIME = 0x17,
+	DER_TAG_GENERALTIME = 0x18,
+	DER_TAG_SEQOF = 0x30,
+	DER_TAG_SETOF = 0x31,
+	
+	/* der tag classes */
+	DER_CLASS_UNIVERSAL = 0,
+	DER_CLASS_APPLICATION = 1,
+	DER_CLASS_CONTEXT = 2,
+	DER_CLASS_PRIVATE = 3,
+	
+	DER_CN_MAX = 1024,
+};
+
+typedef struct
+{
+	uint32_t start;
+	
+	uint64_t len; /* of cert */
+
+	X509 *cert;
+	char *subject;
+	char *issuer;
+	
+	char *commonName[DER_CN_MAX];
+	uint16_t nCommonName;
+	
+	uint8_t selfsigned;
+}Der;
+
+int parseDer(const u_char *pkt, Der *der);
+
+void printDer(Der der);
+
+extern Parser derParser;
+
 /* tls.c */
+enum
+{
+	/* tls record */
+	TLS_RECORD = 5,
+	TLS_RECORD_CONTENTTYPE = 1,
+	TLS_RECORD_VERSION = 2,
+	TLS_RECORD_LEN = 2,
+	
+	/* tls record versions */
+	SSL_30 = 0x300,
+	TLS_10 = 0x301,
+	TLS_11 = 0x302,
+	TLS_12 = 0x303,
+	TLS_13 = 0x304,
+	
+	/* tls 1.2 (client) handshake */
+	TLS_HANDSHAKE_HEADER = 4,
+	TLS_HANDSHAKE_TYPE = 1,
+	TLS_HANDSHAKE_LEN = 3,
+	TLS_HANDSHAKE_VERSION = 2,
+	TLS_HANDSHAKE_RANDOM = 32,
+	TLS_HANDSHAKE_SESSIONID_LEN = 1,
+	/* TLS_HANDSHAKE_SESSIONID = ??, */
+	TLS_HANDSHAKE_CIPHERS_LEN = 2,
+	/* TLS_HANDSHAKE_CIPHERS = ?? , */
+	TLS_HANDSHAKE_CIPHER = 2,
+	TLS_HANDSHAKE_COMP_LEN = 1,
+	TLS_HANDSHAKE_COMP = 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 */
+	TLS_HANDSHAKE_CERTS_LEN = 3,
+	TLS_HANDSHAKE_CERT_LEN = 3,
+	
+	/* tls 1.2 (server) handshake */
+	TLS_HANDSHAKE_COMPS = 1,
+	
+	/* tls SNI */
+	TLS_SNI_LISTLEN = 2,
+	TLS_SNI_TYPE = 1,
+	TLS_SNI_LEN = 2,
+	
+	/* tls supported versions */
+	TLS_SV_LEN = 1,
+	TLS_SV_DATA = 2,
+	
+	/* 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_SERVER_KEY_EXCH = 12,
+	TLS_SERVER_HELLO_DONE = 14,
+	TLS_CERT_REQ = 13,
+	TLS_CLIENT_KEY_EXCH = 16,
+	TLS_FINISHED = 20,
+	TLS_CERT_STATUS = 22,
+	
+	/* tls content types */
+	TLS_CTYPE_ALERT = 21,
+	TLS_CTYPE_HANDSHAKE = 22,
+	TLS_CTYPE_APPLICATION_DATA = 23,
+	TLS_CTYPE_HEARTBEAT = 24,
+	TLS_CTYPE_CID = 25, /* ? */
+	TLS_CTYPE_ACK = 26,
+	TLS_CTYPE_RTC = 27, /* ? */
+	
+	/* tls extensions */
+	TLS_EXT_SNI = 0,
+	TLS_EXT_PADDING = 21,
+	TLS_EXT_SUPPORTED_VERS = 43,
+};
+
 typedef struct
 {
+	uint32_t start;
+	
+	char *name;
 	uint8_t len;
-	uint8_t data[];
+	uint8_t *data;
 }TlsTuple;
 
+/* supported versions */
 typedef struct
 {
+	uint8_t len;
+	uint16_t *vers;
+}TlsExtensionSv;
+		
+/* server name */
+typedef struct
+{
+	uint16_t listLen;
 	uint8_t type;
+	uint16_t len;
+			
+	char *name;
+}TlsExtensionSni;
+
+typedef struct
+{
+	uint32_t start;
+	
+	uint16_t type;
+	uint16_t len;
+
+	union
+	{
+		TlsExtensionSv *sv;
+		TlsExtensionSni *sni;
+		u_char *data;
+	};
+}TlsExtension;
+
+typedef struct
+{
+	uint32_t start;
 	uint32_t len;
+	Der *der;
+}TlsCert;
+
+typedef struct
+{
+	uint32_t start;
+	
+	uint8_t type;
+	uint32_t len;
 	uint16_t version;
 	
-	uint8_t random[32];
+	uint8_t random[TLS_HANDSHAKE_RANDOM];
 	
-	TlsTuple sessionId;
-	TlsTuple cipherSuits;
-	TlsTuple compressionMethods;
-	TlsTuple extensions;
+	TlsTuple *sessionId;
+	union
+	{
+		/* client hello */
+		struct
+		{
+			TlsTuple *cipherSuits;
+			TlsTuple *compressionMethods;
+		};
+		
+		/* server hello */
+		struct
+		{
+			uint16_t cipherSuit;
+			uint8_t compressionMethod;
+		};
+		
+		/* cert */
+		struct
+		{
+			uint32_t certsLen;
+			uint32_t nCerts;
+			TlsCert *certs;
+		};
+	};
+	
+	uint16_t extensionsLen; /* length of extentions in bytes */
+	uint16_t nExtensions; /* number of actual extentions */
+	TlsExtension *extensions;
 }TlsHandshake;
 
 typedef struct
 {
-	uint8_t contenttype;
-	uint16_t rversion; /* record version */
+	uint32_t start;
+	
+	uint8_t type;
+	uint16_t version; /* record version */
 	uint16_t len;
 	
-	TlsHandshake handshake;
+	uint8_t nHandshakes;
+	TlsHandshake *handshakes;
 }Tls;
 
-extern Parser tlsParser;
+int parseTlsTuple(const u_char *pkt, TlsTuple *tuple);
+int parseTlsRecord(const u_char *pkt, Tls *tls);
+int parseTlsExtensions(const u_char *pkt, TlsHandshake *hs);
+int parseTlsHandshake(const u_char *pkt, TlsHandshake *hs);
+int parseTls(const u_char *pkt, Tls *tls);
 
+void printTlsTuple(TlsTuple tuple);
+void printTlsHandshake(TlsHandshake hs);
+void printTlsRecord(Tls tls);
+void printTls(Tls tls);
+void printTlsExtension(TlsExtension e);
+void printTlsExtensions(TlsHandshake hs);
+void freeTls(Tls *tls);
+
+extern Parser tlsParser;
--- a/dns.c
+++ b/dns.c
@@ -1,8 +1,3 @@
-/*
- * notes:
- * we dont parse compressed names very well.
- */
-
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
@@ -9,32 +4,68 @@
 #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)
+parseDnsName(const u_char *pkt, char *buf, u_char len)
 {
-	int section_header, cname_head = 0;
+	int section_header, i;
+	
+	memset(buf, '\0', len);
+	
+	/* skip first len byte, we can't replace it with '.' */
+	strncpy(buf, pkt+1, len);
+	for(i = 0 ; i < len ; i++)
+	{
+		section_header = pkt[i];
+		
+		if(section_header == 0x0 || section_header == 0xc0)
+			break;
+		else
+		{
+				i += section_header;
+				buf[i] = '.';
+		}
+	}
+	
+	buf[len] = '\0';
+	return 1;
+}
+
+/* len must be dns.len */
+int
+parseDnsCname(const u_char *pkt, Dns *d, uint len)
+{
+	int section_header;
 	const u_char *pkt_head;
+	u_char next_header, *cname_head, namebuf[DNS_MAX_LEN];
 	
 	pkt_head = pkt + pos;
+	cname_head = d->cname;
 	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)
+				
+		/* compressed */
+		if(section_header == 0xc0)
+		{
+			next_header = pkt_head[i + 1];
+			parseDnsName(pkt + d->start + next_header, namebuf, DNS_MAX_LEN);
+			cname_head = strchr(cname_head, '\0');
+			*cname_head++ = '.';
+			strncpy(cname_head, namebuf, DNS_MAX_LEN - (cname_head - d->cname));
 			break;
-		
-		/* not compressed, regular size */
-		strncpy(cname + cname_head, pkt_head + i + 1, section_header);
-		
+		}
+		else if(section_header == 0x0)
+			break;
+		else
+		{
+			parseDnsName(pkt_head + i, namebuf, section_header);
+			cname_head = strchr(cname_head, '\0');
+			*cname_head++ = '.';
+			strncpy(cname_head, namebuf, section_header);
+		}
 		i += section_header;
-		cname_head += section_header;
-		cname[cname_head++] = '.';
 	}
+	
 	return 1;
 }
 
@@ -45,65 +76,36 @@
 int
 parseDns(const u_char *pkt, Dns *dns)
 {
-	int section_header;
-	int pos = 0;
-	int name_head = 0;
+	dns->start = pos;
+	get(pkt, DNS_ID, &dns->id);
+	get(pkt, DNS_FLAGS, &dns->flags);
 	
-	dns->id = get2(pkt + pos);
-	pos += DNS_ID;
+	get(pkt, DNS_COUNT_QUERIES, &dns->nQueries);
+	get(pkt, DNS_COUNT_ANSWERS, &dns->nAnswers);
+	get(pkt, DNS_COUNT_AUTH_RR, &dns->nAuthRR);
+	get(pkt, DNS_COUNT_ADD_RR, &dns->nAddRR);
 	
-	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++;
+	parseDnsName(PKTHEAD, dns->domain, DNS_MAX_LEN);
+	/* first byte isn't counted. */
+	pos += strnlen(dns->domain, DNS_MAX_LEN) + 1;
+	get(pkt, DNS_TYPE, &dns->type);
+	get(pkt, DNS_CLASS, &dns->class);
 		
-		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 */
+		get(pkt, DNS_TYPE, &dns->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;
+		get(pkt, DNS_TTL, &dns->ttl);
+		get(pkt, DNS_LEN, &dns->len);
 	}
 	else
 		return 1;
-
+	
 	switch(dns->type)
 	{
 		case DNS_TYPE_A:
@@ -111,33 +113,26 @@
 			dns->ip[1] = pkt[pos++];
 			dns->ip[2] = pkt[pos++];
 			dns->ip[3] = pkt[pos++];
-			break;
+			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;			
+			get(pkt, 2, dns->ip6+0);
+			get(pkt, 2, dns->ip6+1);
+			get(pkt, 2, dns->ip6+2);
+			get(pkt, 2, dns->ip6+3);
+			get(pkt, 2, dns->ip6+4);
+			get(pkt, 2, dns->ip6+5);
+			get(pkt, 2, dns->ip6+6);
+			get(pkt, 2, dns->ip6+7);
 			break;
+		case DNS_TYPE_SOA:	
 		case DNS_TYPE_CNAME:
-			memset(dns->cname, '\0', sizeof(dns->domain));
-			parseDnsCname(pkt, dns->cname, pos, dns->len);
+			memset(dns->cname, '\0', DNS_MAX_LEN);
+			parseDnsCname(pkt, dns, dns->len);
 			break;
 		case DNS_TYPE_MX:
 			break;
 		default:
-			err(1, "parseDnsQuery(%d) unknown type", dns->type);
+			err(1, "parseDns(): unknown type: %d", dns->type);
 	}
 	return 1;
 }
@@ -148,7 +143,7 @@
 	printf("dns query:\n"
 	"\tid: %d\tflags: %b (%x)\n"
 	"\tnQueries: %d\tnAnswers: %d\tnAuthRR: %d\tnAddRR: %d\n"
-	"\tdomain: %s (%p)\n"
+	"\tdomain: %s (%p)\n\n"
 	"\ttype: %d (%s)\tclass: %s\n"
 	"\tttl: %x (%d)\tlen: %x (%d)\n",
 	
@@ -174,6 +169,9 @@
 		case DNS_TYPE_CNAME:
 			printf("\tcname: %s\n", dns.cname);
 			break;
+		case DNS_TYPE_SOA:	
+			printf("\tsoa: %s\n", dns.cname);
+			break;	
 		case DNS_TYPE_MX:
 			break;
 		default:
@@ -204,6 +202,8 @@
 			return "A";
 		case DNS_TYPE_CNAME:
 			return "CNAME";
+		case DNS_TYPE_SOA:
+			return "SOA";
 		case DNS_TYPE_TXT:
 			return "TXT";
 		case DNS_TYPE_AAAA:
--- a/dnsparser.c
+++ b/dnsparser.c
@@ -12,13 +12,12 @@
 
 struct bpf_program dnsfilter;
 char errbuf[PCAP_ERRBUF_SIZE];
+int debug;
 
-/* magic happens here! */
 void
-dns_reader(u_char *args, const struct pcap_pkthdr *header, const u_char *pkt)
+dnsReader(u_char *args, const struct pcap_pkthdr *header, const u_char *pkt)
 {
 	static int packets = 1;
-	int head = 0;
 	Ether e;
 	Pkt p;
 	Udp udp;
@@ -25,37 +24,31 @@
 	Tcp tcp;
 	Dns dns;
 
-	printf("\n==================%3d  ==================\n", packets++);
+	pos = 0;
 	
-	parseEther(pkt + head, &e);
-	head += ETHER_LEN;
-	
-	
-	parsePkt(pkt + head, &p);
-	head += p.headerlen;
+	parseEther(pkt, &e);
+	parsePkt(pkt, &p);
 
 	if(p.proto == IPPROTO_UDP)
 	{
-		parseUdp(pkt + head, &udp);
-		head += UDP_SIZE;
+		parseUdp(pkt, &udp);
 	}
 	else if(p.proto == IPPROTO_TCP)
 	{
-		parseTcp(pkt + head, &tcp);
+		parseTcp(pkt, &tcp);
 
 		/* reduce the noise */
 		if(tcp.flags & (TCP_FLAG_FIN|TCP_FLAG_SYN|TCP_FLAG_ACK) &&
 		!(tcp.flags & TCP_FLAG_PSH))
 		{
-			printf("skipped noise\n");
+		//	printf("skipped noise\n");
 			return;
 		}
 
-		head += tcp.offset;
-		head += 2; /* there is a dns-over-tcp len field we ignore */
+		pos += 2; /* there is a dns-over-tcp len field we ignore */
 	}
 	else
-		err(1, "dns_reader(): unknown proto: %d", p.proto);
+		err(1, "dnsReader(): unknown proto: %#x (%d)", p.proto);
 	
 	if(debug)
 	{
@@ -66,7 +59,9 @@
 		fprintf(stderr, "\n");
 	}
 
-	parseDns(pkt + head, &dns);
+	parseDns(pkt, &dns);
+	
+	printf("\n==================%3d  ==================\n", packets++);
 
 	printf("frame info:\n"
 	"\tlen: %d\tcaplen: %d\n"
@@ -81,7 +76,7 @@
 		printUdp(udp);
 	else if(p.proto == IPPROTO_TCP)
 		printTcp(tcp);
-	
+
 	printDns(dns);
 }
 
@@ -106,7 +101,7 @@
 		err(1, "%s: failed to install filter: %s\n", argv[0], pcap_geterr(handle));
 
 
-	pcap_loop(handle, -1, dns_reader, NULL);
+	pcap_loop(handle, -1, dnsReader, NULL);
 
 	pcap_freecode(&dnsfilter);
 	pcap_close(handle);
--- a/ether.c
+++ b/ether.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <stdint.h>
-#include <pcap/pcap.h>
+#include <pcap.h>
 #include "common.h"
 
 char*
@@ -21,7 +21,7 @@
 int
 parseEther(const u_char *pkt, Ether *e)
 {
-	int pos = 0;
+	e->start = pos;
 	
 	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
 		e->dst[i] = pkt[i];
@@ -32,8 +32,8 @@
 		e->src[i] = pkt[i+ETHER_ADDR_LEN];
 
 	pos += ETHER_SRC;
-	e->type = get2(pkt + pos);
-	
+
+	get(pkt, ETHER_TYPE, &e->type);
 	return 1;
 }
 
@@ -40,7 +40,7 @@
 void
 printEther(Ether e)
 {
-	printf("ether info:\n\tdst:");
+	printf("ether info:\n\tdst: ");
 	for(int i = 0 ; i < ETHER_ADDR_LEN ; i++)
 		printf("%x:", e.dst[i]);
 
--- a/pkt.c
+++ b/pkt.c
@@ -24,42 +24,31 @@
 int
 parsePkt(const u_char *pkt, Pkt *p)
 {
-	int pos = 0;
+	p->start = pos;
+	
+	/* they'r both half a byte */
 	p->version = IP4_V(pkt[pos]);
 	p->headerlen = IP4_HL(pkt[pos]) * 4;
 	pos += PKT_VHL;
 
-	p->dsfield = pkt[pos];
-	pos += PKT_DSFIELD;
+	get(pkt, PKT_DSFIELD, &p->dsfield);
+	get(pkt, PKT_LEN, &p->len);
+	get(pkt, PKT_ID, &p->id);
 	
-	p->len = get2(pkt + pos);
-	pos += PKT_LEN;
-	
-	p->id = get2(pkt + pos);
-	pos += PKT_ID;
-	
-	p->flags = pkt[pos];
 	/* flags are just 3 bits, smaller than a byte */
-	
+	p->flags = pkt[pos];
+
+	/* this one is 12 bits */
 	p->fragoffset = get2(pkt + pos);
 	p->fragoffset &= 0x1FFF;
 	pos += PKT_FRAGOFFSET;
 	
-	p->ttl = pkt[pos];
-	pos += PKT_TTL;
+	get(pkt, PKT_TTL, &p->ttl);
+	get(pkt, PKT_PROTO, &p->proto);
+	get(pkt, PKT_SUM, &p->sum);
+	get(pkt, PKT_SRC, &p->srcip);
+	get(pkt, PKT_SRC, &p->dstip);
 	
-	p->proto = pkt[pos];
-	pos += PKT_PROTO;
-	
-	p->sum = get2(pkt + pos);
-	pos += PKT_SUM;
-
-	p->srcip = get4(pkt + pos);
-	pos += PKT_SRC;
-
-	p->dstip = get4(pkt + pos);
-	pos += PKT_DST;
-
 	return 1;
 }
 
@@ -67,15 +56,19 @@
 printPkt(Pkt p)
 {
 	printf("ip packet info:\n"
-	"\tversion: 0x%x\theaderlen: 0x%x\tdsfield: %b\n",
+	"\tversion: %#x\theaderlen: %#x\tdsfield: %b\n",
 	p.version, p.headerlen, p.dsfield);
 
-	printf("\tlen: %d (%x)\tid: 0x%x (%d)\n",
+	printf("\tlen: %d (%#x)\tid: %#x (%d)\n",
 	p.len, p.len, p.id, p.id);
-	printf("\tttl: 0%x (%d)\tproto 0%x (%s)\tsum: 0x%x\n",
+	
+	printf("\tflags: %b\tfragment offset: %b\n",
+	p.flags, p.fragoffset);
+	
+	printf("\tttl: %#x (%d)\tproto %#x (%s)\tsum: %#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);
+	
+	printf("\tsrcip: %#x\tdstip: %#x\n", p.srcip, p.dstip);
 }
 
 Parser pktParser = {
--- a/tcp.c
+++ b/tcp.c
@@ -1,40 +1,40 @@
 #include <stdio.h>
 #include <stdint.h>
-#include <pcap.h>
 #include "common.h"
 
 int
 parseTcp(const u_char *pkt, Tcp *tcp)
 {
-	int pos = 0;
+	tcp->start = pos;
 	
-	tcp->srcport = get2(pkt + pos);
-	pos += TCP_SRCPORT;
+	get(pkt, TCP_SRCPORT, &tcp->src);
+	get(pkt, TCP_DSTPORT, &tcp->dst);
+	get(pkt, TCP_SEQNUM, &tcp->seq);
+	get(pkt, TCP_ACKNUM, &tcp->ack);
 	
-	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;
+	get(pkt, TCP_OFFSET, &tcp->offset);
+	/* some(?) compilers may do logical shift */
+	tcp->offset = (tcp->offset >> 4) & 0xf;
+	tcp->offset *= 4;
 	
-	tcp->flags = pkt[pos];
-	pos += TCP_FLAGS;
+	get(pkt, TCP_FLAGS, &tcp->flags);
+	get(pkt, TCP_WINSIZE, &tcp->winsize);
+	get(pkt, TCP_SUM, &tcp->sum);
+	get(pkt, TCP_URGPTR, &tcp->urgentptr);
 	
-	tcp->winsize = get2(pkt + pos);
-	pos += TCP_WINSIZE;
-	
-	tcp->sum = pkt[pos];
-	pos += TCP_SUM;
-	
-	tcp->urgentptr = get2(pkt + pos);
-	pos += TCP_URGPTR;
+	/*
+	 * we dont parse tcp options yet, 
+	 * offset alone shows size of tcp packet (options + headers)
+	 * there is no need to add length of headers to pos twice.
+	 *
+	 * x--------x------------------------x------------x
+	 * ^ pkt[0] ^ pkt[tcp.start]         ^ pkt[pos]   ^ pkt[tcp.offset]
+	 *
+	 * tcp.start < pos ≤ tcp.offset
+	 */
+	 
+	pos += tcp->offset - (pos - tcp->start);
 	return 1;
 }
 
@@ -42,13 +42,13 @@
 printTcp(Tcp tcp)
 {
 		printf("tcp pkt:\n"
-		"\tsrcport: %d\tdstport: %d\n"
-		"\tseqnum: %d\tacknum: %d\n"
+		"\tsrc port: %d\tdst port: %d\n"
+		"\tseq num: %u\tack num: %u\n"
 		"\toffset: %d\tflags: %b (%x)\n"
 		"\twinsize: %d (%x)\tsum: %d\n",
 		
-		tcp.srcport, tcp.dstport,
-		tcp.seqnum, tcp.acknum,
+		tcp.src, tcp.dst,
+		tcp.seq, tcp.ack,
 		tcp.offset, tcp.flags, tcp.flags,
 		tcp.winsize, tcp.winsize, tcp.sum);
 }
--- a/tls.c
+++ b/tls.c
@@ -1,57 +1,580 @@
 #include <stdio.h>
 #include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
 #include <pcap.h>
 #include "common.h"
 
 int
-parseTlsRecord(const u_char *pkt, Tls tls)
+parseTlsRecord(const u_char *pkt, Tls *tls)
 {
-	int pos = 0;
+	get(pkt, TLS_RECORD_CONTENTTYPE, &tls->type);
+	get(pkt, TLS_RECORD_VERSION, &tls->version);
+	get(pkt, TLS_RECORD_LEN, &tls->len);
+	return 1;
+}
+
+int
+parseTlsClientHello(const u_char *pkt, TlsHandshake *hs)
+{
+	get(pkt, TLS_HANDSHAKE_VERSION, &hs->version);
+	memmove(hs->random, PKTHEAD, TLS_HANDSHAKE_RANDOM);
+	pos += TLS_HANDSHAKE_RANDOM;
 	
-	tls.contenttype = pkt[pos];
-	pos += TLS_RECORD_CONTENTTYPE;
+	hs->sessionId = emalloc(sizeof(TlsTuple));
+	hs->sessionId->name = "session id";
+	hs->sessionId->start = pos;
+	get(pkt, TLS_HANDSHAKE_SESSIONID_LEN, &hs->sessionId->len);
+	hs->sessionId->data = memdup(PKTHEAD, hs->sessionId->len);
+	pos += hs->sessionId->len;
 	
-	tls.rversion = pkt[pos];
-	pos += TLS_RECORD_VERSION;
+	hs->cipherSuits = emalloc(sizeof(TlsTuple));
+	hs->cipherSuits->name = "cipher suits";
+	get(pkt, TLS_HANDSHAKE_CIPHERS_LEN, &hs->cipherSuits->len);
+	hs->cipherSuits->data = memdup(PKTHEAD, hs->cipherSuits->len);
+	pos += hs->cipherSuits->len;
 	
-	tls.len = get2(pkt + TLS_RECORD_LEN);
-	pos += TLS_RECORD_LEN;
+	hs->compressionMethods = emalloc(sizeof(TlsTuple));
+	hs->compressionMethods->name = "compression methods";
+	get(pkt, TLS_HANDSHAKE_COMP_LEN, &hs->compressionMethods->len);
+	hs->compressionMethods->data = memdup(PKTHEAD, hs->compressionMethods->len);
+	pos += hs->compressionMethods->len;
 	
+	get(pkt, TLS_HANDSHAKE_EXTS_LEN, &hs->extensionsLen);
+	parseTlsExtensions(pkt, hs);
+	
 	return 1;
 }
 
 int
-parseTlsHandshake(const u_char *pkt, TlsHandshake hs)
+parseTlsServerHello(const u_char *pkt, TlsHandshake *hs)
 {
+	get(pkt, TLS_HANDSHAKE_VERSION, &hs->version);
+	memmove(hs->random, PKTHEAD, TLS_HANDSHAKE_RANDOM);
+	pos += TLS_HANDSHAKE_RANDOM;
 	
+	hs->sessionId = emalloc(sizeof(TlsTuple));
+	hs->sessionId->name = "session id";
+	hs->sessionId->start = pos;
+	get(pkt, TLS_HANDSHAKE_SESSIONID_LEN, &hs->sessionId->len);
+	hs->sessionId->data = memdup(PKTHEAD, hs->sessionId->len);
+	pos += hs->sessionId->len;
+	
+	get(pkt, TLS_HANDSHAKE_CIPHER, &hs->cipherSuit);
+	get(pkt, TLS_HANDSHAKE_COMP, &hs->compressionMethod);
+	
+	if(pos < hs->start + hs->len)
+	{
+		get(pkt, TLS_HANDSHAKE_EXTS_LEN, &hs->extensionsLen);
+		parseTlsExtensions(pkt, hs);
+	}
+	else
+	{
+		hs->extensionsLen = 0;
+		hs->nExtensions = 0;
+		pos = hs->start + hs->len;
+		pos += TLS_HANDSHAKE_TYPE + TLS_HANDSHAKE_LEN;
+	}
+	
+	return 1;
 }
 
 int
-parseTls(const u_char *pkt, Tls tls)
+parseTlsCert(const u_char *pkt, TlsCert *cert)
 {
-	int pos = 0;
+	cert->start = pos;
+	get(pkt, TLS_HANDSHAKE_CERT_LEN, &cert->len);
+
+	cert->der = emalloc(sizeof(Der));
+	cert->der->len = cert->len;
+	parseDer(pkt, cert->der);
+	return 1;	
+}
+
+int
+parseTlsCerts(const u_char *pkt, TlsHandshake *hs)
+{
+	get(pkt, TLS_HANDSHAKE_CERTS_LEN, &hs->certsLen);
 	
-	parseTlsRecord(pkt + pos, tls);
-	parseTlsHandshake(pkt + TLS_RECORD, tls.handshake);
+	hs->certs = emalloc(sizeof(TlsCert) * hs->certsLen);
+	hs->nCerts = 0;
+	for(int tmp = pos ; tmp < hs->certsLen + pos ; hs->nCerts++)
+	{
+		tmp += get4(pkt + tmp) >> 8;
+		tmp += TLS_HANDSHAKE_CERT_LEN;
+	}
+	
+	for(int i = 0 ; i < hs->nCerts ; i++)
+	{
+		parseTlsCert(pkt, hs->certs + i);
+	}
+	
+	return 1;
 }
 
+int
+parseExtensionData(const u_char *pkt, TlsExtension *e)
+{
+	switch(e->type)
+	{
+		case TLS_EXT_SNI:
+			e->sni = emalloc(sizeof(TlsExtensionSni));
+			get(pkt, TLS_SNI_LISTLEN, &e->sni->listLen);
+			get(pkt, TLS_SNI_TYPE, &e->sni->type);
+			get(pkt, TLS_SNI_LEN, &e->sni->len);
+			
+			e->sni->name = emalloc(e->sni->len);
+			strncpy(e->sni->name, PKTHEAD, e->sni->len);
+			pos += e->sni->len;
+			break;
+			
+		case TLS_EXT_SUPPORTED_VERS:
+			e->sv = emalloc(sizeof(TlsExtensionSv));
+			get(pkt, TLS_SV_LEN, &e->sv->len);
+			
+			e->sv->vers = emalloc(e->sv->len);
+			for(int i = 0 ; i < e->sv->len / 2 ; i++)
+			{
+				get(pkt, TLS_SV_DATA, &e->sv->vers[i]); 
+			}
+			break;
+			
+		default:
+			e->data = memdup(PKTHEAD, e->len);
+			pos += e->len;
+			break;
+	}
+
+	return 1;
+}
+
+int
+parseTlsExtensions(const u_char *pkt, TlsHandshake *hs)
+{
+	hs->nExtensions = 0;
+	
+	for(int tmp = pos ; tmp < hs->extensionsLen + pos ; hs->nExtensions++)
+	{
+		tmp += TLS_HANDSHAKE_EXT_TYPE;
+		tmp += get2(pkt + tmp);
+		tmp += TLS_HANDSHAKE_EXT_LEN;
+	}
+	
+	hs->extensions = emalloc(hs->nExtensions * sizeof(TlsExtension));
+	for(int i = 0 ; i < hs->nExtensions ; i++)
+	{
+		hs->extensions[i].start = pos;
+		get(pkt, TLS_HANDSHAKE_EXT_TYPE, &hs->extensions[i].type);
+		get(pkt, TLS_HANDSHAKE_EXT_LEN, &hs->extensions[i].len);
+		
+		if(hs->extensions[i].len > 0)
+		{
+			parseExtensionData(pkt, &hs->extensions[i]);
+		}
+	}
+	
+	return 1;
+}
+
+int
+parseTlsHandshake(const u_char *pkt, TlsHandshake *hs)
+{
+	hs->start = pos;
+	get(pkt, TLS_HANDSHAKE_TYPE, &hs->type);
+	
+	/* len is 3 bytes */
+	get(pkt, TLS_HANDSHAKE_LEN, &hs->len);
+	
+	switch(hs->type)
+	{
+		case TLS_CLIENT_HELLO:
+			parseTlsClientHello(pkt, hs);
+			break;
+		case TLS_SERVER_HELLO:
+			parseTlsServerHello(pkt, hs);
+			break;
+		case TLS_CERT:
+			parseTlsCerts(pkt, hs);
+			break;
+		case TLS_NEW_TICKET:
+		case TLS_CLIENT_KEY_EXCH:
+		case TLS_CERT_STATUS:
+		default:
+			pos += hs->len;
+	}
+	return 1;
+}
+
+int
+parseTls(const u_char *pkt, Tls *tls)
+{
+	tls->start = pos;
+	parseTlsRecord(pkt, tls);
+	
+	tls->nHandshakes = 0;
+	if(tls->type != TLS_CTYPE_HANDSHAKE || (pktlen < tls->len && pktlen))
+		return 0;
+	
+	/* count number of handshakes */
+	for(int tmp = pos ; tmp < tls->len + tls->start + TLS_RECORD ; tls->nHandshakes++)
+	{
+		tmp += TLS_HANDSHAKE_TYPE;
+		tmp += get4(pkt + tmp) >> 8;
+		tmp += TLS_HANDSHAKE_LEN;	
+	}
+	
+	tls->handshakes = emalloc(tls->nHandshakes * sizeof(TlsHandshake));
+	for(int i = 0 ; i < tls->nHandshakes ; i++)
+	{
+		parseTlsHandshake(pkt, tls->handshakes + i);
+	}
+	
+	return 1;
+}
+
+char*
+tlsVersionToStr(uint16_t ver)
+{
+	switch(ver)
+	{
+		case SSL_30:
+			return "SSL v3";
+		case TLS_10:
+			return "TLS v1.0";
+		case TLS_11:
+			return "TLS v1.1";
+		case TLS_12:
+			return "TLS v1.2";
+		case TLS_13:
+			return "TLS v1.3";
+		default:
+			return "Unknown";
+	}
+}
+
+char*
+tlsContentTypeToStr(uint8_t type)
+{
+	switch(type)
+	{
+		case TLS_CTYPE_ALERT:
+			return "Alert";
+		case TLS_CTYPE_HANDSHAKE:
+			return "Handshake";
+		case TLS_CTYPE_APPLICATION_DATA:
+			return "Application data";
+		case TLS_CTYPE_HEARTBEAT:
+			return "heart beat";
+		default:
+			return "Unkown";
+	}
+}
+
+char*
+tlsHandshakeTypeToStr(uint8_t type)
+{
+	switch(type)
+	{
+		case TLS_HELLO_REQ:
+			return "Hello Request";
+		case TLS_CLIENT_HELLO:
+			return "Client Hello ☺";
+		case TLS_SERVER_HELLO:
+			return "Server Hello ☺";
+		case TLS_NEW_TICKET:
+			return "New session ticket";
+		case TLS_CERT:
+			return "Certificate";
+		case TLS_SERVER_KEY_EXCH:
+			return "Server key exchange";
+		case TLS_SERVER_HELLO_DONE:
+			return "Server hello done";
+		case TLS_CLIENT_KEY_EXCH:
+			return "Client key exchange";
+		case TLS_CERT_STATUS:
+			return "OCSP";
+		default:
+			err(1, "tlsHandshakeTypeToStr(%d): unkown type", type);
+			return NULL;
+	}
+}
+
+char*
+tlsExtensionsTypeToStr(uint16_t type)
+{
+	switch(type)
+	{
+		case TLS_EXT_SNI:
+			return "SNI (Server name)";
+		case TLS_EXT_SUPPORTED_VERS:
+			return "Supported versions";
+		case TLS_EXT_PADDING:
+			return "Padding";
+		default:
+			return "Unkown";
+	}
+}
+
 void
-printTls(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",
+printTlsTuple(TlsTuple tuple)
+{
+		printf("\ttls tuple (%s):\n"
+		"\t\tlen: %d (%#x)\n",
+		tuple.name,
+		tuple.len, tuple.len);
 		
-		tcp.srcport, tcp.dstport,
-		tcp.seqnum, tcp.acknum,
-		tcp.offset, tcp.flags, tcp.flags,
-		tcp.winsize, tcp.winsize, tcp.sum);
-*/}
+		printf("\t\tdata: ");
+		for(int i = 0 ; i < tuple.len ; i++)
+			printf("%0x", tuple.data[i]);
+		
+		printf("\n");
+}
 
+void
+printTlsExtension(TlsExtension e)
+{
+	if(debug)
+	{
+		switch(e.type)
+		{
+			case TLS_EXT_SNI:
+				printf("list len: %d\ttype: %d\tlen: %d\tname: %s",
+				e.sni->listLen, e.sni->type, e.sni->len, e.sni->name);
+				
+				break;
+			case TLS_EXT_SUPPORTED_VERS:
+				printf("len: %d (%#x)\tdata: ", e.sv->len, e.sv->len);
+				for(int i = 0 ; i < e.sv->len / 2; i++)
+					printf("%#x ", e.sv->vers[i]);
+				break;
+			default:
+				printf("data: ");
+				for(int i = 0 ; i < e.len ; i++)
+					printf("%x", e.data[i]);
+				break;
+		}
+	}
+	else
+	{
+		switch(e.type)
+		{
+			case TLS_EXT_SNI:
+				printf("name: %s", e.sni->name);
+				break;
+			
+			case TLS_EXT_SUPPORTED_VERS:
+				for(int i = 0 ; i < e.sv->len / 2; i++)
+					printf("%s (%#x) ", tlsVersionToStr(e.sv->vers[i]), e.sv->vers[i]);
+				break;
+			default:
+				break;
+		}
+	}
+	printf("\n");
+}
+
+void
+printTlsExtensions(TlsHandshake hs)
+{
+	TlsExtension *e = hs.extensions;
+	
+	if(debug)
+	{
+		printf("\t\ttls extensions:\n"
+		"\t\tlen: %d\tnExtensions: %d (%#x)\n",
+		hs.extensionsLen, hs.nExtensions, hs.nExtensions);
+		
+		for(int i = 0 ; i < hs.nExtensions ; i++)
+		{
+			//if(strcmp("Unkown", tlsExtensionsTypeToStr(e->type)) && e->len > 0)
+			{
+				printf("\t\t\textension %i: start: %d (%#x)\n"
+				"\t\t\t\ttype: %d (%s)\tlen: %d (%#x)\n"
+				"\t\t\t\t",
+				
+				i, e->start, e->start,
+				e->type, tlsExtensionsTypeToStr(e->type), e->len, e->len);
+				
+				printTlsExtension(*e);
+			}
+			e++;	
+		}
+	}
+	else
+	{
+		printf("\t\ttls extensions:\tnExtensions: %d\n",
+		hs.nExtensions);
+		
+		for(int i = 0 ; i < hs.nExtensions ; i++)
+		{
+			if((e->type == TLS_EXT_SNI || e->type == TLS_EXT_SUPPORTED_VERS) && e->len > 0)
+			{
+				printf("\t\t\textension %i: type: %s\t",
+				i, tlsExtensionsTypeToStr(e->type));
+				
+				printTlsExtension(*e);
+			}
+			e++;	
+		}
+	}
+}
+
+void
+printTlsHandshake(TlsHandshake hs)
+{
+	if(debug)
+	{
+		printf("tls handshake:\n"
+		"\ttype: %s (%d)\tlen: %d (%#x)\tstart: %d (%#x)\n",
+		
+		tlsHandshakeTypeToStr(hs.type), hs.type, hs.len,  hs.len, hs.start, hs.start);		
+		switch(hs.type)
+		{
+			case TLS_CLIENT_HELLO:
+		
+				printf("\tversion: %#04x\n", hs.version);
+					
+				printTlsTuple(*(hs.sessionId));
+				
+				printf("\trandom: ");
+				for(int i = 0 ; i < TLS_HANDSHAKE_RANDOM ; i++)
+					printf("%x", hs.random[i]);
+					
+				printTlsTuple(*hs.cipherSuits);
+				printTlsTuple(*hs.compressionMethods);
+				printTlsExtensions(hs);
+				break;
+				
+			case TLS_SERVER_HELLO:
+				printf("\tversion: %#04x\n", hs.version);
+				
+				printTlsTuple(*(hs.sessionId));
+				
+				printf("\trandom: ");
+				for(int i = 0 ; i < TLS_HANDSHAKE_RANDOM ; i++)
+					printf("%x", hs.random[i]);
+			
+				printf("\tcipherSuit: %#x\tcompressionMethod: %#x\n",
+				hs.cipherSuit, hs.compressionMethod);
+				printTlsExtensions(hs);
+				break;
+			
+			case TLS_CERT:
+				printf("\tcertsLen: %d (%#x), nCerts: %d (%#x)\n",
+				hs.certsLen, hs.certsLen, hs.nCerts, hs.nCerts);
+				
+				printf("\tcerts:\n");
+				for(int i = 0 ; i < hs.nCerts ; i++)
+				{
+					printf("\t\t cert %d:\n", i);
+					printf("\t\t\tstart: %d (%#x)\t len: %d (%#x)\n",
+					hs.certs->start, hs.certs->start, hs.certs->len, hs.certs->len);
+					printDer(*hs.certs[i].der);
+				}
+				break;
+		default:
+				break;
+		}
+	}
+	else
+	{
+		printf("tls handshake:\ttype: %s\n",
+		tlsHandshakeTypeToStr(hs.type));
+		
+		switch(hs.type)
+		{
+			case TLS_CLIENT_HELLO:
+		
+				printf("\n\tversion: %s\n", tlsVersionToStr(hs.version));
+				printTlsExtensions(hs);
+				break;
+				
+			case TLS_SERVER_HELLO:
+				printf("\n\tversion: %s\n", tlsVersionToStr(hs.version));
+				printTlsExtensions(hs);
+				break;
+			
+			case TLS_CERT:
+				printf("\tnCerts: %d\n",
+				hs.nCerts);
+				
+				printf("\tcerts:\n");
+				for(int i = 0 ; i < hs.nCerts ; i++)
+				{
+					printf("\t\t***** cert %d:*****\n", i);
+					printDer(*hs.certs[i].der);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+void
+printTlsRecord(Tls tls)
+{
+	if(debug)
+	{
+		printf("tls record:\n"
+		"\ttype: %d\t\tversion: %#x\t"
+		"len: %d (%#x), nHandshakes: %d\n",
+		
+		tls.type, tls.version,
+		tls.len, tls.len, tls.nHandshakes);
+	}
+	else
+	{
+		printf("tls: content type: %s\tversion %s\n",
+		tlsContentTypeToStr(tls.type), tlsVersionToStr(tls.version));
+	}
+}
+
+void
+printTls(Tls tls)
+{
+
+	if(tls.type == TLS_CTYPE_HANDSHAKE)
+	{
+		printTlsRecord(tls);
+		for(int i = 0 ; i < tls.nHandshakes ; i++)
+		{
+			printTlsHandshake(tls.handshakes[i]);
+		}
+	}
+}
+
+/* keep this with sync with parsers */
+void
+freeTls(Tls *tls)
+{
+	TlsHandshake *hs;
+	TlsExtension *e;
+	
+	for(int i = 0 ; i < tls->nHandshakes ; i++)
+	{
+		hs = tls->handshakes + i;
+		for(int j = 0 ; j < hs->nExtensions ; j++)
+		{
+			e = hs->extensions + j;
+			switch(e->type)
+			{
+				case TLS_EXT_SNI:
+				case TLS_EXT_SUPPORTED_VERS:
+					break;
+				default:
+			//		free(e->data);
+			}
+		//	free(e);
+		}
+		free(hs);
+	}
+	/* do not free tls! */
+}
+
 Parser tlsParser = {
 	.name = "tls",
 	.parse = parseTls,
-	.print = printTcp,
+	.print = printTls,
+	.free = freeTls,
 };
\ No newline at end of file
--- a/udp.c
+++ b/udp.c
@@ -6,20 +6,13 @@
 int
 parseUdp(const u_char *pkt, Udp *udp)
 {
-	int pos = 0;
+	udp->start = pos;
 	
-	udp->srcport = get2(pkt + pos);
-	pos += UDP_SRCPORT;
+	get(pkt, UDP_SRCPORT, &udp->src);
+	get(pkt, UDP_DSTPORT, &udp->dst);
+	get(pkt, UDP_LEN, &udp->len);
+	get(pkt, UDP_SUM, &udp->sum);
 	
-	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;
 }
 
@@ -28,8 +21,8 @@
 {
 		printf("udp pkt:\n"
 		"\tsrcport: %d\tdstport: %d\n"
-		"\tlen: %d\tsum 0x%x\n",
-		udp.srcport, udp.dstport, udp.len, udp.sum);
+		"\tlen: %d\tsum 0x%#x\n",
+		udp.src, udp.dst, udp.len, udp.sum);
 }
 
 Parser udpParser = {