rewrote READ* and PUT*; in read.c, handeling malformed compression of names

This commit is contained in:
Bjorn Andersson 2006-08-16 18:12:15 +00:00
parent eb9f38f2e0
commit 4a9887c9df
4 changed files with 162 additions and 73 deletions

88
dns.c
View File

@ -32,18 +32,20 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "read.h"
#include "structs.h" #include "structs.h"
#include "dns.h" #include "dns.h"
#include "encoding.h" #include "encoding.h"
#include "read.h"
// For FreeBSD // For FreeBSD
#ifndef MIN #ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b))
#endif #endif
static int host2dns(const char *, char *, int); static int host2dns(const char *, char *, int);
static int dns_write(int, int, char *, int, char); static int dns_write(int, int, char *, int, char);
static void dns_query(int, int, char *, int);
struct sockaddr_in peer; struct sockaddr_in peer;
char topdomain[256]; char topdomain[256];
@ -68,7 +70,8 @@ open_dns(const char *domain, int localport, in_addr_t listen_ip)
bzero(&addr, sizeof(addr)); bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(localport); 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); fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd < 0) { if(fd < 0) {
@ -88,10 +91,11 @@ open_dns(const char *domain, int localport, in_addr_t listen_ip)
} }
// Save top domain used // Save top domain used
strncpy(topdomain, domain, sizeof(topdomain) - 2); strncpy(topdomain, domain, sizeof(topdomain) - 1);
topdomain[sizeof(topdomain) - 1] = 0; topdomain[sizeof(topdomain) - 1] = '\0';
printf("Opened UDP socket\n"); printf("Opened UDP socket\n");
return fd; return fd;
} }
@ -177,7 +181,7 @@ dns_handshake(int dns_fd)
dns_write(dns_fd, ++pingid, data, 2, 'H'); dns_write(dns_fd, ++pingid, data, 2, 'H');
} }
void static void
dns_query(int fd, int id, char *host, int type) dns_query(int fd, int id, char *host, int type)
{ {
char *p; char *p;
@ -205,16 +209,16 @@ dns_query(int fd, int id, char *host, int type)
p = buf + sizeof(HEADER); p = buf + sizeof(HEADER);
p += host2dns(host, p, strlen(host)); p += host2dns(host, p, strlen(host));
PUTSHORT(type, p); putshort(&p, type);
PUTSHORT(C_IN, p); putshort(&p, C_IN);
// EDNS0 // EDNS0
*p++ = 0x00; //Root putbyte(&p, 0x00); //Root
PUTSHORT(0x0029, p); // OPT putshort(&p, 0x0029); // OPT
PUTSHORT(0x1000, p); // Payload size: 4096 putshort(&p, 0x1000); // Payload size: 4096
PUTSHORT(0x0000, p); // Higher bits/ edns version putshort(&p, 0x0000); // Higher bits/edns version
PUTSHORT(0x8000, p); // Z putshort(&p, 0x8000); // Z
PUTSHORT(0x0000, p); // Data length putshort(&p, 0x0000); // Data length
peerlen = sizeof(peer); peerlen = sizeof(peer);
@ -250,6 +254,7 @@ int
dns_read(int fd, char *buf, int buflen) dns_read(int fd, char *buf, int buflen)
{ {
int r; int r;
int rv;
long ttl; long ttl;
short rlen; short rlen;
short type; short type;
@ -267,6 +272,7 @@ dns_read(int fd, char *buf, int buflen)
addrlen = sizeof(struct sockaddr); addrlen = sizeof(struct sockaddr);
r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen); r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
rv = 0;
if(r == -1) { if(r == -1) {
perror("recvfrom"); perror("recvfrom");
} else { } else {
@ -281,17 +287,17 @@ dns_read(int fd, char *buf, int buflen)
rlen = 0; rlen = 0;
if(qdcount == 1) { if(qdcount == 1) {
READNAME(packet, name, data); readname(packet, &data, name, sizeof(name));
READSHORT(type, data); readshort(packet, &data, &type);
READSHORT(class, data); readshort(packet, &data, &class);
} }
if(ancount == 1) { if(ancount == 1) {
READNAME(packet, name, data); readname(packet, &data, name, sizeof(name));
READSHORT(type, data); readshort(packet, &data, &type);
READSHORT(class, data); readshort(packet, &data, &class);
READLONG(ttl, data); readlong(packet, &data, &ttl);
READSHORT(rlen, data); readshort(packet, &data, &rlen);
READDATA(rdata, data, rlen); readdata(packet, &data, rdata, rlen);
} }
if (dns_sending() && chunkid == ntohs(header->id)) { if (dns_sending() && chunkid == ntohs(header->id)) {
// Got ACK on sent packet // Got ACK on sent packet
@ -309,14 +315,12 @@ dns_read(int fd, char *buf, int buflen)
if(type == T_NULL && rlen > 2) { if(type == T_NULL && rlen > 2) {
memcpy(buf, rdata, rlen); memcpy(buf, rdata, rlen);
return rlen; rv = rlen;
} else {
return 0;
} }
} }
} }
return 0; return rv;
} }
static int static int
@ -375,19 +379,18 @@ dnsd_send(int fd, struct query *q, char *data, int datalen)
name = 0xc000 | ((p - buf) & 0x3fff); name = 0xc000 | ((p - buf) & 0x3fff);
p += host2dns(q->name, p, strlen(q->name)); p += host2dns(q->name, p, strlen(q->name));
PUTSHORT(q->type, p); putshort(&p, q->type);
PUTSHORT(C_IN, p); putshort(&p, C_IN);
PUTSHORT(name, p); putshort(&p, name);
PUTSHORT(q->type, p); putshort(&p, q->type);
PUTSHORT(C_IN, p); putshort(&p, C_IN);
PUTLONG(0, p); putlong(&p, 0);
q->id = 0; q->id = 0;
PUTSHORT(datalen, p); putshort(&p, datalen);
memcpy(p, data, datalen); putdata(&p, data, datalen);
p += datalen;
len = p - buf; len = p - buf;
sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen); 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) dnsd_read(int fd, struct query *q, char *buf, int buflen)
{ {
int r; int r;
int rv;
short id; short id;
short type; short type;
short class; short class;
@ -436,10 +440,9 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen)
qdcount = ntohs(header->qdcount); qdcount = ntohs(header->qdcount);
if(qdcount == 1) { if(qdcount == 1) {
bzero(name, sizeof(name)); readname(packet, &data, name, sizeof(name));
READNAME(packet, name, data); readshort(packet, &data, &type);
READSHORT(type, data); readshort(packet, &data, &class);
READSHORT(class, data);
strncpy(q->name, name, 256); strncpy(q->name, name, 256);
q->type = type; q->type = type;
@ -447,12 +450,13 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen)
q->fromlen = addrlen; q->fromlen = addrlen;
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen); memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
return decodepacket(name, buf, buflen); rv = decodepacket(name, buf, buflen);
} }
} }
} else { } else {
perror("recvfrom"); perror("recvfrom");
rv = 0;
} }
return 0; return rv;
} }

1
dns.h
View File

@ -25,7 +25,6 @@ int dns_sending();
void dns_handle_tun(int, char *, int); void dns_handle_tun(int, char *, int);
void dns_ping(int); void dns_ping(int);
void dns_handshake(int); void dns_handshake(int);
void dns_query(int, int, char *, int);
int dns_read(int, char *, int); int dns_read(int, char *, int);
extern struct sockaddr_in peer; extern struct sockaddr_in peer;

125
read.c
View File

@ -17,38 +17,129 @@
#include <string.h> #include <string.h>
int 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 len;
int offset; char *p;
char c;
len = 0; len = 0;
while(*src) { p = *src;
l = *src++;
len++;
if(l & 0x80 && l & 0x40) { p = *src;
offset = ((src[-1] & 0x3f) << 8) | src[0]; while(*p && len < length) {
readname(packet, dst, packet + offset); c = *p++;
dst += strlen(dst);
/* is this a compressed label? */
if((c & 0xc0) == 0xc0) {
dummy = packet + (((p[-1] & 0x3f) << 8) | p[0]);
readname(packet, &dummy, dst, length - len);
break; break;
} }
while(l) { while(c && len < length) {
*dst++ = *src++; *dst++ = *p++;
l--;
len++; len++;
c--;
} }
*dst++ = '.'; if (*p != 0)
*dst = '.';
else
*dst = '\0';
} }
(*src) = p+1;
*dst = '\0'; return strlen(dst);
src++; }
len++;
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; 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;
}

21
read.h
View File

@ -17,19 +17,14 @@
#ifndef _READ_H_ #ifndef _READ_H_
#define _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)); int putbyte(char **, char);
int putshort(char **, short);
#define READSHORT(dst, src) \ int putlong(char **, long);
memcpy(&dst, src, 2); \ int putdata(char **, char *, size_t);
(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);
#endif #endif