Compare commits

...

3 Commits

Author SHA1 Message Date
Erik Ekman e45bdece8e Tagged iodine 0.4.2 2008-08-06 20:26:36 +00:00
Erik Ekman d27bd67997 Release 0.4.1 tagged 2007-11-30 22:11:30 +00:00
Erik Ekman 4d4da3eb87 Release 0.4.0 2007-03-25 12:41:20 +00:00
35 changed files with 1554 additions and 700 deletions

View File

@ -1,13 +1,40 @@
iodine - IP over DNS is now easy iodine - http://code.kryo.se/iodine
http://code.kryo.se/iodine ***********************************
********************************
CHANGES: CHANGES:
xxxx-xx-xx: 0.4.0 "Run Home" 2008-08-06: 0.4.2 "Opened Zone"
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann
- Applied a patch for not creating and configuring the tun interface,
Debian bug #477692 by Vincent Bernat, controlled by -s switch
- Applied a security patch from Andrew Griffiths, use setgroups() to
limit the groups of the user
- Applied a patch to make iodine build on (Open)Solaris, from Albert Lee
Needs TUN/TAP driver: http://www.whiteboard.ne.jp/~admin2/tuntap/
Still needs some more code in tun.c for opening/closing the device
- Added option in server (-c) to disable IP/port checking on each packet,
will hopefully help when server is behind NAT
- Fixed bug #21, now only IP address part of each packet is checked.
Should remove the need for the -c option and also work with
bugfixed DNS servers worldwide.
- Added -D option on server to enable debugging. Debug level 1 now prints
info about each RX/TX datagram.
2007-11-30: 0.4.1 "Tea Online"
- Introduced encoding API
- Switched to new Base32 implementation
- Added Base64 implementation that only uses 63 chars (not used yet)
- Refined 'install' make target and use $(MAKE) for recursive calls
- All received error messages (RCODE field) are echoed
- Top domain limited to 128 chars
- Case preservation check sent after login to decide codec
- Fixed crash on incoming NULL query in server with bad top domain
- /etc/resolv.conf is consulted if no nameserver is given on commandline
- Applied patch from Matthew W. S. Bell (Detach before chroot/dropping priv)
2007-03-25: 0.4.0 "Run Home"
- Added multiuser support (up to 8 users simultaneously) - Added multiuser support (up to 8 users simultaneously)
- Added authentication (password entered as argument or on stdin) - Added authentication (password entered as argument or on stdin)
- Added manpage - Added manpage

View File

@ -1,6 +1,11 @@
PREFIX=/usr/local prefix=/usr/local
sbindir=$(prefix)/sbin
datadir=$(prefix)/share
mandir=$(datadir)/man
INSTALL=/usr/bin/install DESTDIR=
INSTALL=install
INSTALL_FLAGS= INSTALL_FLAGS=
MKDIR=mkdir MKDIR=mkdir
@ -10,26 +15,31 @@ RM=rm
RM_FLAGS=-f RM_FLAGS=-f
all: all:
@(cd src; make all) @(cd src; $(MAKE) all)
install: all install: all
$(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/sbin $(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
$(INSTALL) $(INSTALL_FLAGS) bin/iodine $(PREFIX)/sbin/iodine $(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine
$(INSTALL) $(INSTALL_FLAGS) bin/iodined $(PREFIX)/sbin/iodined chmod 755 $(DESTDIR)$(sbindir)/iodine
$(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/man/man8 $(INSTALL) $(INSTALL_FLAGS) bin/iodined $(DESTDIR)$(sbindir)/iodined
$(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(PREFIX)/man/man8/iodine.8 chmod 755 $(DESTDIR)$(sbindir)/iodined
$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(mandir)/man8
$(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(DESTDIR)$(mandir)/man8/iodine.8
chmod 644 $(DESTDIR)$(mandir)/man8/iodine.8
uninstall: uninstall:
$(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodine $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodine
$(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodined $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined
$(RM) $(RM_FLAGS) $(PREFIX)/man/man8/iodine.8 $(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8
test: all test: all
@(cd tests; make all) @echo "!! The check library is required for compiling and running the tests"
@echo "!! Get it at http://check.sf.net"
@(cd tests; $(MAKE) all)
clean: clean:
@echo "Cleaning..." @echo "Cleaning..."
@(cd src; make clean) @(cd src; $(MAKE) clean)
@(cd tests; make clean) @(cd tests; $(MAKE) clean)
@rm -rf bin @rm -rf bin

27
README
View File

@ -1,9 +1,7 @@
iodine - IP over DNS is now easy iodine - http://code.kryo.se/iodine
http://code.kryo.se/iodine ***********************************
********************************
This is a piece of software that lets you tunnel IPv4 data through a DNS This is a piece of software that lets you tunnel IPv4 data through a DNS
server. This can be usable in different situations where internet access is server. This can be usable in different situations where internet access is
@ -30,13 +28,18 @@ HOW TO USE:
Server side: Server side:
To use this tunnel, you need control over a real domain (like mytunnel.com), To use this tunnel, you need control over a real domain (like mytunnel.com),
and a server with a static public IP number that does not yet run a DNS and a server with a public IP number (not behind NAT) that does not yet run
server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server. a DNS server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the
If you use BIND for the domain, add these lines to the zone file: server. If you use BIND for the domain, add these lines to the zone file:
tunnel1host IN A 10.15.213.99 tunnel1host IN A 10.15.213.99
tunnel1 IN NS tunnel1host.mytunnel.com. tunnel1 IN NS tunnel1host.mytunnel.com.
Do not use CNAME instead of A above.
If your server has a dynamic IP, use a dynamic dns provider:
tunnel1 IN NS tunnel1host.mydyndnsprovider.com
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
to your server. Start iodined on the server. The first argument is the tunnel to your server. Start iodined on the server. The first argument is the tunnel
IP address (like 192.168.99.1) and the second is the assigned domain (in this IP address (like 192.168.99.1) and the second is the assigned domain (in this
@ -60,13 +63,11 @@ either side.
MISC. INFO: MISC. INFO:
Note that you can have only one client per server at the same time. This is
because of the fragmentation of big packets going upstream, and will be fixed
in future versions.
Try experimenting with the MTU size (-m option) to get maximum bandwidth. It is Try experimenting with the MTU size (-m option) to get maximum bandwidth. It is
set to 1024 by default, which seems to work with most DNS servers. If you have set to 1024 by default, which seems to work with most DNS servers. If you have
problems, try setting it to below 512. problems, try setting it to 220 as this ensures all packets to be < 512 bytes.
Some DNS servers enforce a 512 byte packet limit, and this is probably the case
if you can ping through the tunnel but not login via SSH.
If you have problems, try inspecting the traffic with network monitoring tools If you have problems, try inspecting the traffic with network monitoring tools
and make sure that the relaying DNS server has not cached the response. A and make sure that the relaying DNS server has not cached the response. A
@ -90,7 +91,7 @@ iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
PORTABILITY: PORTABILITY:
iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD
(ia64, x86), OpenBSD (x86), NetBSD (x86) and MacOS X (10.3, ppc, with (ia64, x86), OpenBSD (x86), NetBSD (x86) and MacOS X (ppc and x86, 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 (after some 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. patching). Let us know if you get it to run on other platforms.

6
TODO
View File

@ -1,9 +1,7 @@
iodine - IP over DNS is now easy iodine - http://code.kryo.se/iodine
http://code.kryo.se/iodine ***********************************
********************************
The TODO list is now located at The TODO list is now located at

View File

@ -1,5 +1,5 @@
.\" groff -man -Tascii iodine.8 .\" groff -man -Tascii iodine.8
.TH IODINE 8 "FEB 2007" "User Manuals" .TH IODINE 8 "JUL 2008" "User Manuals"
.SH NAME .SH NAME
iodine, iodined \- tunnel IPv4 over DNS iodine, iodined \- tunnel IPv4 over DNS
.SH SYNOPSIS .SH SYNOPSIS
@ -16,14 +16,16 @@ iodine, iodined \- tunnel IPv4 over DNS
.B ] [-d .B ] [-d
.I device .I device
.B ] .B ]
.B [
.I nameserver .I nameserver
.B ]
.I topdomain .I topdomain
.B iodined [-v] .B iodined [-v]
.B iodined [-h] .B iodined [-h]
.B iodined [-f] [-u .B iodined [-c] [-s] [-f] [-D] [-u
.I user .I user
.B ] [-P .B ] [-P
.I password .I password
@ -76,6 +78,16 @@ Use the TUN device 'device' instead of the normal one, which is dnsX on Linux
and otherwise tunX. and otherwise tunX.
.SS Server Options: .SS Server Options:
.TP .TP
.B -c
Disable checks on client IP on all incoming requests.
.TP
.B -s
Don't try to configure IP address or MTU. This should only be used if
you have already configured the device that will be used.
.TP
.B -D
Increase debug level. Level 1 prints info about each RX/TX packet.
.TP
.B -m mtu .B -m mtu
Set 'mtu' as mtu size for the tunnel device. This will be sent to the client Set 'mtu' as mtu size for the tunnel device. This will be sent to the client
on connect, and the client will use the same mtu. on connect, and the client will use the same mtu.
@ -93,7 +105,8 @@ You must make sure the dns requests are forwarded to this port yourself.
.B nameserver .B nameserver
The nameserver to use to relay the dns traffic. This can be any relaying The nameserver to use to relay the dns traffic. This can be any relaying
nameserver or the ip number of the server running iodined if reachable. nameserver or the ip number of the server running iodined if reachable.
Normally, you should specify a nameserver from your This argument is optional, and if not specified a nameserver will be read
from the
.I /etc/resolv.conf .I /etc/resolv.conf
file. file.
.TP .TP
@ -121,13 +134,13 @@ the same on both the client and the server.
.TP .TP
Try it out within your own LAN! Follow these simple steps: Try it out within your own LAN! Follow these simple steps:
.TP .TP
- On your server, run: ./iodined -f 10.0.0.1 test.asdf - On your server, run: ./iodined \-f 10.0.0.1 test.asdf
(If you already use the 10.0.0.0 network, use another internal net like (If you already use the 10.0.0.0 network, use another internal net like
172.16.0.0) 172.16.0.0)
.TP .TP
- Enter a password - Enter a password
.TP .TP
- On the client, run: ./iodine -f 192.168.0.1 test.asdf - On the client, run: ./iodine \-f 192.168.0.1 test.asdf
(Replace 192.168.0.1 with the server's ip address) (Replace 192.168.0.1 with the server's ip address)
.TP .TP
- Enter the same password - Enter the same password
@ -157,10 +170,10 @@ tunnel1 IN NS tunnel1host.mytunnel.com.
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
to your server. Start iodined on the server. The first argument is the tunnel to your server. Start iodined on the server. The first argument is the tunnel
IP address (like 192.168.99.1) and the second is the assigned domain (in this IP address (like 192.168.99.1) and the second is the assigned domain (in this
case tunnel1.mytunnel.com). The -f argument will keep iodined running in the case tunnel1.mytunnel.com). The \-f argument will keep iodined running in the
foreground, which helps when testing. iodined will start a virtual interface, foreground, which helps when testing. iodined will start a virtual interface,
and also start listening for DNS queries on UDP port 53. Either enter a and also start listening for DNS queries on UDP port 53. Either enter a
password on the commandline (-P pass) or after the server has started. Now password on the commandline (\-P pass) or after the server has started. Now
everything is ready for the client. everything is ready for the client.
.TP .TP
.B Client side: .B Client side:
@ -179,6 +192,12 @@ The normal case is to route all traffic through the DNS tunnel. To do this, firs
add a route to the nameserver you use with the default gateway as gateway. Then add a route to the nameserver you use with the default gateway as gateway. Then
replace the default gateway with the servers IP address within the DNS tunnel, replace the default gateway with the servers IP address within the DNS tunnel,
and configure the server to do NAT. and configure the server to do NAT.
.TP
.B MTU issues:
Some relaying DNS servers enforce a 512 byte packet limit. All larger packets are
simply dropped. If you can ping through the tunnel but not login via SSH, this is
most likely the case. Set the MTU on the server to 220 to ensure that all packets
are less than 512 bytes. This will however greatly affect performance.
.SH BUGS .SH BUGS
File bugs at http://dev.kryo.se/iodine/ File bugs at http://dev.kryo.se/iodine/
.SH AUTHORS .SH AUTHORS

View File

@ -1,29 +1,30 @@
CC = gcc CC = gcc
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o
CLIENTOBJS = iodine.o
CLIENT = ../bin/iodine CLIENT = ../bin/iodine
CLIENTOBJS = iodine.o tun.o dns.o read.o encoding.o login.o base32.o md5.o common.o SERVEROBJS = iodined.o user.o
SERVER = ../bin/iodined SERVER = ../bin/iodined
SERVEROBJS = iodined.o tun.o dns.o read.o encoding.o login.o base32.o md5.o common.o user.o
OS = `uname | tr "a-z" "A-Z"` OS = `uname | tr "a-z" "A-Z"`
ARCH = `uname -m` ARCH = `uname -m`
LDFLAGS = -lz LDFLAGS = -lz `sh osflags link`
CFLAGS = -c -g -Wall -D$(OS) -pedantic CFLAGS = -c -g -Wall -D$(OS) -pedantic
all: stateos $(CLIENT) $(SERVER) $(TESTSUITE) all: stateos $(CLIENT) $(SERVER)
stateos: stateos:
@echo OS is $(OS), arch is $(ARCH) @echo OS is $(OS), arch is $(ARCH)
$(CLIENT): $(CLIENTOBJS) $(CLIENT): $(COMMONOBJS) $(CLIENTOBJS)
@echo LD $@ @echo LD $@
@mkdir -p ../bin @mkdir -p ../bin
@$(CC) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS) @$(CC) $(COMMONOBJS) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
$(SERVER): $(SERVEROBJS) $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
@echo LD $@ @echo LD $@
@mkdir -p ../bin @mkdir -p ../bin
@$(CC) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS) @$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
.c.o: .c.o:
@echo CC $< @echo CC $<

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -18,140 +18,160 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "encoding.h"
#include "base32.h" #include "base32.h"
static const char cb32[] = static const char cb32[] =
"abcdefghijklmnopqrstuvwxyz0123456789"; "abcdefghijklmnopqrstuvwxyz0123456789";
static unsigned char rev32[128];
static int reverse_init = 0;
static struct encoder base32_encoder =
{
"BASE32",
base32_encode,
base32_decode,
base32_handles_dots,
base32_handles_dots
};
struct encoder
*get_base32_encoder()
{
return &base32_encoder;
}
int int
base32_encode(char **buf, size_t *buflen, const void *data, size_t size) base32_handles_dots()
{
return 0;
}
int
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
{ {
size_t newsize; size_t newsize;
char *newbuf; size_t maxsize;
char *s; unsigned char *s;
char *p; unsigned char *p;
char *q; unsigned char *q;
int i; int i;
newsize = 8 * (size / 5 + 1) + 1; memset(buf, 0, *buflen);
if (newsize > *buflen) {
if ((newbuf = realloc(*buf, newsize)) == NULL) {
free(*buf);
*buf = NULL;
*buflen = 0;
return 0;
}
*buf = newbuf; /* how many chars can we encode within the buf */
*buflen = newsize; maxsize = 5 * (*buflen / 8 - 1) - 1;
/* how big will the encoded data be */
newsize = 8 * (size / 5 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
} }
p = s = *buf; p = s = (unsigned char *) buf;
q = (char*)data; q = (unsigned char *)data;
for(i=0;i<size;i+=5) { for(i=0;i<size;i+=5) {
p[0] = cb32[(q[0] >> 3)]; p[0] = cb32[((q[0] & 0xf8) >> 3)];
p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)]; p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0'; p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0'; p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0'; p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0'; p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0'; p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0'; p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
q += 5; q += 5;
p += 8; p += 8;
} }
*p = 0; *p = 0;
return strlen(s);
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf) - 1;
} }
#define DECODE_ERROR 0xffffffff #define DECODE_ERROR 0xffffffff
#define REV32(x) rev32[(int) (x)]
static int static int
pos(char c) decode_token(const unsigned char *t, unsigned char *data, size_t len)
{ {
const char *p;
for (p = cb32; *p; p++)
if (*p == c)
return p - cb32;
return -1;
}
static int
decode_token(const char *t, char *data)
{
int len;
len = strlen(t);
if (len < 2) if (len < 2)
return 0; return 0;
data[0] = ((pos(t[0]) & 0x1f) << 3) | data[0] = ((REV32(t[0]) & 0x1f) << 3) |
((pos(t[1]) & 0x1c) >> 2); ((REV32(t[1]) & 0x1c) >> 2);
if (len < 4) if (len < 4)
return 1; return 1;
data[1] = ((pos(t[1]) & 0x03) << 6) | data[1] = ((REV32(t[1]) & 0x03) << 6) |
((pos(t[2]) & 0x1f) << 1) | ((REV32(t[2]) & 0x1f) << 1) |
((pos(t[3]) & 0x10) >> 4); ((REV32(t[3]) & 0x10) >> 4);
if (len < 5) if (len < 5)
return 2; return 2;
data[2] = ((pos(t[3]) & 0x0f) << 4) | data[2] = ((REV32(t[3]) & 0x0f) << 4) |
((pos(t[4]) & 0x1e) >> 1); ((REV32(t[4]) & 0x1e) >> 1);
if (len < 7) if (len < 7)
return 3; return 3;
data[3] = ((pos(t[4]) & 0x01) << 7) | data[3] = ((REV32(t[4]) & 0x01) << 7) |
((pos(t[5]) & 0x1f) << 2) | ((REV32(t[5]) & 0x1f) << 2) |
((pos(t[6]) & 0x18) >> 3); ((REV32(t[6]) & 0x18) >> 3);
if (len < 8) if (len < 8)
return 4; return 4;
data[4] = ((pos(t[6]) & 0x07) << 5) | data[4] = ((REV32(t[6]) & 0x07) << 5) |
((pos(t[7]) & 0x1f)); ((REV32(t[7]) & 0x1f));
return 5; return 5;
} }
int int
base32_decode(void **buf, size_t *buflen, const char *str) base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{ {
unsigned char *q; unsigned char *q;
size_t newsize; size_t newsize;
size_t maxsize;
const char *p; const char *p;
char *newbuf; unsigned char c;
int len; int len;
int i;
newsize = 5 * (strlen(str) / 8 + 1) + 1;
if (newsize > *buflen) {
if ((newbuf = realloc(*buf, newsize)) == NULL) {
free(*buf);
*buf = NULL;
*buflen = 0;
return 0;
}
*buf = newbuf; if (!reverse_init) {
*buflen = newsize; for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
/* chars needed to decode slen */
newsize = 5 * (slen / 8 + 1) + 1;
/* encoded chars that fit in buf */
maxsize = 8 * (*buflen / 5 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
} }
q = *buf; q = buf;
for (p = str; *p && strchr(cb32, *p); p += 8) { for (p = str; *p && strchr(cb32, *p); p += 8) {
len = decode_token(p, (char *) q); len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
q += len; q += len;
slen -= 8;
if (len < 5) if (len < 5)
break; break;
} }
*q = '\0'; *q = '\0';
return q - (unsigned char *) *buf; return q - (unsigned char *) buf;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -17,7 +17,9 @@
#ifndef __BASE32_H__ #ifndef __BASE32_H__
#define __BASE32_H__ #define __BASE32_H__
int base32_encode(char **, size_t *, const void *, size_t); struct encoder *get_base32_encoder(void);
int base32_decode(void **, size_t *, const char *); int base32_handles_dots();
int base32_encode(char *, size_t *, const void *, size_t);
int base32_decode(void *, size_t *, const char *, size_t);
#endif #endif

338
src/base64.c Normal file
View File

@ -0,0 +1,338 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encoding.h"
#include "common.h"
#include "base64.h"
static const char cb64[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.";
static unsigned char rev64[128];
static int reverse_init = 0;
#define REV64(x) rev64[(int) (x)]
#define MODE (cb64[62])
#define P62 (cb64[62])
#define P63 (cb64[63])
static struct encoder base64_encoder =
{
"BASE64",
base64_encode,
base64_decode,
base64_handles_dots,
base64_handles_dots
};
struct encoder
*get_base64_encoder()
{
return &base64_encoder;
}
int
base64_handles_dots()
{
return 0;
}
static void
findesc(int *count, unsigned char *esc, char c1, char c2, char c3, char c4)
{
int min1 = 0;
int min2 = 0;
int num1 = 0xFF; /* a very big number */
int num2 = 0xFE; /* a nearly as big number */
int i;
/* check if no more escapes needed */
if (count[62] == 0 && count[63] == 0) {
esc[0] = MODE;
esc[1] = MODE;
return;
}
for (i = 0; i < 62; i++) {
if (i == c1 || i == c2 || i == c3 || i == c4) {
continue;
}
if (count[i] < num1) {
min2 = min1;
num2 = num1;
min1 = i;
num1 = count[i];
} else if (count[i] < num2) {
min2 = i;
num2 = count[i];
}
}
esc[0] = cb64[min1];
esc[1] = cb64[min2];
}
static void
escape_chars(char *buf, size_t buflen)
{
int counter[64];
int escapes;
int reset;
int i;
unsigned char temp[4096];
unsigned char *r;
unsigned char *w;
unsigned char *e;
unsigned char esc[2];
memset(counter, 0, sizeof(counter));
esc[0] = P62;
esc[1] = P63;
/* first, find the number of times each token is used */
r = (unsigned char *) buf;
w = temp;
while (*r) {
counter[REV64(*r)]++;
*w++ = *r++;
}
/* check if work needed */
if (counter[62] == 0 && counter[63] == 0)
return;
r = temp;
w = (unsigned char *) buf;
reset = 1;
escapes = 0;
/* check a block for esc chars */
while (*r) {
if (reset == 0 && escapes == 0 && (
r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1])) {
/* last set of escape chars were unused.
* if we reset last escape switch then maybe we dont have to switch now */
/* change the latest escape switch to 999 (RESET) */
e[1] = MODE;
e[2] = MODE;
/* store default esc chars */
esc[0] = P62;
esc[1] = P63;
reset = 1;
}
/* these two if blocks can not be combined because a block can contain both
* char 9 and/or . and the current escape chars. */
if (r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1]) {
/* switch escape chars */
escapes = 0;
reset = 0;
/* find 2 suitable escape chars */
findesc(counter, esc, REV64(r[0]), REV64(r[1]), REV64(r[2]), REV64(r[3]));
/* store escape switch position */
e = w;
/* write new escape chars */
*w++ = MODE;
*w++ = esc[0];
*w++ = esc[1];
}
/* update counter on remaining chars */
for (i = 0; i < 4; i++) {
if (r[i])
counter[REV64(r[i])]--;
}
/* do the escaping */
for (i = 0; i < 4; i++) {
if (r[i] == P62) {
r[i] = esc[0];
escapes++;
} else if (r[i] == P63) {
r[i] = esc[1];
escapes++;
}
}
/* copy back to buf */
*w++ = *r++;
*w++ = *r++;
*w++ = *r++;
*w++ = *r++;
}
}
int
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
{
size_t newsize;
size_t maxsize;
unsigned char c;
unsigned char *s;
unsigned char *p;
unsigned char *q;
int i;
memset(buf, 0, *buflen);
if (!reverse_init) {
for (i = 0; i < 64; i++) {
c = cb64[i];
rev64[(int) c] = i;
}
reverse_init = 1;
}
/* how many chars can we encode within the buf */
maxsize = 3 * (*buflen / 4 - 1) - 1;
/* how big will the encoded data be */
newsize = 4 * (size / 3 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
}
p = s = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=3) {
p[0] = cb64[((q[0] & 0xfc) >> 2)];
p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
q += 3;
p += 4;
}
*p = 0;
escape_chars(buf, *buflen);
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf) - 1;
}
#define DECODE_ERROR 0xffffffff
static int
decode_token(const unsigned char *t, unsigned char *data, size_t len)
{
if (len < 2)
return 0;
data[0] = ((REV64(t[0]) & 0x3f) << 2) |
((REV64(t[1]) & 0x30) >> 4);
if (len < 3)
return 1;
data[1] = ((REV64(t[1]) & 0x0f) << 4) |
((REV64(t[2]) & 0x3c) >> 2);
if (len < 4)
return 2;
data[2] = ((REV64(t[2]) & 0x03) << 6) |
(REV64(t[3]) & 0x3f);
return 3;
}
int
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{
unsigned char *q;
size_t newsize;
size_t maxsize;
const char *p;
unsigned char c;
unsigned char block[4];
unsigned char prot62;
unsigned char prot63;
int len;
int i;
if (!reverse_init) {
for (i = 0; i < 64; i++) {
c = cb64[i];
rev64[(int) c] = i;
}
reverse_init = 1;
}
/* chars needed to decode slen */
newsize = 3 * (slen / 4 + 1) + 1;
/* encoded chars that fit in buf */
maxsize = 4 * (*buflen / 3 + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
prot62 = P62;
prot63 = P63;
q = buf;
for (p = str; *p; p += 4) {
/* handle escape instructions */
if (*p == MODE) {
p++;
if (p[0] == MODE && p[1] == MODE) {
/* reset escape chars */
prot62 = P62;
prot63 = P63;
p += 2;
} else {
prot62 = *p++;
prot63 = *p++;
}
}
/* since the str is const, we unescape in another buf */
for (i = 0; i < 4; i++) {
block[i] = p[i];
if (prot62 == block[i]) {
block[i] = P62;
} else if (prot63 == block[i]) {
block[i] = P63;
}
}
len = decode_token(block, (unsigned char *) q, slen);
q += len;
slen -= 4;
if (len < 3)
break;
}
*q = '\0';
return q - (unsigned char *) buf;
}

25
src/base64.h Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __BASE64_H__
#define __BASE64_H__
struct encoder *get_base64_encoder(void);
int base64_handles_dots();
int base64_encode(char *, size_t *, const void *, size_t);
int base64_decode(void *, size_t *, const char *, size_t);
#endif

View File

@ -1,4 +1,5 @@
/* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> /* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -21,6 +22,8 @@
#endif #endif
#include <time.h> #include <time.h>
#include <err.h> #include <err.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -29,9 +32,48 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h>
#include <termios.h>
#include "common.h" #include "common.h"
/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
#if !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
static int daemon(int nochdir, int noclose)
{
int fd, i;
switch (fork()) {
case 0:
break;
case -1:
return -1;
default:
_exit(0);
}
if (!nochdir) {
chdir("/");
}
if (setsid() < 0) {
return -1;
}
if (!noclose) {
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
for (i = 0; i < 3; i++) {
dup2(fd, i);
}
if (fd > 2) {
close(fd);
}
}
}
return 0;
}
#endif
int int
open_dns(int localport, in_addr_t listen_ip) open_dns(int localport, in_addr_t listen_ip)
{ {
@ -71,13 +113,11 @@ close_dns(int fd)
void void
do_chroot(char *newroot) do_chroot(char *newroot)
{ {
if (newroot) { if (chroot(newroot) != 0 || chdir("/") != 0)
if (chroot(newroot) != 0 || chdir("/") != 0) err(1, "%s", newroot);
err(1, "%s", newroot);
seteuid(geteuid()); seteuid(geteuid());
setuid(getuid()); setuid(getuid());
}
} }
void void
@ -88,3 +128,44 @@ do_detach()
umask(0); umask(0);
alarm(0); alarm(0);
} }
void
read_password(char *buf, size_t len)
{
struct termios old;
struct termios tp;
char pwd[80];
tcgetattr(0, &tp);
old = tp;
tp.c_lflag &= (~ECHO);
tcsetattr(0, TCSANOW, &tp);
printf("Enter password: ");
fflush(stdout);
scanf("%79s", pwd);
printf("\n");
tcsetattr(0, TCSANOW, &old);
strncpy(buf, pwd, len);
buf[len-1] = '\0';
}
int
check_topdomain(char *str)
{
int i;
if(str[0] == '.') /* special case */
return 1;
for( i = 0; i < strlen(str); i++) {
if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
continue;
else
return 1;
}
return 0;
}

View File

@ -17,6 +17,7 @@
#ifndef __COMMON_H__ #ifndef __COMMON_H__
#define __COMMON_H__ #define __COMMON_H__
#include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -27,15 +28,18 @@
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
#endif #endif
#define QUERY_NAME_SIZE 256
struct packet struct packet
{ {
int len; int len; /* Total packet length */
int offset; int sentlen; /* Length of chunk currently transmitted */
char data[64*1024]; int offset; /* Current offset */
char data[64*1024]; /* The data */
}; };
struct query { struct query {
char name[258]; char name[QUERY_NAME_SIZE];
short type; short type;
short id; short id;
struct sockaddr from; struct sockaddr from;
@ -48,4 +52,8 @@ void close_dns(int);
void do_chroot(char *); void do_chroot(char *);
void do_detach(); void do_detach();
void read_password(char*, size_t);
int check_topdomain(char *);
#endif #endif

View File

@ -61,7 +61,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
name = 0xc000 | ((p - buf) & 0x3fff); name = 0xc000 | ((p - buf) & 0x3fff);
putname(&p, 256, q->name); putname(&p, sizeof(q->name), q->name);
putshort(&p, q->type); putshort(&p, q->type);
putshort(&p, C_IN); putshort(&p, C_IN);
@ -78,7 +78,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
header->qdcount = htons(1); header->qdcount = htons(1);
header->arcount = htons(1); header->arcount = htons(1);
putname(&p, 256, data); putname(&p, datalen, data);
putshort(&p, q->type); putshort(&p, q->type);
putshort(&p, C_IN); putshort(&p, C_IN);
@ -101,11 +101,11 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
int int
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
{ {
char name[QUERY_NAME_SIZE];
char rdata[4*1024]; char rdata[4*1024];
HEADER *header; HEADER *header;
short qdcount; short qdcount;
short ancount; short ancount;
char name[255];
uint32_t ttl; uint32_t ttl;
short class; short class;
short type; short type;
@ -137,7 +137,28 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
switch (qr) { switch (qr) {
case QR_ANSWER: case QR_ANSWER:
if(qdcount != 1 || ancount != 1) { if(qdcount != 1 || ancount != 1) {
warnx("no query or answer in answer"); switch (header->rcode) {
case REFUSED:
warnx("Got REFUSED as reply");
break;
case NOTIMP:
warnx("Got NOTIMP as reply");
break;
case NXDOMAIN:
warnx("Got NXDOMAIN as reply");
break;
case SERVFAIL:
warnx("Got SERVFAIL as reply");
break;
case NOERROR:
default:
warnx("no query or answer in reply packet");
break;
}
return -1; return -1;
} }
@ -156,7 +177,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
rv = MIN(rlen, sizeof(rdata)); rv = MIN(rlen, sizeof(rdata));
rv = readdata(packet, &data, rdata, rv); rv = readdata(packet, &data, rdata, rv);
if(type == T_NULL && rv > 2) { if(type == T_NULL && rv > 2 && buf) {
rv = MIN(rv, buflen); rv = MIN(rv, buflen);
memcpy(buf, rdata, rv); memcpy(buf, rdata, rv);
} }
@ -167,17 +188,13 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
return -1; return -1;
} }
readname(packet, packetlen, &data, name, sizeof(name) -1); readname(packet, packetlen, &data, name, sizeof(name) - 1);
name[256] = 0; name[sizeof(name)-1] = '\0';
readshort(packet, &data, &type); readshort(packet, &data, &type);
readshort(packet, &data, &class); readshort(packet, &data, &class);
if(type != T_NULL) { strncpy(q->name, name, sizeof(q->name));
rv = 0; q->name[sizeof(q->name) - 1] = '\0';
break;
}
strncpy(q->name, name, 257);
q->type = type; q->type = type;
q->id = id; q->id = id;
@ -188,27 +205,3 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
return rv; return rv;
} }
int
dns_build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain)
{
int consumed;
int avail;
char *b;
avail = MIN(0xFF, buflen) - strlen(topdomain) - 2;
memset(buf, 0, buflen);
b = buf;
consumed = encode_data(data, datalen, avail, b);
b += strlen(buf);
if (*b != '.')
*b++ = '.';
strncpy(b, topdomain, strlen(topdomain)+1);
return consumed;
}

View File

@ -24,8 +24,6 @@ typedef enum {
QR_ANSWER = 1 QR_ANSWER = 1
} qr_t; } qr_t;
int dns_build_hostname(char *, size_t, const char *, const size_t, const char *);
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t); int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t); int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);

View File

@ -14,207 +14,80 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <stdio.h>
#include <strings.h>
#include <string.h> #include <string.h>
#include "encoding.h"
/* For FreeBSD */
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#define SPACING 63
#define ENC_CHUNK 8
#define RAW_CHUNK 5
static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-";
static const char padder[] = " 1234";
static char reverse32[128];
static int reverse_init = 0;
/* Eat 5 bytes from src, write 8 bytes to dest */
static void
encode_chunk(char *dest, const char *src)
{
unsigned char c;
*dest++ = base32[(*src & 0xF8) >> 3]; /* 1111 1000 first byte */
c = (*src++ & 0x07) << 2; /* 0000 0111 first byte */
c |= ((*src & 0xC0) >> 6); /* 1100 0000 second byte */
*dest++ = base32[(int) c];
*dest++ = base32[(*src & 0x3E) >> 1]; /* 0011 1110 second byte */
c = (*src++ & 0x01) << 4; /* 0000 0001 second byte */
c |= ((*src & 0xF0) >> 4); /* 1111 0000 third byte */
*dest++ = base32[(int) c];
c = (*src++ & 0x0F) << 1; /* 0000 1111 third byte */
c |= ((*src & 0x80) >> 7); /* 1000 0000 fourth byte */
*dest++ = base32[(int) c];
*dest++ = base32[(*src & 0x7C) >> 2]; /* 0111 1100 fourth byte */
c = (*src++ & 0x03) << 3; /* 0000 0011 fourth byte */
c |= ((*src & 0xE0) >> 5); /* 1110 0000 fifth byte */
*dest++ = base32[(int) c];
*dest++ = base32[*src++ & 0x1F]; /* 0001 1111 fifth byte */
}
/* Eat 8 bytes from src, write 5 bytes to dest */
static void
decode_chunk(char *dest, char *src)
{
unsigned char c;
int i;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = base32[i];
reverse32[(int) c] = i;
}
reverse_init = 1;
}
c = reverse32[(int) *src++] << 3; /* Take bits 11111 from byte 1 */
c |= (reverse32[(int) *src] & 0x1C) >> 2; /* Take bits 11100 from byte 2 */
*dest++ = c;
c = (reverse32[(int) *src++] & 0x3) << 6; /* Take bits 00011 from byte 2 */
c |= reverse32[(int) *src++] << 1; /* Take bits 11111 from byte 3 */
c |= (reverse32[(int) *src] & 0x10) >> 4; /* Take bits 10000 from byte 4 */
*dest++ = c;
c = (reverse32[(int) *src++] & 0xF) << 4; /* Take bits 01111 from byte 4 */
c |= (reverse32[(int) *src] & 0x1E) >> 1; /* Take bits 11110 from byte 5 */
*dest++ = c;
c = reverse32[(int) *src++] << 7; /* Take bits 00001 from byte 5 */
c |= reverse32[(int) *src++] << 2; /* Take bits 11111 from byte 6 */
c |= (reverse32[(int) *src] & 0x18) >> 3; /* Take bits 11000 from byte 7 */
*dest++ = c;
c = (reverse32[(int) *src++] & 0x7) << 5; /* Take bits 00111 from byte 7 */
c |= reverse32[(int) *src++]; /* Take bits 11111 from byte 8 */
*dest++ = c;
}
int int
encode_data(const char *buf, const size_t len, int space, char *dest) unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
{ {
int final; if (!enc->eats_dots())
int write; datalen = inline_undotify(data, datalen);
int realwrite; return enc->decode(buf, &buflen, data, datalen);
int chunks;
int leftovers;
int i;
char encoded[255];
char padding[5];
const char *dp;
char *pp;
char *ep;
space -= space / SPACING;
chunks = (space - 1) / ENC_CHUNK;
while ((chunks + 1) * ENC_CHUNK + 1 > space) {
chunks--;
}
write = RAW_CHUNK * chunks;
write = MIN(write, len); /* do not use more bytes than is available; */
final = (write == len); /* is this the last block? */
chunks = write / RAW_CHUNK;
leftovers = write % RAW_CHUNK;
memset(encoded, 0, sizeof(encoded));
ep = encoded;
dp = buf;
for (i = 0; i < chunks; i++) {
encode_chunk(ep, dp);
ep += ENC_CHUNK;
dp += RAW_CHUNK;
}
realwrite = ENC_CHUNK * chunks;
memset(padding, 0, sizeof(padding));
pp = padding;
if (leftovers) {
pp += RAW_CHUNK - leftovers;
memcpy(pp, dp, leftovers);
pp = padding;
*ep++ = padder[leftovers];
encode_chunk(ep, pp);
realwrite += ENC_CHUNK + 1; /* plus padding character */
}
ep = encoded;
if (len > 0) {
for (i = 1; i <= realwrite; i++) {
if (i % SPACING == 0) {
*dest++ = '.';
}
*dest++ = *ep++;
}
}
return write;
} }
int int
decode_data(char *dest, int size, const char *src, char *srcend) inline_dotify(char *buf, size_t buflen)
{ {
int len; unsigned dots;
int i; unsigned pos;
int chunks; unsigned total;
int padded; char *reader, *writer;
char encoded[255];
char padding[5];
int enclen;
char *pp;
char *ep;
memset(encoded, 0, sizeof(encoded)); total = strlen(buf);
memset(dest, 0, size); dots = total / 62;
/* First byte is not encoded */ writer = buf;
*dest++ = *src++; writer += total;
len = 1; writer += dots;
ep = encoded; total += dots;
enclen = 0; if (strlen(buf) + dots > buflen) {
while(enclen < sizeof(encoded) && src < srcend) { writer = buf;
if(*src == '.') { writer += buflen;
src++; total = buflen;
}
reader = writer - dots;
pos = (unsigned) (reader - buf) + 1;
while (dots) {
if (pos % 62 == 0) {
*writer-- = '.';
dots--;
}
*writer-- = *reader--;
pos--;
}
/* return new length of string */
return total;
}
int
inline_undotify(char *buf, size_t len)
{
unsigned pos;
unsigned dots;
char *reader, *writer;
writer = buf;
reader = writer;
pos = 0;
dots = 0;
while (pos < len) {
if (*reader == '.') {
reader++;
pos++;
dots++;
continue; continue;
} }
*writer++ = *reader++;
*ep++ = *src++; pos++;
enclen++;
} }
chunks = enclen / 8;
padded = enclen % 8; /* return new length of string */
return len - dots;
ep = encoded;
for (i = 0; i < chunks-1; i++) {
decode_chunk(dest, ep);
dest += RAW_CHUNK;
ep += ENC_CHUNK;
len += RAW_CHUNK;
}
/* Read last chunk */
if (padded) {
pp = padding;
padded = *ep++ - '0';
decode_chunk(pp, ep);
pp += RAW_CHUNK - padded;
memcpy(dest, pp, padded);
len += padded;
} else {
decode_chunk(dest, ep);
len += RAW_CHUNK;
}
return len;
} }

View File

@ -17,7 +17,17 @@
#ifndef _ENCODING_H_ #ifndef _ENCODING_H_
#define _ENCODING_H_ #define _ENCODING_H_
int encode_data(const char *, const size_t, int, char *); struct encoder {
int decode_data(char *, int, const char *, char *); char name[8];
int (*encode) (char *, size_t *, const void *, size_t);
int (*decode) (void *, size_t *, const char *, size_t);
int (*places_dots) (void);
int (*eats_dots) (void);
};
int unpack_data(char *, size_t, char *, size_t, struct encoder *);
int inline_dotify(char *, size_t);
int inline_undotify(char *, size_t);
#endif /* _ENCODING_H_ */ #endif /* _ENCODING_H_ */

View File

@ -23,9 +23,12 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h> #include <fcntl.h>
#include <err.h> #include <err.h>
#include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <zlib.h> #include <zlib.h>
@ -35,6 +38,8 @@
#endif #endif
#include "common.h" #include "common.h"
#include "encoding.h"
#include "base32.h"
#include "dns.h" #include "dns.h"
#include "login.h" #include "login.h"
#include "tun.h" #include "tun.h"
@ -42,23 +47,41 @@
static void send_ping(int fd); static void send_ping(int fd);
static void send_chunk(int fd); static void send_chunk(int fd);
static int build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain, struct encoder *encoder);
int running = 1; static int running = 1;
char password[33]; static char password[33];
struct sockaddr_in peer; static struct sockaddr_in nameserv;
static char *topdomain; static char *topdomain;
uint16_t rand_seed; static uint16_t rand_seed;
/* Current IP packet */ /* Current IP packet */
static char activepacket[4096]; static struct packet packet;
/* My userid at the server */
static char userid; static char userid;
static int lastlen;
static int packetpos; /* DNS id for next packet */
static int packetlen;
static uint16_t chunkid; static uint16_t chunkid;
/* Base32 encoder used for non-data packets */
static struct encoder *b32;
/* The encoder used for data packets
* Defaults to Base32, can be changed after handshake */
static struct encoder *dataenc;
/* result of case preservation check done after login */
static int case_preserved;
#if !defined(BSD) && !defined(__GLIBC__)
static char *__progname;
#endif
static void static void
sighandler(int sig) sighandler(int sig)
{ {
@ -66,57 +89,96 @@ sighandler(int sig)
} }
static void static void
send_packet(int fd, char cmd, const char *data, const size_t datalen) send_query(int fd, char *hostname)
{ {
char packet[4096]; char packet[4096];
struct query q; struct query q;
char buf[4096];
size_t len; size_t len;
q.id = ++chunkid; q.id = ++chunkid;
q.type = T_NULL; q.type = T_NULL;
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname));
sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv));
}
static void
send_packet(int fd, char cmd, const char *data, const size_t datalen)
{
char buf[4096];
buf[0] = cmd; buf[0] = cmd;
len = dns_build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain); build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32);
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf)); send_query(fd, buf);
}
sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer)); static int
build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain, struct encoder *encoder)
{
int encsize;
size_t space;
char *b;
space = MIN(0xFF, buflen) - strlen(topdomain) - 2;
if (!encoder->places_dots())
space -= (space / 62); /* space for dots */
memset(buf, 0, buflen);
encsize = encoder->encode(buf, &space, data, datalen);
if (!encoder->places_dots())
inline_dotify(buf, buflen);
b = buf;
b += strlen(buf);
if (*b != '.')
*b++ = '.';
strncpy(b, topdomain, strlen(topdomain)+1);
return space;
} }
int int
is_sending() is_sending()
{ {
return (packetlen != 0); return (packet.len != 0);
} }
int int
read_dns(int fd, char *buf, int buflen) read_dns(int fd, char *buf, int buflen)
{ {
struct sockaddr_in from; struct sockaddr_in from;
char packet[64*1024]; char data[64*1024];
socklen_t addrlen; socklen_t addrlen;
struct query q; struct query q;
int rv; int rv;
int r; int r;
addrlen = sizeof(struct sockaddr); addrlen = sizeof(struct sockaddr);
if ((r = recvfrom(fd, packet, sizeof(packet), 0, if ((r = recvfrom(fd, data, sizeof(data), 0,
(struct sockaddr*)&from, &addrlen)) == -1) { (struct sockaddr*)&from, &addrlen)) == -1) {
warn("recvfrom"); warn("recvfrom");
return 0; return 0;
} }
rv = dns_decode(buf, buflen, &q, QR_ANSWER, packet, r); rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r);
if (is_sending() && chunkid == q.id) { if (is_sending() && chunkid == q.id) {
/* Got ACK on sent packet */ /* Got ACK on sent packet */
packetpos += lastlen; packet.offset += packet.sentlen;
if (packetpos == packetlen) { if (packet.offset == packet.len) {
/* Packet completed */ /* Packet completed */
packetpos = 0; packet.offset = 0;
packetlen = 0; packet.len = 0;
lastlen = 0; packet.sentlen = 0;
} else { } else {
/* More to send */ /* More to send */
send_chunk(fd); send_chunk(fd);
@ -142,10 +204,10 @@ tunnel_tun(int tun_fd, int dns_fd)
inlen = read; inlen = read;
compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9); compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
memcpy(activepacket, out, MIN(outlen, sizeof(activepacket))); memcpy(packet.data, out, MIN(outlen, sizeof(packet.data)));
lastlen = 0; packet.sentlen = 0;
packetpos = 0; packet.offset = 0;
packetlen = outlen; packet.len = outlen;
send_chunk(dns_fd); send_chunk(dns_fd);
@ -224,33 +286,26 @@ static void
send_chunk(int fd) send_chunk(int fd)
{ {
char hex[] = "0123456789ABCDEF"; char hex[] = "0123456789ABCDEF";
char packet[4096];
struct query q;
char buf[4096]; char buf[4096];
int avail; int avail;
int code; int code;
char *p; char *p;
int len;
q.id = ++chunkid; p = packet.data;
q.type = T_NULL; p += packet.offset;
avail = packet.len - packet.offset;
p = activepacket; packet.sentlen = build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain, dataenc);
p += packetpos;
avail = packetlen - packetpos;
lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain); if (packet.sentlen == avail)
if (lastlen == avail)
code = 1; code = 1;
else else
code = 0; code = 0;
code |= (userid << 1); code |= (userid << 1);
buf[0] = hex[code]; buf[0] = hex[code];
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer)); send_query(fd, buf);
} }
void void
@ -276,9 +331,9 @@ send_ping(int fd)
char data[3]; char data[3];
if (is_sending()) { if (is_sending()) {
lastlen = 0; packet.sentlen = 0;
packetpos = 0; packet.offset = 0;
packetlen = 0; packet.len = 0;
} }
data[0] = userid; data[0] = userid;
@ -308,6 +363,15 @@ send_version(int fd, uint32_t version)
send_packet(fd, 'V', data, sizeof(data)); send_packet(fd, 'V', data, sizeof(data));
} }
void
send_case_check(int fd)
{
char buf[512] = "zZaAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY123-4560789.";
strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf);
}
static int static int
handshake(int dns_fd) handshake(int dns_fd)
{ {
@ -338,16 +402,19 @@ handshake(int dns_fd)
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, in, sizeof(in));
if(read < 0) { if(read <= 0) {
perror("read"); if (read == 0) {
warn("handshake read");
}
/* if read < 0 then warning has been printed already */
continue; continue;
} }
if (read >= 9) { if (read >= 9) {
payload = (((in[4] & 0xff) << 24) | payload = (((in[4] & 0xff) << 24) |
((in[5] & 0xff) << 16) | ((in[5] & 0xff) << 16) |
((in[6] & 0xff) << 8) | ((in[6] & 0xff) << 8) |
((in[7] & 0xff))); ((in[7] & 0xff)));
if (strncmp("VACK", in, 4) == 0) { if (strncmp("VACK", in, 4) == 0) {
seed = payload; seed = payload;
@ -405,7 +472,7 @@ perform_login:
client[64] = 0; client[64] = 0;
if (tun_setip(client) == 0 && if (tun_setip(client) == 0 &&
tun_setmtu(mtu) == 0) { tun_setmtu(mtu) == 0) {
return 0; goto perform_case_check;
} else { } else {
warnx("Received handshake with bad data"); warnx("Received handshake with bad data");
} }
@ -417,23 +484,98 @@ perform_login:
printf("Retrying login...\n"); printf("Retrying login...\n");
} }
errx(1, "couldn't login to server");
/* NOTREACHED */
return 1; perform_case_check:
case_preserved = 0;
for (i=0; running && i<5 ;i++) {
tv.tv_sec = i + 1;
tv.tv_usec = 0;
send_case_check(dns_fd);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if(read <= 0) {
warn("read");
continue;
}
if (read > 0) {
if (in[0] == 'z' || in[0] == 'Z') {
if (read < (26 * 2)) {
printf("Received short case reply...\n");
} else {
int k;
case_preserved = 1;
for (k = 0; k < 26 && case_preserved; k += 2) {
if (in[k] == in[k+1]) {
/* test string: zZaAbBcCdD... */
case_preserved = 0;
}
}
return 0;
}
} else {
printf("Received bad case check reply\n");
}
}
}
printf("Retrying case check...\n");
}
printf("No reply on case check, continuing\n");
return 0;
}
static char *
get_resolvconf_addr()
{
static char addr[16];
char buf[80];
char *rv;
FILE *fp;
rv = NULL;
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
err(1, "/etc/resolve.conf");
while (feof(fp) == 0) {
fgets(buf, sizeof(buf), fp);
if (sscanf(buf, "nameserver %15s", addr) == 1) {
rv = addr;
break;
}
}
fclose(fp);
return rv;
} }
static void static void
set_target(const char *host) set_nameserver(const char *cp)
{ {
struct hostent *h; struct in_addr addr;
h = gethostbyname(host); if (inet_aton(cp, &addr) != 1)
if (!h) errx(1, "error parsing nameserver address: '%s'", cp);
err(1, "couldn't resolve name %s", host);
memset(&peer, 0, sizeof(peer)); memset(&nameserv, 0, sizeof(nameserv));
peer.sin_family = AF_INET; nameserv.sin_family = AF_INET;
peer.sin_port = htons(53); nameserv.sin_port = htons(53);
peer.sin_addr = *((struct in_addr *) h->h_addr); nameserv.sin_addr = addr;
} }
static void static void
@ -441,7 +583,7 @@ usage() {
extern char *__progname; extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] " printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"nameserver topdomain\n", __progname); "[nameserver] topdomain\n", __progname);
exit(2); exit(2);
} }
@ -451,7 +593,7 @@ help() {
printf("iodine IP over DNS tunneling client\n"); printf("iodine IP over DNS tunneling client\n");
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] " printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"[-P password] nameserver topdomain\n", __progname); "[-P password] [nameserver] 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");
@ -459,7 +601,7 @@ help() {
printf(" -t dir to chroot to directory dir\n"); printf(" -t dir to chroot to directory dir\n");
printf(" -d device to set tunnel device name\n"); printf(" -d device to set tunnel device name\n");
printf(" -P password used for authentication (max 32 chars will be used)\n"); printf(" -P password used for authentication (max 32 chars will be used)\n");
printf("nameserver is the IP number of the relaying nameserver\n"); printf("nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n"); printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
exit(0); exit(0);
@ -467,12 +609,9 @@ help() {
static void static void
version() { version() {
char *svnver;
svnver = "$Rev$ from $Date$";
printf("iodine IP over DNS tunneling client\n"); printf("iodine IP over DNS tunneling client\n");
printf("SVN version: %s\n", svnver); printf("version: 0.4.2 from 2008-08-06\n");
exit(0); exit(0);
} }
@ -480,6 +619,7 @@ version() {
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
char *nameserv_addr;
struct passwd *pw; struct passwd *pw;
char *username; char *username;
int foreground; int foreground;
@ -495,7 +635,18 @@ main(int argc, char **argv)
newroot = NULL; newroot = NULL;
device = NULL; device = NULL;
chunkid = 0; chunkid = 0;
b32 = get_base32_encoder();
dataenc = get_base32_encoder();
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
#endif
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) { while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
switch(choice) { switch(choice) {
case 'v': case 'v':
@ -517,8 +668,11 @@ main(int argc, char **argv)
device = optarg; device = optarg;
break; break;
case 'P': case 'P':
strncpy(password, optarg, 32); strncpy(password, optarg, sizeof(password));
password[32] = 0; password[sizeof(password)-1] = 0;
/* XXX: find better way of cleaning up ps(1) */
memset(optarg, 0, strlen(optarg));
break; break;
default: default:
usage(); usage();
@ -527,37 +681,53 @@ main(int argc, char **argv)
} }
if (geteuid() != 0) { if (geteuid() != 0) {
printf("Run as root and you'll be happy.\n"); warnx("Run as root and you'll be happy.\n");
usage(); usage();
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc != 2) switch (argc) {
case 1:
nameserv_addr = get_resolvconf_addr();
topdomain = strdup(argv[0]);
break;
case 2:
nameserv_addr = argv[0];
topdomain = strdup(argv[1]);
break;
default:
usage(); usage();
/* NOTREACHED */
}
topdomain = strdup(argv[1]); set_nameserver(nameserv_addr);
if(username) { if(strlen(topdomain) <= 128) {
pw = getpwnam(username); if(check_topdomain(topdomain)) {
if (!pw) { warnx("Topdomain contains invalid characters.\n");
printf("User %s does not exist!\n", username); usage();
}
} else {
warnx("Use a topdomain max 128 chars long.\n");
usage();
}
if (username != NULL) {
if ((pw = getpwnam(username)) == NULL) {
warnx("User %s does not exist!\n", username);
usage(); usage();
} }
} }
if (strlen(password) == 0) { if (strlen(password) == 0)
printf("Enter password on stdin:\n"); read_password(password, sizeof(password));
scanf("%32s", password);
password[32] = 0;
}
if ((tun_fd = open_tun(device)) == -1) if ((tun_fd = open_tun(device)) == -1)
goto cleanup1; goto cleanup1;
if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
goto cleanup2; goto cleanup2;
set_target(argv[0]);
signal(SIGINT, sighandler); signal(SIGINT, sighandler);
signal(SIGTERM, sighandler); signal(SIGTERM, sighandler);
@ -565,21 +735,23 @@ main(int argc, char **argv)
if(handshake(dns_fd)) if(handshake(dns_fd))
goto cleanup2; goto cleanup2;
printf("Sending queries for %s to %s\n", argv[1], argv[0]); printf("Sending queries for %s to %s\n", topdomain, nameserv_addr);
do_chroot(newroot); if (foreground == 0)
do_detach();
if (newroot != NULL)
do_chroot(newroot);
if (username) { if (username != NULL) {
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) { gid_t gids[1];
printf("Could not switch to user %s!\n", username); gids[0] = pw->pw_gid;
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
warnx("Could not switch to user %s!\n", username);
usage(); usage();
} }
} }
if (!foreground) {
do_detach();
}
tunnel(tun_fd, dns_fd); tunnel(tun_fd, dns_fd);
cleanup2: cleanup2:

View File

@ -21,9 +21,12 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h> #include <fcntl.h>
#include <err.h> #include <err.h>
#include <grp.h>
#include <time.h> #include <time.h>
#include <pwd.h> #include <pwd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -31,25 +34,36 @@
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <zlib.h> #include <zlib.h>
#include <arpa/nameser.h>
#ifdef DARWIN
#include <arpa/nameser8_compat.h>
#endif
#include "common.h" #include "common.h"
#include "dns.h" #include "dns.h"
#include "encoding.h"
#include "base32.h"
#include "user.h" #include "user.h"
#include "login.h" #include "login.h"
#include "tun.h" #include "tun.h"
#include "encoding.h"
#include "version.h" #include "version.h"
int running = 1; static int running = 1;
static char *topdomain;
static char password[33];
static struct encoder *b32;
char *topdomain; static int check_ip;
static int my_mtu;
static in_addr_t my_ip;
char password[33]; static int debug;
int my_mtu; #if !defined(BSD) && !defined(__GLIBC__)
in_addr_t my_ip; static char *__progname;
#endif
static int read_dns(int, struct query *, char *, int); static int read_dns(int, struct query *);
static void write_dns(int, struct query *, char *, int); static void write_dns(int, struct query *, char *, int);
static void static void
@ -58,6 +72,15 @@ sigint(int sig)
running = 0; running = 0;
} }
static int
ip_cmp(int userid, struct query *q)
{
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
}
static int static int
tunnel_tun(int tun_fd, int dns_fd) tunnel_tun(int tun_fd, int dns_fd)
{ {
@ -117,77 +140,91 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *
out[5] = ((payload >> 16) & 0xff); out[5] = ((payload >> 16) & 0xff);
out[6] = ((payload >> 8) & 0xff); out[6] = ((payload >> 8) & 0xff);
out[7] = ((payload) & 0xff); out[7] = ((payload) & 0xff);
out[8] = u->id; if (u) {
out[8] = u->id;
} else {
out[8] = 0;
}
write_dns(fd, &u->q, out, sizeof(out)); write_dns(fd, &u->q, out, sizeof(out));
} }
static int static void
tunnel_dns(int tun_fd, int dns_fd) handle_null_request(int tun_fd, int dns_fd, struct query *q)
{ {
struct in_addr tempip; struct in_addr tempip;
struct user dummy;
struct ip *hdr; struct ip *hdr;
unsigned long outlen; unsigned long outlen;
char in[64*1024];
char logindata[16]; char logindata[16];
char out[64*1024]; char out[64*1024];
char in[64*1024]; char unpacked[64*1024];
char *tmp[2]; char *tmp[2];
char *domain;
int userid; int userid;
int touser; int touser;
int version; int version;
int read;
int code; int code;
int read;
userid = -1; userid = -1;
if ((read = read_dns(dns_fd, &(dummy.q), in, sizeof(in))) <= 0) domain = strstr(q->name, topdomain);
return 0; if (!domain) {
/* Not for us, discard */
return;
}
read = (int) (domain - q->name);
memcpy(in, q->name, MIN(read, sizeof(in)));
if(in[0] == 'V' || in[0] == 'v') { if(in[0] == 'V' || in[0] == 'v') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Version greeting, compare and send ack/nak */ /* Version greeting, compare and send ack/nak */
if (read > 4) { if (read > 4) {
/* Received V + 32bits version */ /* Received V + 32bits version */
version = (((unpacked[0] & 0xff) << 24) |
((unpacked[1] & 0xff) << 16) |
((unpacked[2] & 0xff) << 8) |
((unpacked[3] & 0xff)));
}
version = (((in[1] & 0xff) << 24) | if (version == VERSION) {
((in[2] & 0xff) << 16) | userid = find_available_user();
((in[3] & 0xff) << 8) | if (userid >= 0) {
((in[4] & 0xff))); struct sockaddr_in *tempin;
if (version == VERSION) { users[userid].seed = rand();
userid = find_available_user(); /* Store remote IP number */
if (userid >= 0) { tempin = (struct sockaddr_in *) &(q->from);
users[userid].seed = rand(); memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query)); memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].addrlen = dummy.q.fromlen; users[userid].encoder = get_base32_encoder();
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]); send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
users[userid].q.id = 0; users[userid].q.id = 0;
} else {
/* No space for another user */
send_version_response(dns_fd, VERSION_FULL, USERS, &dummy);
}
} else { } else {
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy); /* No space for another user */
send_version_response(dns_fd, VERSION_FULL, USERS, NULL);
} }
} else { } else {
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy); send_version_response(dns_fd, VERSION_NACK, VERSION, NULL);
} }
} else if(in[0] == 'L' || in[0] == 'l') { } else if(in[0] == 'L' || in[0] == 'l') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Login phase, handle auth */ /* Login phase, handle auth */
userid = in[1]; userid = unpacked[0];
if (userid < 0 || userid >= USERS) { if (userid < 0 || userid >= USERS) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5); write_dns(dns_fd, q, "BADIP", 5);
return 0; /* illegal id */ return; /* illegal id */
} }
users[userid].last_pkt = time(NULL); users[userid].last_pkt = time(NULL);
login_calculate(logindata, 16, password, users[userid].seed); login_calculate(logindata, 16, password, users[userid].seed);
if (dummy.q.fromlen != users[userid].addrlen || if (check_ip && ip_cmp(userid, q) != 0) {
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) { write_dns(dns_fd, q, "BADIP", 5);
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
} else { } else {
if (read >= 18 && (memcmp(logindata, in+2, 16) == 0)) { if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
/* Login ok, send ip/mtu info */ /* Login ok, send ip/mtu info */
tempip.s_addr = my_ip; tempip.s_addr = my_ip;
@ -198,24 +235,31 @@ tunnel_dns(int tun_fd, int dns_fd)
read = snprintf(out, sizeof(out), "%s-%s-%d", read = snprintf(out, sizeof(out), "%s-%s-%d",
tmp[0], tmp[1], my_mtu); tmp[0], tmp[1], my_mtu);
write_dns(dns_fd, &(dummy.q), out, read); write_dns(dns_fd, q, out, read);
dummy.q.id = 0; q->id = 0;
free(tmp[1]); free(tmp[1]);
free(tmp[0]); free(tmp[0]);
} else { } else {
write_dns(dns_fd, &(dummy.q), "LNAK", 4); write_dns(dns_fd, q, "LNAK", 4);
} }
} }
} else if(in[0] == 'P' || in[0] == 'p') { } else if(in[0] == 'P' || in[0] == 'p') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Ping packet, store userid */ /* Ping packet, store userid */
userid = in[1]; userid = unpacked[0];
if (userid < 0 || userid >= USERS) { if (userid < 0 || userid >= USERS || ip_cmp(userid, q) != 0) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5); write_dns(dns_fd, q, "BADIP", 5);
return 0; /* illegal id */ return; /* illegal id */
} }
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query)); memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].last_pkt = time(NULL); users[userid].last_pkt = time(NULL);
} else if(in[0] == 'Z' || in[0] == 'z') {
/* Case conservation check */
/* Reply with received hostname as data */
write_dns(dns_fd, q, in, read);
return;
} else if((in[0] >= '0' && in[0] <= '9') } else if((in[0] >= '0' && in[0] <= '9')
|| (in[0] >= 'a' && in[0] <= 'f') || (in[0] >= 'a' && in[0] <= 'f')
|| (in[0] >= 'A' && in[0] <= 'F')) { || (in[0] >= 'A' && in[0] <= 'F')) {
@ -228,21 +272,23 @@ tunnel_dns(int tun_fd, int dns_fd)
userid = code >> 1; userid = code >> 1;
if (userid < 0 || userid >= USERS) { if (userid < 0 || userid >= USERS) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5); write_dns(dns_fd, q, "BADIP", 5);
return 0; /* illegal id */ return; /* illegal id */
} }
/* Check sending ip number */ /* Check sending ip number */
if (dummy.q.fromlen != users[userid].addrlen || if (check_ip && ip_cmp(userid, q) != 0) {
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) { write_dns(dns_fd, q, "BADIP", 5);
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
} else { } else {
/* decode with this users encoding */
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1,
users[userid].encoder);
users[userid].last_pkt = time(NULL); users[userid].last_pkt = time(NULL);
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query)); memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].addrlen = dummy.q.fromlen; memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1); users[userid].inpacket.len += read;
users[userid].inpacket.len += read - 1; users[userid].inpacket.offset += read;
users[userid].inpacket.offset += read - 1;
if (code & 1) { if (code & 1) {
outlen = sizeof(out); outlen = sizeof(out);
@ -268,14 +314,35 @@ tunnel_dns(int tun_fd, int dns_fd)
} }
} }
/* userid must be set for a reply to be sent */ /* userid must be set for a reply to be sent */
if (userid >= 0 && userid < USERS && dummy.q.fromlen == users[userid].addrlen && if (userid >= 0 && userid < USERS && ip_cmp(userid, q) == 0 && users[userid].outpacket.len > 0) {
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) == 0 && write_dns(dns_fd, q, users[userid].outpacket.data, users[userid].outpacket.len);
users[userid].outpacket.len > 0) {
write_dns(dns_fd, &(dummy.q), users[userid].outpacket.data, users[userid].outpacket.len);
users[userid].outpacket.len = 0; users[userid].outpacket.len = 0;
users[userid].q.id = 0; users[userid].q.id = 0;
} }
}
static int
tunnel_dns(int tun_fd, int dns_fd)
{
struct query q;
int read;
if ((read = read_dns(dns_fd, &q)) <= 0)
return 0;
if (debug >= 1) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q.from);
printf("RX: client %s, type %d, name %s\n", inet_ntoa(tempin->sin_addr), q.type, q.name);
}
switch (q.type) {
case T_NULL:
handle_null_request(tun_fd, dns_fd, &q);
break;
default:
break;
}
return 0; return 0;
} }
@ -336,31 +403,28 @@ tunnel(int tun_fd, int dns_fd)
} }
static int static int
read_dns(int fd, struct query *q, char *buf, int buflen) read_dns(int fd, struct query *q)
{ {
struct sockaddr_in from; struct sockaddr_in from;
char packet[64*1024]; char packet[64*1024];
char *domain;
socklen_t addrlen; socklen_t addrlen;
int rv;
int r; int r;
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);
if (r > 0) { if (r > 0) {
dns_decode(buf, buflen, q, QR_QUERY, packet, r); dns_decode(NULL, 0, q, QR_QUERY, packet, r);
domain = strstr(q->name, topdomain);
rv = decode_data(buf, buflen, q->name, domain);
q->fromlen = addrlen;
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen); memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
} else if (r < 0) { q->fromlen = addrlen;
return strlen(q->name);
} else if (r < 0) {
/* Error */ /* Error */
perror("recvfrom"); warn("read dns");
rv = 0;
} }
return rv; return 0;
} }
static void static void
@ -371,6 +435,13 @@ write_dns(int fd, struct query *q, char *data, int datalen)
len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen); len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
if (debug >= 1) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
printf("TX: client %s, type %d, name %s, %d bytes data\n",
inet_ntoa(tempin->sin_addr), q->type, q->name, datalen);
}
sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen); sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
} }
@ -378,7 +449,7 @@ static void
usage() { usage() {
extern char *__progname; extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] " printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] [-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-P password]" "[-l ip address to listen on] [-p port] [-P password]"
" tunnel_ip topdomain\n", __progname); " tunnel_ip topdomain\n", __progname);
exit(2); exit(2);
@ -389,12 +460,15 @@ 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] " printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] [-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-P password]" "[-l ip address to listen on] [-p port] [-P password]"
" 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(" -c to disable check of client IP/port on each request\n");
printf(" -s to skip creating and configuring the tun device which then has to be created manually\n");
printf(" -f to keep running in foreground\n"); printf(" -f to keep running in foreground\n");
printf(" -D to increase debug level\n");
printf(" -u name to drop privileges and run as user 'name'\n"); printf(" -u name to drop privileges and run as user 'name'\n");
printf(" -t dir to chroot to directory dir\n"); printf(" -t dir to chroot to directory dir\n");
printf(" -d device to set tunnel device name\n"); printf(" -d device to set tunnel device name\n");
@ -409,26 +483,26 @@ help() {
static void static void
version() { version() {
char *svnver = "$Rev$ from $Date$";
printf("iodine IP over DNS tunneling server\n"); printf("iodine IP over DNS tunneling server\n");
printf("SVN version: %s\n", svnver); printf("version: 0.4.2 from 2008-08-06\n");
exit(0); exit(0);
} }
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int choice;
int tun_fd;
int dnsd_fd;
char *newroot;
char *username;
char *device;
int foreground;
int mtu;
struct passwd *pw;
in_addr_t listen_ip; in_addr_t listen_ip;
struct passwd *pw;
int foreground;
char *username;
char *newroot;
char *device;
int dnsd_fd;
int tun_fd;
int choice;
int port; int port;
int mtu;
int skipipconfig;
username = NULL; username = NULL;
newroot = NULL; newroot = NULL;
@ -437,21 +511,43 @@ main(int argc, char **argv)
mtu = 1024; mtu = 1024;
listen_ip = INADDR_ANY; listen_ip = INADDR_ANY;
port = 53; port = 53;
check_ip = 1;
skipipconfig = 0;
debug = 0;
memset(password, 0, 33); b32 = get_base32_encoder();
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
#endif
memset(password, 0, sizeof(password));
srand(time(NULL)); srand(time(NULL));
while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) { while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:P:")) != -1) {
switch(choice) { switch(choice) {
case 'v': case 'v':
version(); version();
break; break;
case 'c':
check_ip = 0;
break;
case 's':
skipipconfig = 1;
break;
case 'f': case 'f':
foreground = 1; foreground = 1;
break; break;
case 'h': case 'h':
help(); help();
break; break;
case 'D':
debug++;
break;
case 'u': case 'u':
username = optarg; username = optarg;
break; break;
@ -469,14 +565,13 @@ main(int argc, char **argv)
break; break;
case 'p': case 'p':
port = atoi(optarg); port = atoi(optarg);
if (port) {
printf("ALERT! Other dns servers expect you to run on port 53.\n");
printf("You must manually forward port 53 to port %d for things to work.\n", port);
}
break; break;
case 'P': case 'P':
strncpy(password, optarg, 32); strncpy(password, optarg, sizeof(password));
password[32] = 0; password[sizeof(password)-1] = 0;
/* XXX: find better way of cleaning up ps(1) */
memset(optarg, 0, strlen(optarg));
break; break;
default: default:
usage(); usage();
@ -488,7 +583,7 @@ main(int argc, char **argv)
argv += optind; argv += optind;
if (geteuid() != 0) { if (geteuid() != 0) {
printf("Run as root and you'll be happy.\n"); warnx("Run as root and you'll be happy.\n");
usage(); usage();
} }
@ -496,35 +591,57 @@ main(int argc, char **argv)
usage(); usage();
topdomain = strdup(argv[1]); topdomain = strdup(argv[1]);
if(strlen(topdomain) <= 128) {
if(check_topdomain(topdomain)) {
warnx("Topdomain contains invalid characters.\n");
usage();
}
} else {
warnx("Use a topdomain max 128 chars long.\n");
usage();
}
if (username) { if (username != NULL) {
pw = getpwnam(username); if ((pw = getpwnam(username)) == NULL) {
if (!pw) { warnx("User %s does not exist!\n", username);
printf("User %s does not exist!\n", username);
usage(); usage();
} }
} }
if (mtu == 0) { if (mtu <= 0) {
printf("Bad MTU given.\n"); warnx("Bad MTU given.\n");
usage(); usage();
} }
if(port < 1 || port > 65535) {
warnx("Bad port number given.\n");
usage();
}
if (port != 53) {
printf("ALERT! Other dns servers expect you to run on port 53.\n");
printf("You must manually forward port 53 to port %d for things to work.\n", port);
}
if (debug) {
printf("Debug level %d enabled, will stay in foreground.\n", debug);
printf("Add more -D switches to set higher debug level.\n");
foreground = 1;
}
if (listen_ip == INADDR_NONE) { if (listen_ip == INADDR_NONE) {
printf("Bad IP address to listen on.\n"); warnx("Bad IP address to listen on.\n");
usage(); usage();
} }
if (strlen(password) == 0) { if (strlen(password) == 0)
printf("Enter password on stdin:\n"); read_password(password, sizeof(password));
scanf("%32s", password);
password[32] = 0;
}
if ((tun_fd = open_tun(device)) == -1) if ((tun_fd = open_tun(device)) == -1)
goto cleanup0; goto cleanup0;
if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0) if (!skipipconfig)
goto cleanup1; if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
goto cleanup1;
if ((dnsd_fd = open_dns(port, listen_ip)) == -1) if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
goto cleanup2; goto cleanup2;
@ -532,22 +649,24 @@ main(int argc, char **argv)
my_mtu = mtu; my_mtu = mtu;
init_users(my_ip); init_users(my_ip);
printf("Listening to dns for domain %s\n", argv[1]); printf("Listening to dns for domain %s\n", topdomain);
do_chroot(newroot); if (foreground == 0)
do_detach();
if (newroot != NULL)
do_chroot(newroot);
signal(SIGINT, sigint); signal(SIGINT, sigint);
if (username) { if (username != NULL) {
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) { gid_t gids[1];
printf("Could not switch to user %s!\n", username); gids[0] = pw->pw_gid;
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
warnx("Could not switch to user %s!\n", username);
usage(); usage();
} }
} }
if (!foreground) {
do_detach();
}
tunnel(tun_fd, dnsd_fd); tunnel(tun_fd, dnsd_fd);
cleanup2: cleanup2:

View File

@ -47,5 +47,6 @@ login_calculate(char *buf, int buflen, char *pass, int seed)
md5_init(&ctx); md5_init(&ctx);
md5_append(&ctx, temp, 32); md5_append(&ctx, temp, 32);
md5_finish(&ctx, (unsigned char *) buf); md5_finish(&ctx, (unsigned char *) buf);
} }

14
src/osflags Normal file
View File

@ -0,0 +1,14 @@
#!/bin/sh
case $1 in
link)
case `uname` in
SunOS | solaris)
echo '-lsocket -lnsl';
;;
esac
;;
*)
;;
esac

View File

@ -58,7 +58,9 @@ open_tun(const char *tun_device)
if (tun_device != NULL) { if (tun_device != NULL) {
strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ); strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
ifreq.ifr_name[IFNAMSIZ-1] = '\0';
strncpy(if_name, tun_device, sizeof(if_name)); strncpy(if_name, tun_device, sizeof(if_name));
if_name[sizeof(if_name)-1] = '\0';
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) { if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
printf("Opened %s\n", ifreq.ifr_name); printf("Opened %s\n", ifreq.ifr_name);
@ -102,6 +104,7 @@ open_tun(const char *tun_device)
if (tun_device != NULL) { if (tun_device != NULL) {
snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device); snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
strncpy(if_name, tun_device, sizeof(if_name)); strncpy(if_name, tun_device, sizeof(if_name));
if_name[sizeof(if_name)-1] = '\0';
if ((tun_fd = open(tun_name, O_RDWR)) < 0) { if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
warn("open_tun: %s: %s", tun_name, strerror(errno)); warn("open_tun: %s: %s", tun_name, strerror(errno));
@ -140,7 +143,7 @@ close_tun(int tun_fd)
} }
int int
write_tun(int tun_fd, char *data, int len) write_tun(int tun_fd, char *data, size_t len)
{ {
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
data += 4; data += 4;
@ -166,8 +169,8 @@ write_tun(int tun_fd, char *data, int len)
return 0; return 0;
} }
int ssize_t
read_tun(int tun_fd, char *buf, int len) read_tun(int tun_fd, char *buf, size_t len)
{ {
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
/* FreeBSD/Darwin/NetBSD has no header */ /* FreeBSD/Darwin/NetBSD has no header */
@ -181,6 +184,9 @@ int
tun_setip(const char *ip) tun_setip(const char *ip)
{ {
char cmdline[512]; char cmdline[512];
#ifndef LINUX
int r;
#endif
if (inet_addr(ip) != INADDR_NONE) { if (inet_addr(ip) != INADDR_NONE) {
snprintf(cmdline, sizeof(cmdline), snprintf(cmdline, sizeof(cmdline),
@ -191,8 +197,6 @@ tun_setip(const char *ip)
printf("Setting IP of %s to %s\n", if_name, ip); printf("Setting IP of %s to %s\n", if_name, ip);
#ifndef LINUX #ifndef LINUX
int r;
r = system(cmdline); r = system(cmdline);
if(r != 0) { if(r != 0) {
return r; return r;
@ -212,20 +216,20 @@ tun_setip(const char *ip)
} }
int int
tun_setmtu(const int mtu) tun_setmtu(const size_t mtu)
{ {
char cmdline[512]; char cmdline[512];
if (mtu > 200 && mtu < 1500) { if (mtu > 200 && mtu < 1500) {
snprintf(cmdline, sizeof(cmdline), snprintf(cmdline, sizeof(cmdline),
"/sbin/ifconfig %s mtu %d", "/sbin/ifconfig %s mtu %u",
if_name, if_name,
mtu); mtu);
printf("Setting MTU of %s to %d\n", if_name, mtu); printf("Setting MTU of %s to %u\n", if_name, mtu);
return system(cmdline); return system(cmdline);
} else { } else {
warn("MTU out of range: %d\n", mtu); warn("MTU out of range: %u\n", mtu);
} }
return 1; return 1;

View File

@ -19,9 +19,9 @@
int open_tun(const char *); int open_tun(const char *);
void close_tun(int); void close_tun(int);
int write_tun(int, char *, int); int write_tun(int, char *, size_t);
int read_tun(int, char *, int); ssize_t read_tun(int, char *, size_t);
int tun_setip(const char *); int tun_setip(const char *);
int tun_setmtu(const int); int tun_setmtu(const size_t);
#endif /* _TUN_H_ */ #endif /* _TUN_H_ */

View File

@ -14,15 +14,23 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <time.h> #include <time.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h>
#include <err.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h>
#include "common.h" #include "common.h"
#include "encoding.h"
#include "user.h" #include "user.h"
struct user users[USERS]; struct user users[USERS];

View File

@ -25,11 +25,11 @@ struct user {
time_t last_pkt; time_t last_pkt;
int seed; int seed;
in_addr_t tun_ip; in_addr_t tun_ip;
struct sockaddr host; struct in_addr host;
int addrlen;
struct query q; struct query q;
struct packet inpacket; struct packet inpacket;
struct packet outpacket; struct packet outpacket;
struct encoder *encoder;
}; };
extern struct user users[USERS]; extern struct user users[USERS];

View File

@ -19,7 +19,7 @@
/* This is the version of the network protocol /* This is the version of the network protocol
It is usually equal to the latest iodine version number */ It is usually equal to the latest iodine version number */
#define VERSION 0x00000400 #define VERSION 0x00000402
#endif /* _VERSION_H_ */ #endif /* _VERSION_H_ */

View File

@ -1,7 +1,7 @@
CC = gcc CC = gcc
TEST = test TEST = test
OBJS = test.o base32.o read.o dns.o encoding.o login.o user.o OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o user.o
SRCOBJS = ../src/base32.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o SRCOBJS = ../src/base32.o ../src/base64.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o
OS = `uname | tr "a-z" "A-Z"` OS = `uname | tr "a-z" "A-Z"`
@ -21,6 +21,6 @@ $(TEST): $(OBJS) $(SRCOBJS)
clean: clean:
@echo "Cleaning..." @echo "Cleaning tests/"
@rm -f *~ *.core $(TEST) $(OBJS) @rm -f *~ *.core $(TEST) $(OBJS)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -20,61 +20,54 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "encoding.h"
#include "base32.h" #include "base32.h"
#include "test.h" #include "test.h"
struct touple static struct tuple
{ {
char *a; char *a;
char *b; char *b;
} testpairs[] = { } testpairs[] = {
{ "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
{ "abc123", "mfrggmjsgm" }, { "abc123", "mfrggmjsgm" },
{ NULL, NULL } { NULL, NULL }
}; };
START_TEST(test_base32_encode) START_TEST(test_base32_encode)
{ {
size_t len; size_t len;
char *buf; char buf[4096];
int val; int val;
int i; int i;
len = 0;
buf = NULL;
for (i = 0; testpairs[i].a != NULL; i++) { for (i = 0; testpairs[i].a != NULL; i++) {
val = base32_encode(&buf, &len, testpairs[i].a, strlen(testpairs[i].a)); len = sizeof(buf);
val = base32_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno)); fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL"); fail_unless(strcmp(buf, testpairs[i].b) == 0,
fail_unless(strcmp(buf, testpairs[i].b) == 0, "'%s' != '%s'", buf, testpairs[i].b);
va_str("'%s' != '%s'", buf, testpairs[i].b));
} }
free(buf);
} }
END_TEST END_TEST
START_TEST(test_base32_decode) START_TEST(test_base32_decode)
{ {
size_t len; size_t len;
void *buf; char buf[4096];
int val; int val;
int i; int i;
len = 0;
buf = NULL;
for (i = 0; testpairs[i].a != NULL; i++) { for (i = 0; testpairs[i].a != NULL; i++) {
val = base32_decode(&buf, &len, testpairs[i].b); len = sizeof(buf);
val = base32_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
fail_unless(val > 0, strerror(errno)); fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL"); fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0, fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a)); "'%s' != '%s'", buf, testpairs[i].a);
} }
free(buf);
} }
END_TEST END_TEST

112
tests/base64.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <check.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "encoding.h"
#include "base64.h"
#include "test.h"
static struct tuple
{
char *a;
char *b;
} testpairs[] = {
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
{ "abc123", "ywjJmtiZ" },
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
"\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68\x9E\x69\x64\x8E\x28\x60"
"\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48"
"\x1C\x61\x44\x0C\x20\x40\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70"
"\xBE\xEB\x6C\xAE\xAA\x68\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58"
"\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40",
"9abba876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfe999dcbapZ"
"776543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9abba87654"
"3210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfe999dcba"
},
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
"\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xA1\x61\x91\x61\x61\x81\x28\x60"
"\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48"
"\x1C\x61\x44\x0C\x20\x40\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70"
"\xBE\xEB\x6C\xAE\xA1\x61\x91\x61\x61\x81\x28\x60\x7D\xE7\x5C\x6D\xA6\x58"
"\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40",
"9IJJI876543210-ZYXWVUTSRQPONMLK9LMJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ"
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcbaML87654321"
"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
},
{ NULL, NULL }
};
START_TEST(test_base64_encode)
{
size_t len;
char buf[4096];
int val;
int i;
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
}
END_TEST
START_TEST(test_base64_decode)
{
size_t len;
char buf[4096];
int val;
int i;
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
}
END_TEST
TCase *
test_base64_create_tests()
{
TCase *tc;
tc = tcase_create("Base64");
tcase_add_test(tc, test_base64_encode);
tcase_add_test(tc, test_base64_decode);
return tc;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -28,39 +28,39 @@
#include "common.h" #include "common.h"
#include "dns.h" #include "dns.h"
#include "encoding.h" #include "encoding.h"
#include "base32.h"
#include "test.h" #include "test.h"
static void dump_packet(char *, size_t); static void dump_packet(char *, size_t);
static char queryPacket[] = static char queryPacket[] =
"\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x32\x41\x4A\x42\x43" "\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x2D\x41\x6A\x62\x63"
"\x55\x59\x54\x43\x50\x45\x42\x39\x47\x51\x39\x4C\x54\x45\x42\x55\x58" "\x75\x79\x74\x63\x70\x65\x62\x30\x67\x71\x30\x6C\x74\x65\x62\x75\x78"
"\x47\x49\x44\x55\x4E\x42\x53\x53\x41\x36\x44\x46\x4F\x4E\x39\x43\x41" "\x67\x69\x64\x75\x6E\x62\x73\x73\x61\x33\x64\x66\x6F\x6E\x30\x63\x61"
"\x5A\x44\x42\x32\x41\x41\x41\x41\x41\x36\x44\x42\x04\x6B\x72\x79\x6F" "\x7A\x64\x62\x6F\x72\x71\x71\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00"
"\x02\x73\x65\x00\x00\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00" "\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00";
"\x00\x00";
static char answerPacket[] = static char answerPacket[] =
"\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C" "\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04" "\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01" "\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
"\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20" "\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20"
"\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F" "\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
"\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64"; "\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
static char *msgData = "this is the message to be delivered"; static char *msgData = "this is the message to be delivered";
static char *topdomain = "kryo.se"; static char *topdomain = "kryo.se";
static char *queryData = "HELLO this is the test data"; static char *innerData = "HELLO this is the test data";
static char *recData = "AHELLO this is the test data"; /* The A flag is added */
START_TEST(test_encode_query) START_TEST(test_encode_query)
{ {
char buf[512]; char buf[512];
char resolv[512]; char resolv[512];
struct query q; struct query q;
struct encoder *enc;
char *d; char *d;
int len; size_t len;
int ret; int ret;
len = sizeof(buf); len = sizeof(buf);
@ -70,9 +70,10 @@ START_TEST(test_encode_query)
q.type = T_NULL; q.type = T_NULL;
q.id = 1337; q.id = 1337;
d = resolv; d = resolv;
enc = get_base32_encoder();
*d++ = 'A'; *d++ = 'A';
encode_data(queryData, strlen(queryData), 100, d); enc->encode(d, &len, innerData, strlen(innerData));
d = resolv + strlen(resolv); d = resolv + strlen(resolv);
if (*d != '.') { if (*d != '.') {
*d++ = '.'; *d++ = '.';
@ -87,7 +88,7 @@ START_TEST(test_encode_query)
dump_packet(buf, ret); dump_packet(buf, ret);
} }
fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet"); fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len)); fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
} }
END_TEST END_TEST
@ -96,20 +97,22 @@ START_TEST(test_decode_query)
char buf[512]; char buf[512];
char *domain; char *domain;
struct query q; struct query q;
int len; struct encoder *enc;
int ret; size_t len;
memset(&q, 0, sizeof(struct query)); memset(&q, 0, sizeof(struct query));
memset(&buf, 0, sizeof(buf)); memset(&buf, 0, sizeof(buf));
q.id = 0; q.id = 0;
len = sizeof(queryPacket) - 1; len = sizeof(queryPacket) - 1;
enc = get_base32_encoder();
dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len); dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len);
domain = strstr(q.name, topdomain); domain = strstr(q.name, topdomain);
ret = decode_data(buf, sizeof(buf), q.name, domain); len = sizeof(buf);
unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);
fail_unless(strncmp(buf, recData, ret) == 0, "Did not extract expected host: '%s'", buf); fail_unless(strncmp(buf, innerData, strlen(innerData)) == 0, "Did not extract expected host: '%s'", buf);
fail_unless(strlen(buf) == strlen(recData), va_str("Bad host length: %d, expected %d", strlen(q.name), strlen(recData))); fail_unless(strlen(buf) == strlen(innerData), "Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf);
} }
END_TEST END_TEST
@ -132,7 +135,7 @@ START_TEST(test_encode_response)
len = sizeof(answerPacket) - 1; /* Skip extra null character */ len = sizeof(answerPacket) - 1; /* Skip extra null character */
fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet"); fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len)); fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
} }
END_TEST END_TEST
@ -147,7 +150,7 @@ START_TEST(test_decode_response)
ret = dns_decode(buf, len, NULL, QR_ANSWER, answerPacket, sizeof(answerPacket)-1); ret = dns_decode(buf, len, NULL, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data"); fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), va_str("Bad data length: %d, expected %d", ret, strlen(msgData))); fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
} }
END_TEST END_TEST

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,24 +22,56 @@
#include "encoding.h" #include "encoding.h"
#include "test.h" #include "test.h"
START_TEST(test_encoding_base32) struct tuple
{ {
char temp[256]; char *a;
char *start = "HELLOTEST"; char *b;
char *out = "1HELLOTEST"; } dottests[] = {
char end[256]; { "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
char *tempend; "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a"},
int codedlength; { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
{ "abc123", "abc123" },
{ NULL, NULL }
};
memset(temp, 0, sizeof(temp)); START_TEST(test_inline_dotify)
memset(end, 0, sizeof(end)); {
unsigned i;
char temp[1024];
char *b;
codedlength = encode_data(start, strlen(start), sizeof(temp) - 1, temp + 1); i = 0;
temp[0] = '1'; while (dottests[i].a) {
tempend = temp + strlen(temp); memset(temp, 0, sizeof(temp));
decode_data(end, sizeof(end), temp, tempend); strcpy(temp, dottests[i].a);
b = temp;
inline_dotify(b, sizeof(temp));
fail_unless(strcmp(out, end) == 0, NULL); fail_unless(strcmp(dottests[i].b, temp) == 0,
"'%s' != '%s'", temp, dottests[i].b);
i++;
}
}
END_TEST
START_TEST(test_inline_undotify)
{
unsigned i;
char temp[1024];
char *b;
i = 0;
while (dottests[i].a) {
memset(temp, 0, sizeof(temp));
strcpy(temp, dottests[i].b);
b = temp;
inline_undotify(b, sizeof(temp));
fail_unless(strcmp(dottests[i].a, temp) == 0,
"'%s' != '%s'", temp, dottests[i].a);
i++;
}
} }
END_TEST END_TEST
@ -49,7 +81,8 @@ test_encoding_create_tests()
TCase *tc; TCase *tc;
tc = tcase_create("Encoding"); tc = tcase_create("Encoding");
tcase_add_test(tc, test_encoding_base32); tcase_add_test(tc, test_inline_dotify);
tcase_add_test(tc, test_inline_undotify);
return tc; return tc;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -33,7 +33,7 @@
#include "dns.h" #include "dns.h"
#include "read.h" #include "read.h"
#include "test.h" #include "test.h"
START_TEST(test_read_putshort) START_TEST(test_read_putshort)
{ {
unsigned short k; unsigned short k;
@ -44,15 +44,15 @@ START_TEST(test_read_putshort)
for (i = 0; i < 65536; i++) { for (i = 0; i < 65536; i++) {
p = (char*)&k; p = (char*)&k;
putshort(&p, i); putshort(&p, i);
fail_unless(ntohs(k) == i, fail_unless(ntohs(k) == i,
va_str("Bad value on putshort for %d: %d != %d", "Bad value on putshort for %d: %d != %d",
i, ntohs(k), i)); i, ntohs(k), i);
p = (char*)&k; p = (char*)&k;
readshort(NULL, &p, (short *) &l); readshort(NULL, &p, (short *) &l);
fail_unless(l == i, fail_unless(l == i,
va_str("Bad value on readshort for %d: %d != %d", "Bad value on readshort for %d: %d != %d",
i, l, i)); i, l, i);
} }
} }
END_TEST END_TEST
@ -71,14 +71,14 @@ START_TEST(test_read_putlong)
putlong(&p, j); putlong(&p, j);
fail_unless(ntohl(k) == j, fail_unless(ntohl(k) == j,
va_str("Bad value on putlong for %d: %d != %d", i, ntohl(j), j)); "Bad value on putlong for %d: %d != %d", i, ntohl(j), j);
p = (char*)&k; p = (char*)&k;
readlong(NULL, &p, &l); readlong(NULL, &p, &l);
fail_unless(l == j, fail_unless(l == j,
va_str("Bad value on readlong for %d: %d != %d", i, l, j)); "Bad value on readlong for %d: %d != %d", i, l, j);
} }
} }
END_TEST END_TEST
@ -87,11 +87,11 @@ START_TEST(test_read_name)
{ {
unsigned char emptyloop[] = { unsigned char emptyloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char infloop[] = { unsigned char infloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char longname[] = unsigned char longname[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00" "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA" "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA" "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
@ -100,15 +100,15 @@ START_TEST(test_read_name)
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA" "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA" "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x00\x00\x01\x00\x01"; "\x00\x00\x01\x00\x01";
unsigned char onejump[] = unsigned 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";
unsigned char badjump[] = { unsigned char badjump[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 }; 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
unsigned char badjump2[] = { unsigned char badjump2[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 }; 0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
unsigned char *jumper; unsigned char *jumper;
char buf[1024]; char buf[1024];
char *data; char *data;
@ -119,13 +119,13 @@ START_TEST(test_read_name)
buf[1023] = 'A'; buf[1023] = 'A';
rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023); rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
fail_unless(buf[1023] == 'A', NULL); fail_unless(buf[1023] == 'A', NULL);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = (char*) infloop + sizeof(HEADER); data = (char*) infloop + sizeof(HEADER);
buf[4] = '\a'; buf[4] = '\a';
rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4); rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
fail_unless(buf[4] == '\a', NULL); fail_unless(buf[4] == '\a', NULL);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
data = (char*) longname + sizeof(HEADER); data = (char*) longname + sizeof(HEADER);
buf[256] = '\a'; buf[256] = '\a';
@ -136,7 +136,7 @@ START_TEST(test_read_name)
data = (char*) onejump + sizeof(HEADER); data = (char*) onejump + sizeof(HEADER);
rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256); rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);
fail_unless(rv == 9, NULL); fail_unless(rv == 9, NULL);
/* These two tests use malloc to cause segfault if jump is executed */ /* These two tests use malloc to cause segfault if jump is executed */
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump)); jumper = malloc(sizeof(badjump));
@ -149,7 +149,7 @@ START_TEST(test_read_name)
fail_unless(buf[0] == 0, NULL); fail_unless(buf[0] == 0, NULL);
} }
free(jumper); free(jumper);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump2)); jumper = malloc(sizeof(badjump2));
if (jumper) { if (jumper) {
@ -158,8 +158,8 @@ START_TEST(test_read_name)
rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256); rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
fail_unless(rv == 4, NULL); fail_unless(rv == 4, NULL);
fail_unless(strcmp("BA.", buf) == 0, fail_unless(strcmp("BA.", buf) == 0,
va_str("buf is not BA: %s", buf)); "buf is not BA: %s", buf);
} }
free(jumper); free(jumper);
} }
@ -184,11 +184,11 @@ START_TEST(test_putname)
fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed"); fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
} }
END_TEST END_TEST
START_TEST(test_putname_nodot) START_TEST(test_putname_nodot)
{ {
char buf[256]; char buf[256];
char *nodot = char *nodot =
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"; "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *b; char *b;
@ -205,11 +205,11 @@ START_TEST(test_putname_nodot)
fail_unless(b == buf, NULL); fail_unless(b == buf, NULL);
} }
END_TEST END_TEST
START_TEST(test_putname_toolong) START_TEST(test_putname_toolong)
{ {
char buf[256]; char buf[256];
char *toolong = char *toolong =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ." "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,20 +22,6 @@
#include "test.h" #include "test.h"
char *
va_str(const char *fmt, ...)
{
static char buf[512];
va_list ap;
memset(buf, 0, sizeof(buf));
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
int int
main() main()
{ {
@ -49,6 +35,9 @@ main()
test = test_base32_create_tests(); test = test_base32_create_tests();
suite_add_tcase(iodine, test); suite_add_tcase(iodine, test);
test = test_base64_create_tests();
suite_add_tcase(iodine, test);
test = test_dns_create_tests(); test = test_dns_create_tests();
suite_add_tcase(iodine, test); suite_add_tcase(iodine, test);
@ -65,7 +54,7 @@ main()
suite_add_tcase(iodine, test); suite_add_tcase(iodine, test);
runner = srunner_create(iodine); runner = srunner_create(iodine);
srunner_run_all(runner, CK_VERBOSE); srunner_run_all(runner, CK_MINIMAL);
failed = srunner_ntests_failed(runner); failed = srunner_ntests_failed(runner);
srunner_free(runner); srunner_free(runner);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -18,6 +18,7 @@
#define __TEST_H__ #define __TEST_H__
TCase *test_base32_create_tests(); TCase *test_base32_create_tests();
TCase *test_base64_create_tests();
TCase *test_dns_create_tests(); TCase *test_dns_create_tests();
TCase *test_encoding_create_tests(); TCase *test_encoding_create_tests();
TCase *test_read_create_tests(); TCase *test_read_create_tests();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -23,6 +23,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include "common.h" #include "common.h"
#include "encoding.h"
#include "user.h" #include "user.h"
#include "test.h" #include "test.h"