summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-12-14 03:46:58 +0100
committerMarcel Holtmann <marcel@holtmann.org>2009-12-14 03:46:58 +0100
commit1fab2db6662c9f7097cbc2486a84f36482e83050 (patch)
treedced56e815dcefe429b7423b30333fbe4e36d77c /plugins
parentad8fce0c1b11756e1fe04bf04ff205f18ff5dfad (diff)
downloadconnman-1fab2db6662c9f7097cbc2486a84f36482e83050.tar.gz
connman-1fab2db6662c9f7097cbc2486a84f36482e83050.tar.bz2
connman-1fab2db6662c9f7097cbc2486a84f36482e83050.zip
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.
Diffstat (limited to 'plugins')
-rw-r--r--plugins/dnsproxy.c30
1 files changed, 27 insertions, 3 deletions
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;