From 1fab2db6662c9f7097cbc2486a84f36482e83050 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Dec 2009 03:46:58 +0100 Subject: Add workaround for EDNS0 queries that exceed the buffer size This is a dirty hack which makes it work -- artificially bump the buffer size up to 4KiB for requests with a smaller buffer size. For a DNS proxy which serves arbitrary clients this might crash when it gets a larger response than asked for, but since this is only serving the local host and knowing that glibc does cope, it is possible to get away with it for now. --- plugins/dnsproxy.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'plugins') diff --git a/plugins/dnsproxy.c b/plugins/dnsproxy.c index 8f282142..7cce0f0a 100644 --- a/plugins/dnsproxy.c +++ b/plugins/dnsproxy.c @@ -151,7 +151,7 @@ static gboolean server_event(GIOChannel *channel, GIOCondition condition, { struct server_data *data = user_data; struct request_data *req; - unsigned char buf[768]; + unsigned char buf[4096]; struct domain_hdr *hdr = (void *) &buf; int sk, err, len; @@ -390,6 +390,7 @@ static int parse_request(unsigned char *buf, int len, { struct domain_hdr *hdr = (void *) buf; uint16_t qdcount = ntohs(hdr->qdcount); + uint16_t arcount = ntohs(hdr->arcount); unsigned char *ptr; char *last_label = NULL; int label_count = 0; @@ -398,8 +399,9 @@ static int parse_request(unsigned char *buf, int len, if (len < 12) return -EINVAL; - DBG("id 0x%04x qr %d opcode %d qdcount %d", - hdr->id, hdr->qr, hdr->opcode, qdcount); + DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d", + hdr->id, hdr->qr, hdr->opcode, + qdcount, arcount); if (hdr->qr != 0 || qdcount != 1) return -EINVAL; @@ -432,6 +434,28 @@ static int parse_request(unsigned char *buf, int len, remain -= len + 1; } + if (arcount && remain >= 9 && last_label[4] == 0 && + last_label[5] == 0 && last_label[6] == 0x29) { + uint16_t edns0_bufsize; + + edns0_bufsize = last_label[7] << 8 | last_label[8]; + + DBG("EDNS0 buffer size %u", edns0_bufsize); + + /* This is an evil hack until full TCP support has been + * implemented. + * + * Somtimes the EDNS0 request gets send with a too-small + * buffer size. Since glibc doesn't seem to crash when it + * gets a response biffer then it requested, just bump + * the buffer size up to 4KiB. + */ + if (edns0_bufsize < 0x1000) { + last_label[7] = 0x10; + last_label[8] = 0x00; + } + } + DBG("query %s (%d labels)", name, label_count); return 0; -- cgit v1.2.3