ref: 24acc31508fd9964b812962a0ff2c52864cb212f
dir: /dns.c/
/*
* 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,
};