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: 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 - Fixed possible buffer overflow
(Found by poplix) (Found by poplix, Bugtraq ID: 20883)
- Reworked dns hostname encoding - Reworked dns hostname encoding
2006-09-11: 0.3.2 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. 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: PORTABILITY:
iodine has been tested on Linux (x86 and SPARC64), FreeBSD (x86), OpenBSD (x86), iodine has been tested on Linux (x86, AMD64 and SPARC64), FreeBSD (x86),
NetBSD (x86) and MacOS X (10.3, ppc, with 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 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 unix-like systems as well that has TUN/TAP tunneling support (after some
get it to run on other platforms. patching). Let us know if you get it to run on other platforms.
THE NAME: THE NAME:

19
dns.c
View File

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

View File

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

View File

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

View File

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

42
read.c
View File

@ -15,14 +15,16 @@
*/ */
#include <string.h> #include <string.h>
#include <stdint.h>
static int 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 *dummy;
char *s; char *s;
char *d; char *d;
int len; int len;
int offset;
char c; char c;
if (loop <= 0) 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? */ /* is this a compressed label? */
if((c & 0xc0) == 0xc0) { if((c & 0xc0) == 0xc0) {
dummy = packet + (((s[-1] & 0x3f) << 8) | s[0]); offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
len += readname_loop(packet, &dummy, d, length - len, loop - 1); 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; goto end;
} }
@ -65,9 +77,9 @@ end:
} }
int 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 int
@ -83,19 +95,20 @@ readshort(char *packet, char **src, short *dst)
} }
int 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; unsigned char *p;
p = *src; p = *src;
*dst = ((long)p[0] << 24) *dst = ((uint32_t)p[0] << 24)
| ((long)p[1] << 16) | ((uint32_t)p[1] << 16)
| ((long)p[2] << 8) | ((uint32_t)p[2] << 8)
| ((long)p[3]); | ((uint32_t)p[3]);
(*src) += sizeof(long); (*src) += sizeof(uint32_t);
return sizeof(long); return sizeof(uint32_t);
} }
int int
@ -135,8 +148,9 @@ putshort(char **dst, short value)
} }
int 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; unsigned char *p;
p = *dst; p = *dst;
@ -147,7 +161,7 @@ putlong(char **dst, long value)
*p++ = (value); *p++ = (value);
(*dst) = p; (*dst) = p;
return sizeof(long); return sizeof(uint32_t);
} }
int int

6
read.h
View File

@ -17,14 +17,14 @@
#ifndef _READ_H_ #ifndef _READ_H_
#define _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 readshort(char *, char **, short *);
int readlong(char *, char **, long *); int readlong(char *, char **, uint32_t *);
int readdata(char *, char **, char *, size_t); int readdata(char *, char **, char *, size_t);
int putbyte(char **, char); int putbyte(char **, char);
int putshort(char **, short); int putshort(char **, short);
int putlong(char **, long); int putlong(char **, uint32_t);
int putdata(char **, char *, size_t); int putdata(char **, char *, size_t);
#endif #endif

86
test.c
View File

@ -23,11 +23,13 @@
#include <arpa/nameser8_compat.h> #include <arpa/nameser8_compat.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "structs.h" #include "structs.h"
#include "encoding.h"
#include "dns.h" #include "dns.h"
#include "read.h" #include "read.h"
@ -73,10 +75,10 @@ static void
test_readputlong() test_readputlong()
{ {
char buf[4]; char buf[4];
long putint; uint32_t putint;
long tempi; uint32_t tempi;
long tint; uint32_t tint;
long *l; uint32_t *l;
char* p; char* p;
int i; int i;
@ -89,13 +91,13 @@ test_readputlong()
p = buf; p = buf;
putlong(&p, tint); putlong(&p, tint);
l = &putint; l = &putint;
memcpy(l, buf, sizeof(int)); memcpy(l, buf, sizeof(uint32_t));
if (putint != tempi) { if (putint != tempi) {
printf("Bad value on putlong for %d\n", i); printf("Bad value on putlong for %d\n", i);
exit(2); exit(2);
} }
l = &tempi; l = &tempi;
memcpy(buf, l, sizeof(int)); memcpy(buf, l, sizeof(uint32_t));
p = buf; p = buf;
readlong(NULL, &p, &tempi); readlong(NULL, &p, &tempi);
if (tempi != tint) { if (tempi != tint) {
@ -129,6 +131,13 @@ test_readname()
char onejump[] = char onejump[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00" "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\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 buf[1024];
char *data; char *data;
int rv; int rv;
@ -136,28 +145,50 @@ test_readname()
printf(" * Testing readname... "); printf(" * Testing readname... ");
fflush(stdout); fflush(stdout);
bzero(buf, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = emptyloop + sizeof(HEADER); data = emptyloop + sizeof(HEADER);
buf[1023] = 'A'; buf[1023] = 'A';
rv = readname(emptyloop, &data, buf, 1023); rv = readname(emptyloop, sizeof(emptyloop), &data, buf, 1023);
assert(buf[1023] == 'A'); assert(buf[1023] == 'A');
bzero(buf, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = infloop + sizeof(HEADER); data = infloop + sizeof(HEADER);
buf[4] = '\a'; buf[4] = '\a';
rv = readname(infloop, &data, buf, 4); rv = readname(infloop, sizeof(infloop), &data, buf, 4);
assert(buf[4] == '\a'); assert(buf[4] == '\a');
bzero(buf, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = longname + sizeof(HEADER); data = longname + sizeof(HEADER);
buf[256] = '\a'; buf[256] = '\a';
rv = readname(longname, &data, buf, 256); rv = readname(longname, sizeof(longname), &data, buf, 256);
assert(buf[256] == '\a'); assert(buf[256] == '\a');
bzero(buf, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = onejump + sizeof(HEADER); data = onejump + sizeof(HEADER);
rv = readname(onejump, &data, buf, 256); rv = readname(onejump, sizeof(onejump), &data, buf, 256);
assert(rv == 9); 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"); printf("OK\n");
} }
@ -170,6 +201,7 @@ test_encode_hostname() {
len = 256; len = 256;
printf(" * Testing hostname encoding... "); printf(" * Testing hostname encoding... ");
fflush(stdout);
memset(buf, 0, 256); memset(buf, 0, 256);
ret = dns_encode_hostname( // More than 63 chars between dots ret = dns_encode_hostname( // More than 63 chars between dots
@ -189,6 +221,31 @@ test_encode_hostname() {
printf("OK\n"); 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 int
main() main()
{ {
@ -198,6 +255,7 @@ main()
test_readputlong(); test_readputlong();
test_readname(); test_readname();
test_encode_hostname(); test_encode_hostname();
test_base32();
printf("** All went well :)\n"); printf("** All went well :)\n");
return 0; return 0;

2
tun.c
View File

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