Release 0.4.1 tagged
This commit is contained in:
parent
4d4da3eb87
commit
d27bd67997
18
CHANGELOG
18
CHANGELOG
|
@ -1,12 +1,22 @@
|
||||||
|
|
||||||
iodine - IP over DNS is now easy
|
iodine - http://code.kryo.se/iodine
|
||||||
|
|
||||||
http://code.kryo.se/iodine
|
***********************************
|
||||||
|
|
||||||
********************************
|
|
||||||
|
|
||||||
CHANGES:
|
CHANGES:
|
||||||
|
|
||||||
|
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"
|
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)
|
||||||
|
|
36
Makefile
36
Makefile
|
@ -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
|
||||||
|
@echo "!! The check library is required for compiling and running the tests"
|
||||||
|
@echo "!! Get it at http://check.sf.net"
|
||||||
@(cd tests; make all)
|
@(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
27
README
|
@ -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
6
TODO
|
@ -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
|
||||||
|
|
||||||
|
|
13
man/iodine.8
13
man/iodine.8
|
@ -1,5 +1,5 @@
|
||||||
.\" groff -man -Tascii iodine.8
|
.\" groff -man -Tascii iodine.8
|
||||||
.TH IODINE 8 "FEB 2007" "User Manuals"
|
.TH IODINE 8 "JUN 2007" "User Manuals"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
iodine, iodined \- tunnel IPv4 over DNS
|
iodine, iodined \- tunnel IPv4 over DNS
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -16,7 +16,9 @@ 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]
|
||||||
|
@ -93,7 +95,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
|
||||||
|
@ -179,6 +182,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
|
||||||
|
|
13
src/Makefile
13
src/Makefile
|
@ -1,8 +1,9 @@
|
||||||
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`
|
||||||
|
@ -15,15 +16,15 @@ all: stateos $(CLIENT) $(SERVER) $(TESTSUITE)
|
||||||
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 $<
|
||||||
|
|
152
src/base32.c
152
src/base32.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
35
src/common.c
35
src/common.c
|
@ -29,6 +29,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
@ -71,13 +72,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 +87,27 @@ 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';
|
||||||
|
}
|
||||||
|
|
14
src/common.h
14
src/common.h
|
@ -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,6 @@ void close_dns(int);
|
||||||
void do_chroot(char *);
|
void do_chroot(char *);
|
||||||
void do_detach();
|
void do_detach();
|
||||||
|
|
||||||
|
void read_password(char*, size_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
61
src/dns.c
61
src/dns.c
|
@ -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,29 @@ 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 answer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +189,8 @@ 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);
|
||||||
|
|
||||||
|
@ -177,7 +199,8 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(q->name, name, 257);
|
strncpy(q->name, name, sizeof(q->name));
|
||||||
|
q->name[sizeof(q->name) - 1] = '\0';
|
||||||
q->type = type;
|
q->type = type;
|
||||||
q->id = id;
|
q->id = id;
|
||||||
|
|
||||||
|
@ -188,27 +211,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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
251
src/encoding.c
251
src/encoding.c
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
325
src/iodine.c
325
src/iodine.c
|
@ -23,6 +23,7 @@
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.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>
|
||||||
|
@ -35,6 +36,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 +45,37 @@
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sighandler(int sig)
|
sighandler(int sig)
|
||||||
{
|
{
|
||||||
|
@ -66,57 +83,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 +198,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 +280,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 +325,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 +357,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)
|
||||||
{
|
{
|
||||||
|
@ -339,15 +397,15 @@ handshake(int dns_fd)
|
||||||
read = read_dns(dns_fd, in, sizeof(in));
|
read = read_dns(dns_fd, in, sizeof(in));
|
||||||
|
|
||||||
if(read < 0) {
|
if(read < 0) {
|
||||||
perror("read");
|
warn("handshake read");
|
||||||
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 +463,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 +475,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 +574,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 +584,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 +592,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);
|
||||||
|
@ -469,7 +602,7 @@ static void
|
||||||
version() {
|
version() {
|
||||||
|
|
||||||
printf("iodine IP over DNS tunneling client\n");
|
printf("iodine IP over DNS tunneling client\n");
|
||||||
printf("version: 0.4.0 from 2007-03-25\n");
|
printf("version: 0.4.1 from 2007-11-30\n");
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -477,6 +610,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;
|
||||||
|
@ -492,6 +626,9 @@ 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();
|
||||||
|
|
||||||
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
|
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
|
||||||
switch(choice) {
|
switch(choice) {
|
||||||
|
@ -514,8 +651,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();
|
||||||
|
@ -524,37 +664,48 @@ 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 || topdomain[0] == '.') {
|
||||||
pw = getpwnam(username);
|
warnx("Use a topdomain max 128 chars long. Do not start it with a dot.\n");
|
||||||
if (!pw) {
|
usage();
|
||||||
printf("User %s does not exist!\n", username);
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
@ -562,21 +713,21 @@ 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) {
|
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
|
||||||
printf("Could not switch to user %s!\n", username);
|
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:
|
||||||
|
|
165
src/iodined.c
165
src/iodined.c
|
@ -21,6 +21,7 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.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>
|
||||||
|
@ -34,20 +35,20 @@
|
||||||
|
|
||||||
#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 my_mtu;
|
||||||
|
static in_addr_t my_ip;
|
||||||
char password[33];
|
|
||||||
|
|
||||||
int my_mtu;
|
|
||||||
in_addr_t my_ip;
|
|
||||||
|
|
||||||
static int read_dns(int, struct query *, char *, int);
|
static int read_dns(int, struct query *, char *, int);
|
||||||
static void write_dns(int, struct query *, char *, int);
|
static void write_dns(int, struct query *, char *, int);
|
||||||
|
@ -133,6 +134,7 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
char logindata[16];
|
char logindata[16];
|
||||||
char out[64*1024];
|
char out[64*1024];
|
||||||
char in[64*1024];
|
char in[64*1024];
|
||||||
|
char unpacked[64*1024];
|
||||||
char *tmp[2];
|
char *tmp[2];
|
||||||
int userid;
|
int userid;
|
||||||
int touser;
|
int touser;
|
||||||
|
@ -145,37 +147,37 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
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)));
|
users[userid].seed = rand();
|
||||||
|
memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
|
||||||
if (version == VERSION) {
|
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
||||||
userid = find_available_user();
|
users[userid].addrlen = dummy.q.fromlen;
|
||||||
if (userid >= 0) {
|
users[userid].encoder = get_base32_encoder();
|
||||||
users[userid].seed = rand();
|
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
|
||||||
memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
|
users[userid].q.id = 0;
|
||||||
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
|
||||||
users[userid].addrlen = dummy.q.fromlen;
|
|
||||||
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
|
|
||||||
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, &dummy);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
|
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
|
||||||
}
|
}
|
||||||
} 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, &(dummy.q), "BADIP", 5);
|
||||||
return 0; /* illegal id */
|
return 0; /* illegal id */
|
||||||
|
@ -187,7 +189,7 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
||||||
write_dns(dns_fd, &(dummy.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;
|
||||||
|
@ -208,14 +210,21 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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) {
|
||||||
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
||||||
return 0; /* illegal id */
|
return 0; /* illegal id */
|
||||||
}
|
}
|
||||||
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
memcpy(&(users[userid].q), &(dummy.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, &(dummy.q), in, read);
|
||||||
|
return 0;
|
||||||
} 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')) {
|
||||||
|
@ -237,12 +246,16 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
||||||
write_dns(dns_fd, &(dummy.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), &(dummy.q), sizeof(struct query));
|
||||||
users[userid].addrlen = dummy.q.fromlen;
|
users[userid].addrlen = dummy.q.fromlen;
|
||||||
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1);
|
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
|
||||||
users[userid].inpacket.len += read - 1;
|
users[userid].inpacket.len += read;
|
||||||
users[userid].inpacket.offset += read - 1;
|
users[userid].inpacket.offset += read;
|
||||||
|
|
||||||
if (code & 1) {
|
if (code & 1) {
|
||||||
outlen = sizeof(out);
|
outlen = sizeof(out);
|
||||||
|
@ -351,12 +364,17 @@ read_dns(int fd, struct query *q, char *buf, int buflen)
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
dns_decode(buf, buflen, q, QR_QUERY, packet, r);
|
dns_decode(buf, buflen, q, QR_QUERY, packet, r);
|
||||||
domain = strstr(q->name, topdomain);
|
domain = strstr(q->name, topdomain);
|
||||||
rv = decode_data(buf, buflen, q->name, domain);
|
if (domain) {
|
||||||
q->fromlen = addrlen;
|
rv = (int) (domain - q->name);
|
||||||
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
|
memcpy(buf, q->name, MIN(rv, buflen));
|
||||||
} else if (r < 0) {
|
q->fromlen = addrlen;
|
||||||
|
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
} else if (r < 0) {
|
||||||
/* Error */
|
/* Error */
|
||||||
perror("recvfrom");
|
warn("read dns");
|
||||||
rv = 0;
|
rv = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,24 +428,24 @@ help() {
|
||||||
static void
|
static void
|
||||||
version() {
|
version() {
|
||||||
printf("iodine IP over DNS tunneling server\n");
|
printf("iodine IP over DNS tunneling server\n");
|
||||||
printf("version: 0.4.0 from 2007-03-25\n");
|
printf("version: 0.4.1 from 2007-11-30\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;
|
||||||
|
|
||||||
username = NULL;
|
username = NULL;
|
||||||
newroot = NULL;
|
newroot = NULL;
|
||||||
|
@ -437,7 +455,9 @@ main(int argc, char **argv)
|
||||||
listen_ip = INADDR_ANY;
|
listen_ip = INADDR_ANY;
|
||||||
port = 53;
|
port = 53;
|
||||||
|
|
||||||
memset(password, 0, 33);
|
b32 = get_base32_encoder();
|
||||||
|
|
||||||
|
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, "vfhu:t:d:m:l:p:P:")) != -1) {
|
||||||
|
@ -474,8 +494,11 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
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();
|
||||||
|
@ -487,7 +510,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,30 +518,30 @@ main(int argc, char **argv)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
topdomain = strdup(argv[1]);
|
topdomain = strdup(argv[1]);
|
||||||
|
if (strlen(topdomain) > 128 || topdomain[0] == '.') {
|
||||||
|
warnx("Use a topdomain max 128 chars long. Do not start it with a dot.\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 (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;
|
||||||
|
@ -531,22 +554,22 @@ 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) {
|
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
|
||||||
printf("Could not switch to user %s!\n", username);
|
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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
src/tun.c
22
src/tun.c
|
@ -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;
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
12
src/user.c
12
src/user.c
|
@ -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];
|
||||||
|
|
|
@ -30,6 +30,7 @@ struct user {
|
||||||
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];
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
||||||
|
|
|
@ -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,14 +20,16 @@
|
||||||
#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 }
|
||||||
};
|
};
|
||||||
|
@ -35,46 +37,37 @@ struct touple
|
||||||
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,
|
||||||
va_str("'%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));
|
va_str("'%s' != '%s'", buf, testpairs[i].a));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
va_str("'%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,
|
||||||
|
va_str("'%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;
|
||||||
|
}
|
35
tests/dns.c
35
tests/dns.c
|
@ -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,17 +28,17 @@
|
||||||
#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"
|
||||||
|
@ -51,16 +51,16 @@ static char answerPacket[] =
|
||||||
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++ = '.';
|
||||||
|
@ -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), va_str("Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf));
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
va_str("'%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,
|
||||||
|
va_str("'%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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -49,6 +49,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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue