diff --git a/CHANGELOG b/CHANGELOG index b6ccad8..65029d7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,11 @@ iodine - IP over DNS is now easy CHANGES: +2006-11-06: 0.3.3 + - Fixed possible buffer overflow + (Found by poplix) + - Reworked dns hostname encoding + 2006-09-11: 0.3.2 - Support for NetBSD - Fixed potential security problems diff --git a/README b/README index 716b553..452e74c 100644 --- a/README +++ b/README @@ -67,7 +67,7 @@ If you have problems, try inspecting the traffic with network monitoring tools and make sure that the relaying DNS server has not cached the response. A cached error message could mean that you started the client before the server. -The upstream data is sent gzipped encoded in hexadecimal. DNS protocol allows +The upstream data is sent gzipped encoded with Base32. DNS protocol allows one query per packet, and one query can be max 256 chars. Each domain name part can be max 63 chars. So your domain name and subdomain should be as short as possible to allow maximum throughput. @@ -91,6 +91,7 @@ iodine has atomic number 53, which happens to be the DNS port number. THANKS: - To kuxien for FreeBSD and OS X testing +- To poplix for code audit AUTHORS & LICENSE: diff --git a/dns.c b/dns.c index 2692850..460932f 100644 --- a/dns.c +++ b/dns.c @@ -43,7 +43,6 @@ #endif -static int host2dns(const char *, char *, int); static int dns_write(int, int, char *, int, char); static void dns_query(int, int, char *, int); @@ -207,7 +206,7 @@ dns_query(int fd, int id, char *host, int type) header->arcount = htons(1); p = buf + sizeof(HEADER); - p += host2dns(host, p, strlen(host)); + p += dns_encode_hostname(host, p, strlen(host)); putshort(&p, type); putshort(&p, C_IN); @@ -320,11 +319,12 @@ dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen) readshort(packet, &data, &class); readlong(packet, &data, &ttl); readshort(packet, &data, &rlen); - readdata(packet, &data, rdata, rlen); + rv = MIN(rlen, sizeof(rdata)); + readdata(packet, &data, rdata, rv); } - if(type == T_NULL && rlen > 2) { - rv = MIN(rlen, sizeof(rdata)); + if(type == T_NULL && rv > 2) { + rv = MIN(rv, buflen); memcpy(outbuf, rdata, rv); } } @@ -332,19 +332,25 @@ dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen) return rv; } -static int -host2dns(const char *host, char *buffer, int size) +int +dns_encode_hostname(const char *host, char *buffer, int size) { char *h; char *p; char *word; + int left; h = strdup(host); memset(buffer, 0, size); p = buffer; + left = size; word = strtok(h, "."); while(word) { + if (strlen(word) > 63 || strlen(word) > left) { + return -1; + } + left -= (strlen(word) + 1); *p++ = (char)strlen(word); memcpy(p, word, strlen(word)); p += strlen(word); @@ -387,7 +393,7 @@ dnsd_send(int fd, struct query *q, char *data, int datalen) p = buf + sizeof(HEADER); name = 0xc000 | ((p - buf) & 0x3fff); - p += host2dns(q->name, p, strlen(q->name)); + p += dns_encode_hostname(q->name, p, strlen(q->name)); putshort(&p, q->type); putshort(&p, C_IN); diff --git a/dns.h b/dns.h index f3807a1..f8da628 100644 --- a/dns.h +++ b/dns.h @@ -26,6 +26,7 @@ void dns_handle_tun(int, char *, int); void dns_ping(int); void dns_handshake(int); int dns_read(int, char *, int); +int dns_encode_hostname(const char *, char *, int); extern struct sockaddr_in peer; diff --git a/iodine.c b/iodine.c index b33c720..756dff1 100644 --- a/iodine.c +++ b/iodine.c @@ -190,7 +190,7 @@ help() { static void version() { printf("iodine IP over DNS tunneling client\n"); - printf("version: 0.3.2 from 2006-09-11\n"); + printf("version: 0.3.3 from 2006-11-05\n"); exit(0); } diff --git a/iodined.c b/iodined.c index 88d3c67..9bda8be 100644 --- a/iodined.c +++ b/iodined.c @@ -196,7 +196,7 @@ help() { static void version() { printf("iodine IP over DNS tunneling server\n"); - printf("version: 0.3.2 from 2006-09-11\n"); + printf("version: 0.3.3 from 2006-11-05\n"); exit(0); } diff --git a/test.c b/test.c index 4125ebe..19050df 100644 --- a/test.c +++ b/test.c @@ -162,6 +162,33 @@ test_readname() printf("OK\n"); } +static void +test_encode_hostname() { + char buf[256]; + int len; + int ret; + + len = 256; + printf(" * Testing hostname encoding... "); + + memset(buf, 0, 256); + ret = dns_encode_hostname( // More than 63 chars between dots + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" + , buf, len); + assert(ret == -1); + + memset(buf, 0, 256); + ret = dns_encode_hostname( // More chars than fits into array + "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." + "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." + , buf, len); + assert(ret == -1); + assert(strlen(buf) < len); + + printf("OK\n"); +} + int main() { @@ -170,6 +197,7 @@ main() test_readputshort(); test_readputlong(); test_readname(); + test_encode_hostname(); printf("** All went well :)\n"); return 0;