Sunday, May 10, 2009

dns packet parser

something I found in my home directory.


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* returns a pointer to the octet after the string */
char *decode_string(const char *packet, const char *in, char *out) {
char *rv = NULL;

*out = '\0';
while (1) {
if (*in == '\0') {
if (rv == NULL)
rv = (char *)in + 1;
break;
} else if ((*in & 0xc0) == 0xc0) {
if (rv == NULL)
rv = (char *)in + 2;
in = packet + ((in[0] & 0x3f) << 8 | in[1] & 0xff);
continue;
} else {
int len;

len = *in++ & 0xff;
strncat(out, in, len);
in += len;
strcat(out, ".");
}
}

return rv;
}

int main() {
char buf[512];
char *p;
uint16_t id, flags, qdcount, ancount, nscount, arcount;

if (read(STDIN_FILENO, &buf, sizeof (buf)) <= 0) {
perror("read()");
return 1;
}

id = buf[0] << 8 | buf[1] & 0xff;
flags = buf[2] << 8 | buf[3] & 0xff;
qdcount = buf[4] << 8 | buf[5] & 0xff;
ancount = buf[6] << 8 | buf[7] & 0xff;
nscount = buf[8] << 8 | buf[9] & 0xff;
arcount = buf[10] << 8 | buf[11] & 0xff;

printf("id: %d\n", id);
printf("flags: %hx\n", flags);
printf("qdcount: %d\n", qdcount);
printf("ancount: %d\n", ancount);
printf("nscount: %d\n", nscount);
printf("arcount: %d\n", arcount);

p = buf + 12;
while (qdcount + ancount + nscount + arcount > 0) {
if (qdcount > 0) {
char qname[512];
uint16_t qtype, qclass;
int len;

/* 1,"a",2,"bb",3,"ccc",0,qtype,qclass */
qname[0] = '\0';
while (*p != '\0') {
len = *p++;
strncat (qname, p, len);
p += len;
strcat(qname, ".");
}
p++;
qtype = p[0] << 8 | p[1] & 0xff;
p += 2;
qclass = p[0] << 8 | p[1] & 0xff;
p += 2;

printf("qd: %s %d %d\n", qname, qtype, qclass);

qdcount--;
} else {
char name[512];
uint16_t type, class;
uint32_t ttl;
uint16_t rdlength;
char data[512];
char *section;

if (ancount > 0) {
section = "an";
ancount--;
} else if (nscount > 0) {
section = "ns";
nscount--;
} else if (arcount > 0) {
section = "ar";
arcount--;
}

p = decode_string(buf, p, name);
type = p[0] << 8 | p[1] & 0xff;
p += 2;
class = p[0] << 8 | p[1] & 0xff;
p += 2;
ttl = (p[0] & 0xff) << 24 | (p[1] & 0xff) << 16 |
(p[2] & 0xff) << 8 | (p[3] & 0xff);
p += 4;
rdlength = p[0] << 8 | p[1] & 0xff;
p += 2;
data[0] = '\0';
if (type == 1 && class == 1) {
sprintf(data, "%u.%u.%u.%u", p[0] & 0xff, p[1] & 0xff,
p[2] & 0xff, p[3] & 0xff);
} else if (type == 2 && class == 1) {
decode_string(buf, p, data);
} else {
fprintf(stderr, "warning: unimplemented data type\n");
}
p += rdlength;

printf("%s: %s %d %d %d %d %s\n", section, name, type, class, ttl, rdlength,
data);

}
}

return 0;
}


outputs something like:

% ./dns_query.pl|./dns_parse_reponse
id: 11111
flags: 8180
qdcount: 1
ancount: 3
nscount: 4
arcount: 4
qd: google.com. 1 1
an: google.com. 1 1 294 4 74.125.45.100
an: google.com. 1 1 294 4 209.85.171.100
an: google.com. 1 1 294 4 74.125.67.100
ns: google.com. 2 1 104685 6 ns1.google.com.
ns: google.com. 2 1 104685 6 ns2.google.com.
ns: google.com. 2 1 104685 6 ns3.google.com.
ns: google.com. 2 1 104685 6 ns4.google.com.
ar: ns1.google.com. 1 1 92892 4 216.239.32.10
ar: ns2.google.com. 1 1 97189 4 216.239.34.10
ar: ns3.google.com. 1 1 101429 4 216.239.36.10
ar: ns4.google.com. 1 1 96839 4 216.239.38.10

No comments: