From 4a9887c9df4756eabb018351cc66abbdd14c77a7 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 16 Aug 2006 18:12:15 +0000 Subject: [PATCH] rewrote READ* and PUT*; in read.c, handeling malformed compression of names --- dns.c | 88 +++++++++++++++++++++------------------- dns.h | 1 - read.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++-------- read.h | 21 ++++------ 4 files changed, 162 insertions(+), 73 deletions(-) diff --git a/dns.c b/dns.c index 051412a..cada4a1 100644 --- a/dns.c +++ b/dns.c @@ -32,18 +32,20 @@ #include #include -#include "read.h" #include "structs.h" #include "dns.h" #include "encoding.h" +#include "read.h" // For FreeBSD #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #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); struct sockaddr_in peer; char topdomain[256]; @@ -68,7 +70,8 @@ open_dns(const char *domain, int localport, in_addr_t listen_ip) bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(localport); - addr.sin_addr.s_addr = listen_ip; // This is already network byte order, inet_addr() or constant INADDR_ANY (==0) + /* listen_ip already in network byte order from inet_addr, or 0 */ + addr.sin_addr.s_addr = listen_ip; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(fd < 0) { @@ -88,10 +91,11 @@ open_dns(const char *domain, int localport, in_addr_t listen_ip) } // Save top domain used - strncpy(topdomain, domain, sizeof(topdomain) - 2); - topdomain[sizeof(topdomain) - 1] = 0; + strncpy(topdomain, domain, sizeof(topdomain) - 1); + topdomain[sizeof(topdomain) - 1] = '\0'; printf("Opened UDP socket\n"); + return fd; } @@ -177,7 +181,7 @@ dns_handshake(int dns_fd) dns_write(dns_fd, ++pingid, data, 2, 'H'); } -void +static void dns_query(int fd, int id, char *host, int type) { char *p; @@ -205,16 +209,16 @@ dns_query(int fd, int id, char *host, int type) p = buf + sizeof(HEADER); p += host2dns(host, p, strlen(host)); - PUTSHORT(type, p); - PUTSHORT(C_IN, p); + putshort(&p, type); + putshort(&p, C_IN); // EDNS0 - *p++ = 0x00; //Root - PUTSHORT(0x0029, p); // OPT - PUTSHORT(0x1000, p); // Payload size: 4096 - PUTSHORT(0x0000, p); // Higher bits/ edns version - PUTSHORT(0x8000, p); // Z - PUTSHORT(0x0000, p); // Data length + putbyte(&p, 0x00); //Root + putshort(&p, 0x0029); // OPT + putshort(&p, 0x1000); // Payload size: 4096 + putshort(&p, 0x0000); // Higher bits/edns version + putshort(&p, 0x8000); // Z + putshort(&p, 0x0000); // Data length peerlen = sizeof(peer); @@ -250,6 +254,7 @@ int dns_read(int fd, char *buf, int buflen) { int r; + int rv; long ttl; short rlen; short type; @@ -267,6 +272,7 @@ dns_read(int fd, char *buf, int buflen) addrlen = sizeof(struct sockaddr); r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen); + rv = 0; if(r == -1) { perror("recvfrom"); } else { @@ -281,17 +287,17 @@ dns_read(int fd, char *buf, int buflen) rlen = 0; if(qdcount == 1) { - READNAME(packet, name, data); - READSHORT(type, data); - READSHORT(class, data); + readname(packet, &data, name, sizeof(name)); + readshort(packet, &data, &type); + readshort(packet, &data, &class); } if(ancount == 1) { - READNAME(packet, name, data); - READSHORT(type, data); - READSHORT(class, data); - READLONG(ttl, data); - READSHORT(rlen, data); - READDATA(rdata, data, rlen); + readname(packet, &data, name, sizeof(name)); + readshort(packet, &data, &type); + readshort(packet, &data, &class); + readlong(packet, &data, &ttl); + readshort(packet, &data, &rlen); + readdata(packet, &data, rdata, rlen); } if (dns_sending() && chunkid == ntohs(header->id)) { // Got ACK on sent packet @@ -309,14 +315,12 @@ dns_read(int fd, char *buf, int buflen) if(type == T_NULL && rlen > 2) { memcpy(buf, rdata, rlen); - return rlen; - } else { - return 0; + rv = rlen; } } } - return 0; + return rv; } static int @@ -375,19 +379,18 @@ dnsd_send(int fd, struct query *q, char *data, int datalen) name = 0xc000 | ((p - buf) & 0x3fff); p += host2dns(q->name, p, strlen(q->name)); - PUTSHORT(q->type, p); - PUTSHORT(C_IN, p); - - PUTSHORT(name, p); - PUTSHORT(q->type, p); - PUTSHORT(C_IN, p); - PUTLONG(0, p); + putshort(&p, q->type); + putshort(&p, C_IN); + + putshort(&p, name); + putshort(&p, q->type); + putshort(&p, C_IN); + putlong(&p, 0); q->id = 0; - PUTSHORT(datalen, p); - memcpy(p, data, datalen); - p += datalen; + putshort(&p, datalen); + putdata(&p, data, datalen); len = p - buf; sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen); @@ -411,6 +414,7 @@ int dnsd_read(int fd, struct query *q, char *buf, int buflen) { int r; + int rv; short id; short type; short class; @@ -436,10 +440,9 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen) qdcount = ntohs(header->qdcount); if(qdcount == 1) { - bzero(name, sizeof(name)); - READNAME(packet, name, data); - READSHORT(type, data); - READSHORT(class, data); + readname(packet, &data, name, sizeof(name)); + readshort(packet, &data, &type); + readshort(packet, &data, &class); strncpy(q->name, name, 256); q->type = type; @@ -447,12 +450,13 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen) q->fromlen = addrlen; memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen); - return decodepacket(name, buf, buflen); + rv = decodepacket(name, buf, buflen); } } } else { perror("recvfrom"); + rv = 0; } - return 0; + return rv; } diff --git a/dns.h b/dns.h index 62f6ca1..c64f58c 100644 --- a/dns.h +++ b/dns.h @@ -25,7 +25,6 @@ int dns_sending(); void dns_handle_tun(int, char *, int); void dns_ping(int); void dns_handshake(int); -void dns_query(int, int, char *, int); int dns_read(int, char *, int); extern struct sockaddr_in peer; diff --git a/read.c b/read.c index 4007cf9..2cc5ddf 100644 --- a/read.c +++ b/read.c @@ -17,38 +17,129 @@ #include int -readname(char *packet, char *dst, char *src) +readname(char *packet, char **src, char *dst, size_t length) { - char l; + char *dummy; int len; - int offset; + char *p; + char c; len = 0; - while(*src) { - l = *src++; - len++; + p = *src; - if(l & 0x80 && l & 0x40) { - offset = ((src[-1] & 0x3f) << 8) | src[0]; - readname(packet, dst, packet + offset); - dst += strlen(dst); + p = *src; + while(*p && len < length) { + c = *p++; + + /* is this a compressed label? */ + if((c & 0xc0) == 0xc0) { + dummy = packet + (((p[-1] & 0x3f) << 8) | p[0]); + readname(packet, &dummy, dst, length - len); break; } - while(l) { - *dst++ = *src++; - l--; + while(c && len < length) { + *dst++ = *p++; len++; + + c--; } - *dst++ = '.'; + if (*p != 0) + *dst = '.'; + else + *dst = '\0'; } + (*src) = p+1; - *dst = '\0'; - src++; - len++; + return strlen(dst); +} + +int +readshort(char *packet, char **src, short *dst) +{ + char *p; + + p = *src; + *dst = ((short)p[0] << 8) + | ((short)p[1]); + + (*src) += sizeof(short); + return sizeof(short); +} + +int +readlong(char *packet, char **src, long *dst) +{ + char *p; + + p = *src; + + *dst = ((long)p[0] << 24) + | ((long)p[1] << 16) + | ((long)p[2] << 8) + | ((long)p[3]); + + (*src) += sizeof(long); + return sizeof(long); +} + +int +readdata(char *packet, char **src, char *dst, size_t len) +{ + memcpy(dst, *src, len); + + (*src) += len; return len; } +int +putbyte(char **dst, char value) +{ + **dst = value; + (*dst)++; + + return sizeof(char); +} + +int +putshort(char **dst, short value) +{ + char *p; + + p = *dst; + + *p++ = (value >> 8); + *p++ = value; + + (*dst) = p; + return sizeof(short); +} + +int +putlong(char **dst, long value) +{ + char *p; + + p = *dst; + + *p++ = (value >> 24); + *p++ = (value >> 16); + *p++ = (value >> 8); + *p++ = (value); + + (*dst) = p; + return sizeof(long); +} + +int +putdata(char **dst, char *data, size_t len) +{ + memcpy(*dst, data, len); + + (*dst) += len; + return len; +} + diff --git a/read.h b/read.h index a4075ec..6117b7b 100644 --- a/read.h +++ b/read.h @@ -17,19 +17,14 @@ #ifndef _READ_H_ #define _READ_H_ -int readname(char *, char *, char *); +int readname(char *, char **, char *, size_t); +int readshort(char *, char **, short *); +int readlong(char *, char **, long *); +int readdata(char *, char **, char *, size_t); -#define READNAME(packet, dst, src) (src) += readname((packet), (dst), (src)); - -#define READSHORT(dst, src) \ - memcpy(&dst, src, 2); \ - (dst) = ntohs(dst); (src)+=2; - -#define READLONG(dst, src) \ - memcpy(&dst, src, 2); \ - (dst) = ntohl(dst); (src)+=4; - -#define READDATA(dst, src, len) \ - memcpy((dst), (src), (len)); (src)+=(len); +int putbyte(char **, char); +int putshort(char **, short); +int putlong(char **, long); +int putdata(char **, char *, size_t); #endif