Release 0.3.4

This commit is contained in:
Erik Ekman 2006-11-08 21:50:15 +00:00
parent 2b6054a939
commit 1defd22a20
10 changed files with 171 additions and 64 deletions

View file

@ -7,9 +7,17 @@ iodine - IP over DNS is now easy
CHANGES:
2006-11-06: 0.3.3
2006-11-08: 0.3.4
- Fixed handshake() buffer overflow
(Found by poplix, Secunia: SA22674 / FrSIRT/ADV-2006-4333)
- Added more tests
- More name parsing enhancements
- Now runs on Linux/AMD64
- Added setting to change server port
2006-11-05: 0.3.3
- Fixed possible buffer overflow
(Found by poplix)
(Found by poplix, Bugtraq ID: 20883)
- Reworked dns hostname encoding
2006-09-11: 0.3.2

17
README
View file

@ -73,13 +73,22 @@ can be max 63 chars. So your domain name and subdomain should be as short as
possible to allow maximum throughput.
TIPS & TRICKS:
If your port 53 is taken on a specific interface by an application that does
not use it, use -p on iodined to specify an alternate port (like -p 5353) and
use for instance iptables (on Linux) to forward the traffic:
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
(Sent in by Tom Schouten)
PORTABILITY:
iodine has been tested on Linux (x86 and SPARC64), FreeBSD (x86), OpenBSD (x86),
NetBSD (x86) and MacOS X (10.3, ppc, with
iodine has been tested on Linux (x86, AMD64 and SPARC64), FreeBSD (x86),
OpenBSD (x86), NetBSD (x86) and MacOS X (10.3, ppc, with
http://www-user.rhrk.uni-kl.de/~nissler/tuntap/). It should work on other
unix-like systems as well that has TUN/TAP tunneling support. Let us know if you
get it to run on other platforms.
unix-like systems as well that has TUN/TAP tunneling support (after some
patching). Let us know if you get it to run on other platforms.
THE NAME:

19
dns.c
View file

@ -26,6 +26,7 @@
#include <time.h>
#include <err.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
@ -66,7 +67,7 @@ open_dns(const char *domain, int localport, in_addr_t listen_ip)
int flag;
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(localport);
/* listen_ip already in network byte order from inet_addr, or 0 */
@ -110,7 +111,7 @@ dns_settarget(const char *host)
return -1;
}
bzero(&peer, sizeof(peer));
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(53);
peer.sin_addr = *((struct in_addr *) h->h_addr);
@ -235,7 +236,7 @@ dns_write(int fd, int id, char *buf, int len, char flag)
char *d;
avail = 0xFF - strlen(topdomain) - 2;
bzero(data, sizeof(data));
memset(data, 0, sizeof(data));
d = data;
written = encode_data(buf, len, avail, d, flag);
encoded = strlen(data);
@ -286,7 +287,7 @@ int
dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen)
{
int rv;
long ttl;
uint32_t ttl;
short rlen;
short type;
short class;
@ -309,12 +310,12 @@ dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen)
rlen = 0;
if(qdcount == 1) {
readname(packet, &data, name, sizeof(name));
readname(packet, packetlen, &data, name, sizeof(name));
readshort(packet, &data, &type);
readshort(packet, &data, &class);
}
if(ancount == 1) {
readname(packet, &data, name, sizeof(name));
readname(packet, packetlen, &data, name, sizeof(name));
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
@ -455,7 +456,7 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen)
qdcount = ntohs(header->qdcount);
if(qdcount == 1) {
readname(packet, &data, name, sizeof(name) -1);
readname(packet, r, &data, name, sizeof(name) -1);
name[256] = 0;
readshort(packet, &data, &type);
readshort(packet, &data, &class);
@ -469,9 +470,11 @@ dnsd_read(int fd, struct query *q, char *buf, int buflen)
rv = decodepacket(name, buf, buflen);
}
}
} else {
} else if (r < 0) { // Error
perror("recvfrom");
rv = 0;
} else { // Packet too small to be dns protocol
rv = 0;
}
return rv;

View file

@ -127,6 +127,7 @@ encode_data(char *buf, int len, int space, char *dest, char flag)
chunks = write / RAW_CHUNK;
leftovers = write % RAW_CHUNK;
// flag is special character to be placed first in the encoded data
if (flag != 0) {
*dest = flag;
} else {
@ -135,7 +136,7 @@ encode_data(char *buf, int len, int space, char *dest, char flag)
}
dest++;
bzero(encoded, sizeof(encoded));
memset(encoded, 0, sizeof(encoded));
ep = encoded;
dp = buf;
for (i = 0; i < chunks; i++) {
@ -144,7 +145,7 @@ encode_data(char *buf, int len, int space, char *dest, char flag)
dp += RAW_CHUNK;
}
realwrite = ENC_CHUNK * chunks;
bzero(padding, sizeof(padding));
memset(padding, 0, sizeof(padding));
pp = padding;
if (leftovers) {
pp += RAW_CHUNK - leftovers;
@ -187,7 +188,7 @@ decode_data(char *dest, int size, const char *src, char *srcend)
dest++;
src++;
bzero(encoded, sizeof(encoded));
memset(encoded, 0, sizeof(encoded));
ep = encoded;
while(len < size && src < srcend) {
if(*src == '.') {

View file

@ -112,8 +112,8 @@ static int
handshake(int dns_fd)
{
struct timeval tv;
char server[128];
char client[128];
char server[65];
char client[65];
char in[4096];
int timeout;
fd_set fds;
@ -144,12 +144,20 @@ handshake(int dns_fd)
}
if (read > 0) {
if (sscanf(in, "%[^-]-%[^-]-%d",
if (sscanf(in, "%64[^-]-%64[^-]-%d",
server, client, &mtu) == 3) {
if (tun_setip(client) == 0 && tun_setmtu(mtu) == 0)
server[64] = 0;
client[64] = 0;
if (tun_setip(client) == 0 &&
tun_setmtu(mtu) == 0) {
return 0;
else
warn("Received handshake but b0rk");
} else {
warn("Received handshake with bad data");
}
} else {
printf("Received bad handshake\n");
}
}
}
@ -190,7 +198,7 @@ help() {
static void
version() {
printf("iodine IP over DNS tunneling client\n");
printf("version: 0.3.3 from 2006-11-05\n");
printf("version: 0.3.4 from 2006-11-08\n");
exit(0);
}

View file

@ -111,7 +111,7 @@ tunnel(int tun_fd, int dns_fd)
}
if(FD_ISSET(dns_fd, &fds)) {
read = dnsd_read(dns_fd, &q, in, sizeof(in));
if (read < 0)
if (read <= 0)
continue;
if(in[0] == 'H' || in[0] == 'h') {
@ -168,8 +168,8 @@ static void
usage() {
extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] "
"tunnel_ip topdomain\n", __progname);
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
" tunnel_ip topdomain\n", __progname);
exit(2);
}
@ -178,8 +178,8 @@ help() {
extern char *__progname;
printf("iodine IP over DNS tunneling server\n");
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] "
"tunnel_ip topdomain\n", __progname);
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
" tunnel_ip topdomain\n", __progname);
printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n");
printf(" -f to keep running in foreground\n");
@ -188,6 +188,7 @@ help() {
printf(" -d device to set tunnel device name\n");
printf(" -m mtu to set tunnel device mtu\n");
printf(" -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
printf(" -p port to listen on for incoming dns traffic (default 53)\n");
printf("tunnel_ip is the IP number of the local tunnel interface.\n");
printf("topdomain is the FQDN that is delegated to this server.\n");
exit(0);
@ -196,7 +197,7 @@ help() {
static void
version() {
printf("iodine IP over DNS tunneling server\n");
printf("version: 0.3.3 from 2006-11-05\n");
printf("version: 0.3.4 from 2006-11-08\n");
exit(0);
}
@ -213,6 +214,7 @@ main(int argc, char **argv)
int mtu;
struct passwd *pw;
in_addr_t listen_ip;
int port;
username = NULL;
newroot = NULL;
@ -220,13 +222,14 @@ main(int argc, char **argv)
foreground = 0;
mtu = 1024;
listen_ip = INADDR_ANY;
port = 53;
packetbuf.len = 0;
packetbuf.offset = 0;
outpacket.len = 0;
q.id = 0;
while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:")) != -1) {
while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:")) != -1) {
switch(choice) {
case 'v':
version();
@ -252,6 +255,9 @@ main(int argc, char **argv)
case 'l':
listen_ip = inet_addr(optarg);
break;
case 'p':
port = atoi(optarg);
break;
default:
usage();
break;
@ -291,7 +297,7 @@ main(int argc, char **argv)
goto cleanup0;
if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
goto cleanup1;
if ((dnsd_fd = open_dns(argv[1], 53, listen_ip)) == -1)
if ((dnsd_fd = open_dns(argv[1], port, listen_ip)) == -1)
goto cleanup2;
my_ip = inet_addr(argv[0]);

42
read.c
View file

@ -15,14 +15,16 @@
*/
#include <string.h>
#include <stdint.h>
static int
readname_loop(char *packet, char **src, char *dst, size_t length, size_t loop)
readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
{
char *dummy;
char *s;
char *d;
int len;
int offset;
char c;
if (loop <= 0)
@ -36,8 +38,18 @@ readname_loop(char *packet, char **src, char *dst, size_t length, size_t loop)
/* is this a compressed label? */
if((c & 0xc0) == 0xc0) {
dummy = packet + (((s[-1] & 0x3f) << 8) | s[0]);
len += readname_loop(packet, &dummy, d, length - len, loop - 1);
offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
if (offset > packetlen) {
if (len == 0) {
// Bad jump first in packet
return 0;
} else {
// Bad jump after some data
break;
}
}
dummy = packet + offset;
len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
goto end;
}
@ -65,9 +77,9 @@ end:
}
int
readname(char *packet, char **src, char *dst, size_t length)
readname(char *packet, int packetlen, char **src, char *dst, size_t length)
{
return readname_loop(packet, src, dst, length, 10);
return readname_loop(packet, packetlen, src, dst, length, 10);
}
int
@ -83,19 +95,20 @@ readshort(char *packet, char **src, short *dst)
}
int
readlong(char *packet, char **src, long *dst)
readlong(char *packet, char **src, uint32_t *dst)
{
// A long as described in dns protocol is always 32 bits
unsigned char *p;
p = *src;
*dst = ((long)p[0] << 24)
| ((long)p[1] << 16)
| ((long)p[2] << 8)
| ((long)p[3]);
*dst = ((uint32_t)p[0] << 24)
| ((uint32_t)p[1] << 16)
| ((uint32_t)p[2] << 8)
| ((uint32_t)p[3]);
(*src) += sizeof(long);
return sizeof(long);
(*src) += sizeof(uint32_t);
return sizeof(uint32_t);
}
int
@ -135,8 +148,9 @@ putshort(char **dst, short value)
}
int
putlong(char **dst, long value)
putlong(char **dst, uint32_t value)
{
// A long as described in dns protocol is always 32 bits
unsigned char *p;
p = *dst;
@ -147,7 +161,7 @@ putlong(char **dst, long value)
*p++ = (value);
(*dst) = p;
return sizeof(long);
return sizeof(uint32_t);
}
int

6
read.h
View file

@ -17,14 +17,14 @@
#ifndef _READ_H_
#define _READ_H_
int readname(char *, char **, char *, size_t);
int readname(char *, int, char **, char *, size_t);
int readshort(char *, char **, short *);
int readlong(char *, char **, long *);
int readlong(char *, char **, uint32_t *);
int readdata(char *, char **, char *, size_t);
int putbyte(char **, char);
int putshort(char **, short);
int putlong(char **, long);
int putlong(char **, uint32_t);
int putdata(char **, char *, size_t);
#endif

86
test.c
View file

@ -23,11 +23,13 @@
#include <arpa/nameser8_compat.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "structs.h"
#include "encoding.h"
#include "dns.h"
#include "read.h"
@ -73,10 +75,10 @@ static void
test_readputlong()
{
char buf[4];
long putint;
long tempi;
long tint;
long *l;
uint32_t putint;
uint32_t tempi;
uint32_t tint;
uint32_t *l;
char* p;
int i;
@ -89,13 +91,13 @@ test_readputlong()
p = buf;
putlong(&p, tint);
l = &putint;
memcpy(l, buf, sizeof(int));
memcpy(l, buf, sizeof(uint32_t));
if (putint != tempi) {
printf("Bad value on putlong for %d\n", i);
exit(2);
}
l = &tempi;
memcpy(buf, l, sizeof(int));
memcpy(buf, l, sizeof(uint32_t));
p = buf;
readlong(NULL, &p, &tempi);
if (tempi != tint) {
@ -129,6 +131,13 @@ test_readname()
char onejump[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
char badjump[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
char badjump2[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
char *jumper;
char buf[1024];
char *data;
int rv;
@ -136,28 +145,50 @@ test_readname()
printf(" * Testing readname... ");
fflush(stdout);
bzero(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
data = emptyloop + sizeof(HEADER);
buf[1023] = 'A';
rv = readname(emptyloop, &data, buf, 1023);
rv = readname(emptyloop, sizeof(emptyloop), &data, buf, 1023);
assert(buf[1023] == 'A');
bzero(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
data = infloop + sizeof(HEADER);
buf[4] = '\a';
rv = readname(infloop, &data, buf, 4);
rv = readname(infloop, sizeof(infloop), &data, buf, 4);
assert(buf[4] == '\a');
bzero(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
data = longname + sizeof(HEADER);
buf[256] = '\a';
rv = readname(longname, &data, buf, 256);
rv = readname(longname, sizeof(longname), &data, buf, 256);
assert(buf[256] == '\a');
bzero(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
data = onejump + sizeof(HEADER);
rv = readname(onejump, &data, buf, 256);
rv = readname(onejump, sizeof(onejump), &data, buf, 256);
assert(rv == 9);
// These two tests use malloc to cause segfault if jump is executed
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump));
if (jumper) {
memcpy(jumper, badjump, sizeof(badjump));
data = jumper + sizeof(HEADER);
rv = readname(jumper, sizeof(badjump), &data, buf, 256);
assert(rv == 0);
}
free(jumper);
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump2));
if (jumper) {
memcpy(jumper, badjump2, sizeof(badjump2));
data = jumper + sizeof(HEADER);
rv = readname(jumper, sizeof(badjump2), &data, buf, 256);
assert(rv == 4);
assert(strcmp("BA.", buf) == 0);
}
free(jumper);
printf("OK\n");
}
@ -170,6 +201,7 @@ test_encode_hostname() {
len = 256;
printf(" * Testing hostname encoding... ");
fflush(stdout);
memset(buf, 0, 256);
ret = dns_encode_hostname( // More than 63 chars between dots
@ -189,6 +221,31 @@ test_encode_hostname() {
printf("OK\n");
}
static void
test_base32() {
char temp[256];
char *start = "HELLOTEST";
char *out = "1HELLOTEST";
char *end;
char *tempend;
int codedlength;
printf(" * Testing base32 encoding... ");
fflush(stdout);
memset(temp, 0, sizeof(temp));
end = malloc(16);
memset(end, 0, 16);
codedlength = encode_data(start, 9, 256, temp, 0);
tempend = temp + strlen(temp);
decode_data(end, 16, temp, tempend);
assert(strcmp(out, end) == 0);
free(end);
printf("OK\n");
}
int
main()
{
@ -198,6 +255,7 @@ main()
test_readputlong();
test_readname();
test_encode_hostname();
test_base32();
printf("** All went well :)\n");
return 0;

2
tun.c
View file

@ -52,7 +52,7 @@ open_tun(const char *tun_device)
return -1;
}
bzero(&ifreq, sizeof(ifreq));
memset(&ifreq, 0, sizeof(ifreq));
ifreq.ifr_flags = IFF_TUN;