wm: dnsparser

ref: 03a44eb1a1da64f1269f21217abe3253cdf47b5a
dir: /dnsparser.c/

View raw version
/*
 * program to parse dns packets,
 * it assumes packets are not sent over qinq or vxlan or jumbo frames
 * or avian carriers
 */

#include <stdio.h>
#include <pcap.h>
#include <stdint.h>
#include <string.h>
#include "common.h"

struct bpf_program dnsfilter;
char errbuf[PCAP_ERRBUF_SIZE];

/* magic happens here! */
void
dns_reader(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;
	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;
	
	printEther(e);
	
	parsePkt(pkt + head, &p);
	printPkt(p);
	head += p.headerlen;

	if(p.proto == IPPROTO_UDP)
	{
		parseUdp(pkt + head, &udp);
		head += UDP_SIZE;
	}
	else if(p.proto == IPPROTO_TCP)
	{
		parseTcp(pkt + head, &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");
			return;
		}

		head += tcp.offset;
		head += 2; /* there is a dns-over-tcp len field we ignore */
	}
	else
		err(1, "dns_reader(): unknown proto: %d", p.proto);
	
	if(debug)
	{
		fprintf(stderr, "DEBUG: ");
		for(int i = 0 ; i < header->caplen ; i++)
			fprintf(stderr, "%d: 0x%x\t", i, pkt[i]);
		
		fprintf(stderr, "\n");
	}

	parseDns(pkt + head, &dns);

	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);
	
	printEther(e);
	printPkt(p);
	
	if(p.proto == IPPROTO_UDP)
		printUdp(udp);
	else if(p.proto == IPPROTO_TCP)
		printTcp(tcp);
	
	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]);

	pcap_init(PCAP_CHAR_ENC_LOCAL, errbuf);
	handle = pcap_open_offline(argv[1], errbuf);

	if(handle == NULL)
		err(1, "%s: unable to open: %s", argv[0], argv[1]);

	if (pcap_compile(handle, &dnsfilter, "src port 53", 0, PCAP_NETMASK_UNKNOWN) == -1)
		err(1, "%s: failed to compile the expr: %s\n", argv[0], pcap_geterr(handle));

	if (pcap_setfilter(handle, &dnsfilter) == -1)
		err(1, "%s: failed to install filter: %s\n", argv[0], pcap_geterr(handle));


	pcap_loop(handle, -1, dns_reader, NULL);

	pcap_freecode(&dnsfilter);
	pcap_close(handle);

	return 0;
}