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 <ctype.h>
#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;
}

1
dns.h
View file

@ -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;

125
read.c
View file

@ -17,38 +17,129 @@
#include <string.h>
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;
}

21
read.h
View file

@ -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