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