[svn-upgrade] Integrating new upstream version, iodine (0.4.1) upstream/0.4.1
authorgregor herrmann <gregoa@debian.org>
Sat, 1 Dec 2007 00:43:05 +0000 (00:43 -0000)
committergregor herrmann <gregoa@debian.org>
Sat, 1 Dec 2007 00:43:05 +0000 (00:43 -0000)
34 files changed:
CHANGELOG
Makefile
README
TODO
man/iodine.8
src/Makefile
src/base32.c
src/base32.h
src/base64.c [new file with mode: 0644]
src/base64.h [new file with mode: 0644]
src/common.c
src/common.h
src/dns.c
src/dns.h
src/encoding.c
src/encoding.h
src/iodine.c
src/iodined.c
src/login.c
src/tun.c
src/tun.h
src/user.c
src/user.h
src/version.h
tests/Makefile
tests/base32.c
tests/base64.c [new file with mode: 0644]
tests/dns.c
tests/encoding.c
tests/login.c
tests/read.c
tests/test.c
tests/test.h
tests/user.c

index 3ecee1fa7df085b18fc034aef3654cf5a59566f2..14ad31397fda2d009c5f5c771082b78cd0f83b77 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,12 +1,22 @@
 
-iodine - IP over DNS is now easy
+iodine - http://code.kryo.se/iodine
 
-   http://code.kryo.se/iodine
-
-********************************
+***********************************
 
 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"
        - Added multiuser support (up to 8 users simultaneously)
        - Added authentication (password entered as argument or on stdin)
index c6d63a2b022a5b650dcc8d1c119291a2aef5374c..7516942ec6059ba8a2c00cade5b0685b4d8b4b34 100644 (file)
--- a/Makefile
+++ b/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=
 
 MKDIR=mkdir
@@ -10,26 +15,31 @@ RM=rm
 RM_FLAGS=-f
 
 all: 
-       @(cd src; make all)
+       @(cd src; $(MAKE) all)
 
 install: all
-       $(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/sbin
-       $(INSTALL) $(INSTALL_FLAGS) bin/iodine $(PREFIX)/sbin/iodine
-       $(INSTALL) $(INSTALL_FLAGS) bin/iodined $(PREFIX)/sbin/iodined
-       $(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/man/man8
-       $(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(PREFIX)/man/man8/iodine.8
+       $(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
+       $(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine
+       chmod 755 $(DESTDIR)$(sbindir)/iodine
+       $(INSTALL) $(INSTALL_FLAGS) bin/iodined $(DESTDIR)$(sbindir)/iodined
+       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:
-       $(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodine
-       $(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodined
-       $(RM) $(RM_FLAGS) $(PREFIX)/man/man8/iodine.8
+       $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodine
+       $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined
+       $(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8
        
 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)
 
 clean:
        @echo "Cleaning..."
-       @(cd src; make clean)
-       @(cd tests; make clean)
+       @(cd src; $(MAKE) clean)
+       @(cd tests; $(MAKE) clean)
        @rm -rf bin
 
diff --git a/README b/README
index f52ed4f370762f6cd5d9f517f42c2debe7c650f0..8e449937b5f9669974a17363bfbb838f6874a4f0 100644 (file)
--- a/README
+++ b/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
 server. This can be usable in different situations where internet access is
@@ -30,13 +28,18 @@ HOW TO USE:
 
 Server side:
 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
-server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server.
-If you use BIND for the domain, add these lines to the zone file:
+and a server with a public IP number (not behind NAT) that does not yet run 
+a DNS server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the 
+server. If you use BIND for the domain, add these lines to the zone file:
 
 tunnel1host    IN      A       10.15.213.99
 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
 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
@@ -60,13 +63,11 @@ either side.
 
 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
 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
 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:
 
 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 
 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. 
diff --git a/TODO b/TODO
index 766d37b88eb9d908b8ce08fd6b9b625874e0ba83..e852d32d83ae710cd912f5b499d2ac4b82e65b70 100644 (file)
--- a/TODO
+++ b/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
 
index 69921c7eccb07dea40075ef230e9a3a8adcd007c..3720a50b0294f642bb1e6817bb162ac8ef7be68a 100644 (file)
@@ -1,5 +1,5 @@
 .\" groff -man -Tascii iodine.8
-.TH IODINE 8 "FEB 2007" "User Manuals"
+.TH IODINE 8 "JUN 2007" "User Manuals"
 .SH NAME
 iodine, iodined \- tunnel IPv4 over DNS
 .SH SYNOPSIS
@@ -16,7 +16,9 @@ iodine, iodined \- tunnel IPv4 over DNS
 .B ] [-d
 .I device
 .B ]
+.B [
 .I nameserver
+.B ]
 .I topdomain
 
 .B iodined [-v]
@@ -93,7 +95,8 @@ You must make sure the dns requests are forwarded to this port yourself.
 .B nameserver
 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.
-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
 file.
 .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
 replace the default gateway with the servers IP address within the DNS tunnel,
 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
 File bugs at http://dev.kryo.se/iodine/
 .SH AUTHORS
index ebf27e9af635a845ca84b6b449d3549ca141d805..958aa701b9e79265e8de9fdc36238b37a3403200 100644 (file)
@@ -1,8 +1,9 @@
 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
-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
-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"`
 ARCH = `uname -m`
@@ -15,15 +16,15 @@ all: stateos $(CLIENT) $(SERVER) $(TESTSUITE)
 stateos:
        @echo OS is $(OS), arch is $(ARCH)
 
-$(CLIENT): $(CLIENTOBJS)
+$(CLIENT): $(COMMONOBJS) $(CLIENTOBJS)
        @echo LD $@
        @mkdir -p ../bin
-       @$(CC) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
+       @$(CC) $(COMMONOBJS) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
 
-$(SERVER): $(SERVEROBJS)
+$(SERVER): $(COMMONOBJS) $(SERVEROBJS)
        @echo LD $@
        @mkdir -p ../bin
-       @$(CC) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
+       @$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
 
 .c.o: 
        @echo CC $<
index 73576045606e72d644f515c7626b423c0d6715b1..d42c5e97a5602a7ec1698b0307cf44e26cd0a937 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <stdlib.h>
 #include <string.h>
 
+#include "encoding.h"
 #include "base32.h"
 
 static const char cb32[] = 
        "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 
+base32_handles_dots()
+{
+       return 0;
+}
 
 int 
-base32_encode(char **buf, size_t *buflen, const void *data, size_t size)
+base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
 {
        size_t newsize;
-       char *newbuf;
-       char *s;
-       char *p;
-       char *q;
+       size_t maxsize;
+       unsigned char *s;
+       unsigned char *p;
+       unsigned char *q;
        int i;
 
-       newsize = 8 * (size / 5 + 1) + 1;
-       if (newsize > *buflen) {
-               if ((newbuf = realloc(*buf, newsize)) == NULL) {
-                       free(*buf);
-                       *buf = NULL;
-                       *buflen = 0;
-                       return 0;
-               }
+       memset(buf, 0, *buflen);
 
-               *buf = newbuf;
-               *buflen = newsize;
+       /* how many chars can we encode within the buf */
+       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;
-       q = (char*)data;
+       p = s = (unsigned char *) buf;
+       q = (unsigned char *)data;
 
        for(i=0;i<size;i+=5) {
-               p[0] = cb32[(q[0] >> 3)];
-               p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)];
+               p[0] = cb32[((q[0] & 0xf8) >> 3)];
+               p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
                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[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[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\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[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
                
                q += 5;
                p += 8;
        }       
        *p = 0;
-       return strlen(s);
-}
 
-#define DECODE_ERROR 0xffffffff
+       /* store number of bytes from data that was used */
+       *buflen = size;
 
-static int
-pos(char c)
-{
-    const char *p;
-    for (p = cb32; *p; p++)
-               if (*p == c)
-                       return p - cb32;
-    return -1;
+       return strlen(buf) - 1;
 }
 
+#define DECODE_ERROR 0xffffffff
+#define REV32(x) rev32[(int) (x)]
+
 static int
-decode_token(const char *t, char *data
+decode_token(const unsigned char *t, unsigned char *data, size_t len
 {
-       int len;
-
-       len = strlen(t);
-
        if (len < 2)
                return 0;
 
-       data[0] = ((pos(t[0]) & 0x1f) << 3) | 
-                         ((pos(t[1]) & 0x1c) >> 2);
+       data[0] = ((REV32(t[0]) & 0x1f) << 3) | 
+                         ((REV32(t[1]) & 0x1c) >> 2);
        
        if (len < 4)
                return 1;
 
-       data[1] = ((pos(t[1]) & 0x03) << 6) | 
-                         ((pos(t[2]) & 0x1f) << 1) | 
-                         ((pos(t[3]) & 0x10) >> 4);
+       data[1] = ((REV32(t[1]) & 0x03) << 6) | 
+                         ((REV32(t[2]) & 0x1f) << 1) | 
+                         ((REV32(t[3]) & 0x10) >> 4);
 
        if (len < 5)
                return 2;
 
-       data[2] = ((pos(t[3]) & 0x0f) << 4) |
-                         ((pos(t[4]) & 0x1e) >> 1);
+       data[2] = ((REV32(t[3]) & 0x0f) << 4) |
+                         ((REV32(t[4]) & 0x1e) >> 1);
 
        if (len < 7)
                return 3;
 
-       data[3] = ((pos(t[4]) & 0x01) << 7) |
-                         ((pos(t[5]) & 0x1f) << 2) |
-                         ((pos(t[6]) & 0x18) >> 3);
+       data[3] = ((REV32(t[4]) & 0x01) << 7) |
+                         ((REV32(t[5]) & 0x1f) << 2) |
+                         ((REV32(t[6]) & 0x18) >> 3);
 
        if (len < 8)
                return 4;
 
-       data[4] = ((pos(t[6]) & 0x07) << 5) |
-                         ((pos(t[7]) & 0x1f));
+       data[4] = ((REV32(t[6]) & 0x07) << 5) |
+                         ((REV32(t[7]) & 0x1f));
 
        return 5;
 }
 
 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;
        size_t newsize;
+       size_t maxsize;
        const char *p;
-       char *newbuf;
+       unsigned char c;
        int len;
-       
-       newsize = 5 * (strlen(str) / 8 + 1) + 1;
-       if (newsize > *buflen) {
-               if ((newbuf = realloc(*buf, newsize)) == NULL) {
-                       free(*buf);
-                       *buf = NULL;
-                       *buflen = 0;
-                       return 0;
-               }
+       int i;
 
-               *buf = newbuf;
-               *buflen = newsize;
+       if (!reverse_init) {
+               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) {
-               len = decode_token(p, (char *) q);      
+               len = decode_token((unsigned char *) p, (unsigned char *) q, slen);     
                q += len;
+               slen -= 8;
                
                if (len < 5)
                        break;
        }
        *q = '\0';
        
-       return q - (unsigned char *) *buf;
+       return q - (unsigned char *) buf;
 }
 
index be3b7ea8daadb4aa3e949aeb602084ecef6ac185..fa9415114ed10329a2ef98976cec1b2f20a6cda9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,9 @@
 #ifndef __BASE32_H__
 #define __BASE32_H__
 
-int base32_encode(char **, size_t *, const void *, size_t);
-int base32_decode(void **, size_t *, const char *);
+struct encoder *get_base32_encoder(void);
+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
diff --git a/src/base64.c b/src/base64.c
new file mode 100644 (file)
index 0000000..512a199
--- /dev/null
@@ -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;
+}
+
diff --git a/src/base64.h b/src/base64.h
new file mode 100644 (file)
index 0000000..6ee0656
--- /dev/null
@@ -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
index 521d2e6e75cfab2ab842aebe69606de1144815a9..73cf24d24e051030f5dfe0551943e12a914bdeb1 100644 (file)
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <ctype.h>
+#include <termios.h>
 
 #include "common.h"
 
@@ -71,13 +72,11 @@ close_dns(int fd)
 void
 do_chroot(char *newroot)
 {
-       if (newroot) {
-               if (chroot(newroot) != 0 || chdir("/") != 0)
-                       err(1, "%s", newroot);
+       if (chroot(newroot) != 0 || chdir("/") != 0)
+               err(1, "%s", newroot);
 
-               seteuid(geteuid());
-               setuid(getuid());
-       }
+       seteuid(geteuid());
+       setuid(getuid());
 }
 
 void
@@ -88,3 +87,27 @@ do_detach()
        umask(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';
+}
index 40b80f147bc636ebc16232a80288af73c6b63d85..811aa40a635aac4c9c325b9e85eab64cbd77a60c 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __COMMON_H__
 #define __COMMON_H__
 
+#include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
 #define MAX(a,b) ((a)>(b)?(a):(b))
 #endif
 
+#define QUERY_NAME_SIZE 256
+
 struct packet 
 {
-       int len;
-       int offset;
-       char data[64*1024];
+       int len;                /* Total packet length */
+       int sentlen;            /* Length of chunk currently transmitted */
+       int offset;             /* Current offset */
+       char data[64*1024];     /* The data */
 };
 
 struct query {
-       char name[258];
+       char name[QUERY_NAME_SIZE];
        short type;
        short id;
        struct sockaddr from;
@@ -48,4 +52,6 @@ void close_dns(int);
 void do_chroot(char *);
 void do_detach();
 
+void read_password(char*, size_t);
+
 #endif
index f50ffc86a258f1c45a17c504ef2b1aea423bc30d..1b6dd60dab0a78c55ba43cb93ba1f4f3dbfe8ee2 100644 (file)
--- a/src/dns.c
+++ b/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);
 
-               putname(&p, 256, q->name);
+               putname(&p, sizeof(q->name), q->name);
 
                putshort(&p, q->type);
                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->arcount = htons(1);
        
-               putname(&p, 256, data);
+               putname(&p, datalen, data);
 
                putshort(&p, q->type);
                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
 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];
        HEADER *header;
        short qdcount;
        short ancount;
-       char name[255];
        uint32_t ttl;
        short class;
        short type;
@@ -137,7 +137,29 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
        switch (qr) {
        case QR_ANSWER:
                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;
                }
 
@@ -167,8 +189,8 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                        return -1;
                }
 
-               readname(packet, packetlen, &data, name, sizeof(name) -1);
-               name[256] = 0;
+               readname(packet, packetlen, &data, name, sizeof(name) - 1);
+               name[sizeof(name)-1] = '\0';
                readshort(packet, &data, &type);
                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;
                }
 
-               strncpy(q->name, name, 257);
+               strncpy(q->name, name, sizeof(q->name));
+               q->name[sizeof(q->name) - 1] = '\0';
                q->type = type;
                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;
 }
 
-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;
-}
-
index 5a96f225f4de73446447d01b7ff1466d14620234..0ced1f193bd126b48b9910cc334b43a7b945aca2 100644 (file)
--- a/src/dns.h
+++ b/src/dns.h
@@ -24,8 +24,6 @@ typedef enum {
        QR_ANSWER = 1
 } 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_decode(char *, size_t, struct query *, qr_t, char *, size_t);
 
index 4de10c63593b2ac9457c1bc7e5df57f41d85929c..127e87190050b9697cf1c023855ae3b6af9d7fe6 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <stdio.h>
-#include <strings.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)
+int
+unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
 {
-       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;
+       if (!enc->eats_dots())
+               datalen = inline_undotify(data, datalen);
+       return enc->decode(buf, &buflen, data, datalen);
 }
 
-int
-encode_data(const char *buf, const size_t len, int space, char *dest)
+int 
+inline_dotify(char *buf, size_t buflen)
 {
-       int final;
-       int write;
-       int realwrite;
-       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--;
+       unsigned dots;
+       unsigned pos;
+       unsigned total;
+       char *reader, *writer;
+
+       total = strlen(buf);
+       dots = total / 62;
+
+       writer = buf;
+       writer += total;
+       writer += dots;
+
+       total += dots;
+       if (strlen(buf) + dots > buflen) {
+               writer = buf;
+               writer += buflen;
+               total = buflen;
        }
-       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);
+       reader = writer - dots;
+       pos = (unsigned) (reader - buf) + 1;
 
-               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++;
+       while (dots) {
+               if (pos % 62 == 0) {
+                       *writer-- = '.';
+                       dots--;
                }
+               *writer-- = *reader--;
+               pos--;
        }
-       
-       return write;
+
+       /* return new length of string */
+       return total;
 }
 
-int
-decode_data(char *dest, int size, const char *src, char *srcend)
+int 
+inline_undotify(char *buf, size_t len)
 {
-       int len;
-       int i;
-       int chunks;
-       int padded;
-       char encoded[255];
-       char padding[5];
-       int enclen;
-       char *pp;
-       char *ep;
+       unsigned pos;
+       unsigned dots;
+       char *reader, *writer;
 
-       memset(encoded, 0, sizeof(encoded));
-       memset(dest, 0, size);
+       writer = buf;
+       reader = writer;
 
-       /* First byte is not encoded */
-       *dest++ = *src++;
-       len = 1;
+       pos = 0;
+       dots = 0;
 
-       ep = encoded;
-       enclen = 0;
-       while(enclen < sizeof(encoded) && src < srcend) {
-               if(*src == '.') {
-                       src++;
+       while (pos < len) {
+               if (*reader == '.') {
+                       reader++;
+                       pos++;
+                       dots++;
                        continue;
                }
-
-               *ep++ = *src++;
-               enclen++;
-       }
-       chunks = enclen / 8;
-       padded = enclen % 8;
-
-       ep = encoded;
-       for (i = 0; i < chunks-1; i++) {
-               decode_chunk(dest, ep);
-               dest += RAW_CHUNK;
-               ep += ENC_CHUNK;
-               len += RAW_CHUNK;
+               *writer++ = *reader++;
+               pos++;
        }
-       /* 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;
+       
+       /* return new length of string */
+       return len - dots;
 }
-
index 2e4351b6b5602d193be88c260980e958539cb76e..4473b2ff973cdd86d3bb03fa61212b852247f58b 100644 (file)
 #ifndef _ENCODING_H_
 #define _ENCODING_H_
 
-int encode_data(const char *, const size_t, int, char *);
-int decode_data(char *, int, const char *, char *);
+struct encoder {
+       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_ */
index a26281f8d78f1e71eaa250a991872d6562f29f86..3b2cc6144337a87ed2fbfab38ddd24eb8551cd36 100644 (file)
@@ -23,6 +23,7 @@
 #include <netdb.h>
 #include <netinet/in.h>
 #include <sys/types.h>
+#include <sys/time.h>
 #include <sys/socket.h>
 #include <fcntl.h>
 #include <err.h>
@@ -35,6 +36,8 @@
 #endif
 
 #include "common.h"
+#include "encoding.h"
+#include "base32.h"
 #include "dns.h"
 #include "login.h"
 #include "tun.h"
 
 static void send_ping(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;
-char password[33];
+static int running = 1;
+static char password[33];
 
-struct sockaddr_in peer;
+static struct sockaddr_in nameserv;
 static char *topdomain;
 
-uint16_t rand_seed;
+static uint16_t rand_seed;
 
 /* Current IP packet */
-static char activepacket[4096];
+static struct packet packet;
+
+/* My userid at the server */
 static char userid;
-static int lastlen;
-static int packetpos;
-static int packetlen;
+
+/* DNS id for next packet */
 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
 sighandler(int sig) 
 {
@@ -66,57 +83,96 @@ sighandler(int sig)
 }
 
 static void
-send_packet(int fd, char cmd, const char *data, const size_t datalen)
+send_query(int fd, char *hostname)
 {
        char packet[4096];
        struct query q;
-       char buf[4096];
        size_t len;
 
        q.id = ++chunkid;
        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;
        
-       len = dns_build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain);
-       len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
+       build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32);
+       send_query(fd, buf);
+}
+
+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);
 
-       sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
+       if (*b != '.') 
+               *b++ = '.';
+
+       strncpy(b, topdomain, strlen(topdomain)+1);
+
+       return space;
 }
 
 int
 is_sending()
 {
-       return (packetlen != 0);
+       return (packet.len != 0);
 }
 
 int
 read_dns(int fd, char *buf, int buflen)
 {
        struct sockaddr_in from;
-       char packet[64*1024];
+       char data[64*1024];
        socklen_t addrlen;
        struct query q;
        int rv;
        int r;
 
        addrlen = sizeof(struct sockaddr);
-       if ((r = recvfrom(fd, packet, sizeof(packet), 0, 
-                                         (struct sockaddr*)&from, &addrlen)) == -1) {
+       if ((r = recvfrom(fd, data, sizeof(data), 0, 
+                         (struct sockaddr*)&from, &addrlen)) == -1) {
                warn("recvfrom");
                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) {
                /* Got ACK on sent packet */
-               packetpos += lastlen;
-               if (packetpos == packetlen) {
+               packet.offset += packet.sentlen;
+               if (packet.offset == packet.len) {
                        /* Packet completed */
-                       packetpos = 0;
-                       packetlen = 0;
-                       lastlen = 0;
+                       packet.offset = 0;
+                       packet.len = 0;
+                       packet.sentlen = 0;
                } else {
                        /* More to send */
                        send_chunk(fd);
@@ -142,10 +198,10 @@ tunnel_tun(int tun_fd, int dns_fd)
        inlen = read;
        compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
 
-       memcpy(activepacket, out, MIN(outlen, sizeof(activepacket)));
-       lastlen = 0;
-       packetpos = 0;
-       packetlen = outlen;
+       memcpy(packet.data, out, MIN(outlen, sizeof(packet.data)));
+       packet.sentlen = 0;
+       packet.offset = 0;
+       packet.len = outlen;
 
        send_chunk(dns_fd);
 
@@ -224,33 +280,26 @@ static void
 send_chunk(int fd)
 {
        char hex[] = "0123456789ABCDEF";
-       char packet[4096];
-       struct query q;
        char buf[4096];
        int avail;
        int code;
        char *p;
-       int len;
-
-       q.id = ++chunkid;
-       q.type = T_NULL;
 
-       p = activepacket;
-       p += packetpos;
-       avail = packetlen - packetpos;
+       p = packet.data;
+       p += packet.offset;
+       avail = packet.len - packet.offset;
 
-       lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain);
+       packet.sentlen = build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain, dataenc);
 
-       if (lastlen == avail)
+       if (packet.sentlen == avail)
                code = 1;
        else
                code = 0;
                
        code |= (userid << 1);
        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
@@ -276,9 +325,9 @@ send_ping(int fd)
        char data[3];
        
        if (is_sending()) {
-               lastlen = 0;
-               packetpos = 0;
-               packetlen = 0;
+               packet.sentlen = 0;
+               packet.offset = 0;
+               packet.len = 0;
        }
 
        data[0] = userid;
@@ -308,6 +357,15 @@ send_version(int fd, uint32_t version)
        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
 handshake(int dns_fd)
 {
@@ -339,15 +397,15 @@ handshake(int dns_fd)
                        read = read_dns(dns_fd, in, sizeof(in));
                        
                        if(read < 0) {
-                               perror("read");
+                               warn("handshake read");
                                continue;
                        }
 
                        if (read >= 9) {
                                payload =  (((in[4] & 0xff) << 24) |
-                                                       ((in[5] & 0xff) << 16) |
-                                                       ((in[6] & 0xff) << 8) |
-                                                       ((in[7] & 0xff)));
+                                               ((in[5] & 0xff) << 16) |
+                                               ((in[6] & 0xff) << 8) |
+                                               ((in[7] & 0xff)));
 
                                if (strncmp("VACK", in, 4) == 0) {
                                        seed = payload;
@@ -405,7 +463,7 @@ perform_login:
                                        client[64] = 0;
                                        if (tun_setip(client) == 0 && 
                                                tun_setmtu(mtu) == 0) {
-                                               return 0;
+                                               goto perform_case_check;
                                        } else {
                                                warnx("Received handshake with bad data");
                                        }
@@ -417,23 +475,98 @@ perform_login:
 
                printf("Retrying login...\n");
        }
+       errx(1, "couldn't login to server");
+       /* NOTREACHED */
+
+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);
 
-       return 1;
+               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 
-set_target(const char *host
+static void
+set_nameserver(const char *cp
 {
-       struct hostent *h;
+       struct in_addr addr;
 
-       h = gethostbyname(host);
-       if (!h)
-               err(1, "couldn't resolve name %s", host);
+       if (inet_aton(cp, &addr) != 1)
+               errx(1, "error parsing nameserver address: '%s'", cp);
 
-       memset(&peer, 0, sizeof(peer));
-       peer.sin_family = AF_INET;
-       peer.sin_port = htons(53);
-       peer.sin_addr = *((struct in_addr *) h->h_addr);
+       memset(&nameserv, 0, sizeof(nameserv));
+       nameserv.sin_family = AF_INET;
+       nameserv.sin_port = htons(53);
+       nameserv.sin_addr = addr;
 }
 
 static void
@@ -441,7 +574,7 @@ usage() {
        extern char *__progname;
 
        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
-                       "nameserver topdomain\n", __progname);
+                       "[nameserver] topdomain\n", __progname);
        exit(2);
 }
 
@@ -451,7 +584,7 @@ help() {
 
        printf("iodine IP over DNS tunneling client\n");
        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("  -h to print this help and exit\n");
        printf("  -f to keep running in foreground\n");
@@ -459,7 +592,7 @@ help() {
        printf("  -t dir to chroot to directory dir\n");
        printf("  -d device to set tunnel device name\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");
 
        exit(0);
@@ -469,7 +602,7 @@ static void
 version() {
 
        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);
 }
@@ -477,6 +610,7 @@ version() {
 int
 main(int argc, char **argv)
 {
+       char *nameserv_addr;
        struct passwd *pw;
        char *username;
        int foreground;
@@ -492,6 +626,9 @@ main(int argc, char **argv)
        newroot = NULL;
        device = NULL;
        chunkid = 0;
+
+       b32 = get_base32_encoder();
+       dataenc = get_base32_encoder();
        
        while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
                switch(choice) {
@@ -514,8 +651,11 @@ main(int argc, char **argv)
                        device = optarg;
                        break;
                case 'P':
-                       strncpy(password, optarg, 32);
-                       password[32] = 0;
+                       strncpy(password, optarg, sizeof(password));
+                       password[sizeof(password)-1] = 0;
+                       
+                       /* XXX: find better way of cleaning up ps(1) */
+                       memset(optarg, 0, strlen(optarg)); 
                        break;
                default:
                        usage();
@@ -524,37 +664,48 @@ main(int argc, char **argv)
        }
        
        if (geteuid() != 0) {
-               printf("Run as root and you'll be happy.\n");
+               warnx("Run as root and you'll be happy.\n");
                usage();
        }
 
        argc -= 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();
+               /* NOTREACHED */
+       }
 
-       topdomain = strdup(argv[1]);
+       set_nameserver(nameserv_addr);
+
+       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) {
-               pw = getpwnam(username);
-               if (!pw) {
-                       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();
                }
        }
        
-       if (strlen(password) == 0) {
-               printf("Enter password on stdin:\n");
-               scanf("%32s", password);
-               password[32] = 0;
-       }
+       if (strlen(password) == 0) 
+               read_password(password, sizeof(password));
 
        if ((tun_fd = open_tun(device)) == -1)
                goto cleanup1;
        if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
                goto cleanup2;
-       set_target(argv[0]);
 
        signal(SIGINT, sighandler);
        signal(SIGTERM, sighandler);
@@ -562,21 +713,21 @@ main(int argc, char **argv)
        if(handshake(dns_fd))
                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);
+
+       if (foreground == 0) 
+               do_detach();
 
-       do_chroot(newroot);
+       if (newroot != NULL)
+               do_chroot(newroot);
        
-       if (username) {
+       if (username != NULL) {
                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();
                }
        }
        
-       if (!foreground) {
-               do_detach();
-       }
-
        tunnel(tun_fd, dns_fd);
 
 cleanup2:
index 950b0d88446b67e4129a1323aeebd59e3e78e1c0..17f27cc584fae0619fadc41fafa77afa279ef572 100644 (file)
@@ -21,6 +21,7 @@
 #include <signal.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/time.h>
 #include <sys/socket.h>
 #include <fcntl.h>
 #include <err.h>
 
 #include "common.h"
 #include "dns.h"
+#include "encoding.h"
+#include "base32.h"
 #include "user.h"
 #include "login.h"
 #include "tun.h"
-#include "encoding.h"
 #include "version.h"
 
-int running = 1;
-
-char *topdomain;
+static int running = 1;
+static char *topdomain;
+static char password[33];
+static struct encoder *b32;
 
-char password[33];
-
-int my_mtu;
-in_addr_t my_ip;
+static int my_mtu;
+static in_addr_t my_ip;
 
 static int read_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 out[64*1024];
        char in[64*1024];
+       char unpacked[64*1024];
        char *tmp[2];
        int userid;
        int touser;
@@ -145,37 +147,37 @@ tunnel_dns(int tun_fd, int dns_fd)
                return 0;
                                
        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 */
                if (read > 4) { 
                        /* 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) |
-                                          ((in[2] & 0xff) << 16) |
-                                          ((in[3] & 0xff) << 8) |
-                                          ((in[4] & 0xff)));
-
-                       if (version == VERSION) {
-                               userid = find_available_user();
-                               if (userid >= 0) {
-                                       users[userid].seed = rand();
-                                       memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
-                                       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);
-                               }
+               if (version == VERSION) {
+                       userid = find_available_user();
+                       if (userid >= 0) {
+                               users[userid].seed = rand();
+                               memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
+                               memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
+                               users[userid].addrlen = dummy.q.fromlen;
+                               users[userid].encoder = get_base32_encoder();
+                               send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
+                               users[userid].q.id = 0;
                        } 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 {
                        send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
                }
        } else if(in[0] == 'L' || in[0] == 'l') {
+               read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
                /* Login phase, handle auth */
-               userid = in[1];
+               userid = unpacked[0];
                if (userid < 0 || userid >= USERS) {
                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
                        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) {
                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
                } 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 */
 
                                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') {
+               read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
                /* Ping packet, store userid */
-               userid = in[1];
+               userid = unpacked[0];
                if (userid < 0 || userid >= USERS) {
                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
                        return 0; /* illegal id */
                }
                memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
                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')
                        || (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) {
                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
                } 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);
                        memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
                        users[userid].addrlen = dummy.q.fromlen;
-                       memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1);
-                       users[userid].inpacket.len += read - 1;
-                       users[userid].inpacket.offset += read - 1;
+                       memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
+                       users[userid].inpacket.len += read;
+                       users[userid].inpacket.offset += read;
 
                        if (code & 1) {
                                outlen = sizeof(out);
@@ -351,12 +364,17 @@ read_dns(int fd, struct query *q, char *buf, int buflen)
        if (r > 0) {
                dns_decode(buf, buflen, q, QR_QUERY, packet, r);
                domain = strstr(q->name, topdomain);
-               rv = decode_data(buf, buflen, q->name, domain);
-               q->fromlen = addrlen;
-               memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
-       } else if (r < 0) {     
+               if (domain) {
+                       rv = (int) (domain - q->name); 
+                       memcpy(buf, q->name, MIN(rv, buflen));
+                       q->fromlen = addrlen;
+                       memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
+               } else {
+                       rv = 0;
+               }
+       } else if (r < 0) { 
                /* Error */
-               perror("recvfrom");
+               warn("read dns");
                rv = 0;
        }
 
@@ -410,24 +428,24 @@ help() {
 static void
 version() {
        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);
 }
 
 int
 main(int argc, char **argv)
 {
-       int choice;
-       int tun_fd;
-       int dnsd_fd;
-       char *newroot;
+       in_addr_t listen_ip;
+       struct passwd *pw;
+       int foreground;
        char *username;
+       char *newroot;
        char *device;
-       int foreground;
-       int mtu;
-       struct passwd *pw;
-       in_addr_t listen_ip;
+       int dnsd_fd;
+       int tun_fd;
+       int choice;
        int port;
+       int mtu;
 
        username = NULL;
        newroot = NULL;
@@ -437,7 +455,9 @@ main(int argc, char **argv)
        listen_ip = INADDR_ANY;
        port = 53;
 
-       memset(password, 0, 33);
+       b32 = get_base32_encoder();
+
+       memset(password, 0, sizeof(password));
        srand(time(NULL));
        
        while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
@@ -474,8 +494,11 @@ main(int argc, char **argv)
                        }
                        break;
                case 'P':
-                       strncpy(password, optarg, 32);
-                       password[32] = 0;
+                       strncpy(password, optarg, sizeof(password));
+                       password[sizeof(password)-1] = 0;
+                       
+                       /* XXX: find better way of cleaning up ps(1) */
+                       memset(optarg, 0, strlen(optarg)); 
                        break;
                default:
                        usage();
@@ -487,7 +510,7 @@ main(int argc, char **argv)
        argv += optind;
 
        if (geteuid() != 0) {
-               printf("Run as root and you'll be happy.\n");
+               warnx("Run as root and you'll be happy.\n");
                usage();
        }
 
@@ -495,30 +518,30 @@ main(int argc, char **argv)
                usage();
 
        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) {
-               pw = getpwnam(username);
-               if (!pw) {
-                       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();
                }
        }
 
        if (mtu == 0) {
-               printf("Bad MTU given.\n");
+               warnx("Bad MTU given.\n");
                usage();
        }
 
        if (listen_ip == INADDR_NONE) {
-               printf("Bad IP address to listen on.\n");
+               warnx("Bad IP address to listen on.\n");
                usage();
        }
 
-       if (strlen(password) == 0) {
-               printf("Enter password on stdin:\n");
-               scanf("%32s", password);
-               password[32] = 0;
-       }
+       if (strlen(password) == 0)
+               read_password(password, sizeof(password));
 
        if ((tun_fd = open_tun(device)) == -1)
                goto cleanup0;
@@ -531,22 +554,22 @@ main(int argc, char **argv)
        my_mtu = mtu;
        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);
-       if (username) {
+       if (username != NULL) {
                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();
                }
        }
        
-       if (!foreground) {
-               do_detach();
-       }
-       
        tunnel(tun_fd, dnsd_fd);
 
 cleanup2:
index b3f942a2c677357c386dc3ee91b0b73ea251134e..a5cde37e242683e8b1ffceb8a4110d615c827ee3 100644 (file)
@@ -47,5 +47,6 @@ login_calculate(char *buf, int buflen, char *pass, int seed)
        md5_init(&ctx);
        md5_append(&ctx, temp, 32);
        md5_finish(&ctx, (unsigned char *) buf);
+
 }
 
index cdc91240a5680ea7bba6ea6122bccb582be2a691..144133d53bee4932acd86bff2379544b1e642f49 100644 (file)
--- a/src/tun.c
+++ b/src/tun.c
@@ -58,7 +58,9 @@ open_tun(const char *tun_device)
 
        if (tun_device != NULL) {
                strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
+               ifreq.ifr_name[IFNAMSIZ-1] = '\0';
                strncpy(if_name, tun_device, sizeof(if_name));
+               if_name[sizeof(if_name)-1] = '\0';
 
                if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
                        printf("Opened %s\n", ifreq.ifr_name);
@@ -102,6 +104,7 @@ open_tun(const char *tun_device)
        if (tun_device != NULL) {
                snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
                strncpy(if_name, tun_device, sizeof(if_name));
+               if_name[sizeof(if_name)-1] = '\0';
 
                if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
                        warn("open_tun: %s: %s", tun_name, strerror(errno));
@@ -140,7 +143,7 @@ close_tun(int tun_fd)
 }
 
 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)
        data += 4;
@@ -166,8 +169,8 @@ write_tun(int tun_fd, char *data, int len)
        return 0;
 }
 
-int 
-read_tun(int tun_fd, char *buf, int len) 
+ssize_t
+read_tun(int tun_fd, char *buf, size_t len) 
 {
 #if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
        /* FreeBSD/Darwin/NetBSD has no header */
@@ -181,6 +184,9 @@ int
 tun_setip(const char *ip)
 {
        char cmdline[512];
+#ifndef LINUX
+               int r;
+#endif
 
        if (inet_addr(ip) != INADDR_NONE) {
                snprintf(cmdline, sizeof(cmdline), 
@@ -191,8 +197,6 @@ tun_setip(const char *ip)
                
                printf("Setting IP of %s to %s\n", if_name, ip);
 #ifndef LINUX
-               int r;
-
                r = system(cmdline);
                if(r != 0) {
                        return r;
@@ -212,20 +216,20 @@ tun_setip(const char *ip)
 }
 
 int 
-tun_setmtu(const int mtu)
+tun_setmtu(const size_t mtu)
 {
        char cmdline[512];
 
        if (mtu > 200 && mtu < 1500) {
                snprintf(cmdline, sizeof(cmdline), 
-                               "/sbin/ifconfig %s mtu %d",
+                               "/sbin/ifconfig %s mtu %u",
                                if_name,
                                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);
        } else {
-               warn("MTU out of range: %d\n", mtu);
+               warn("MTU out of range: %u\n", mtu);
        }
 
        return 1;
index 2313b3aa9be0fdca8ece089be8acf6de43fbc686..72773defdcd6df7907b17f0a0e2aabdb14cf43e9 100644 (file)
--- a/src/tun.h
+++ b/src/tun.h
@@ -19,9 +19,9 @@
 
 int open_tun(const char *);
 void close_tun(int);
-int write_tun(int, char *, int);
-int read_tun(int, char *, int);
+int write_tun(int, char *, size_t);
+ssize_t read_tun(int, char *, size_t);
 int tun_setip(const char *);
-int tun_setmtu(const int);
+int tun_setmtu(const size_t);
 
 #endif /* _TUN_H_ */
index ed809b80bb624f8aa32538bd2aa76f3b883bfad6..6cbddfb8e1b00bc41b43c355b2656088a2df165f 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <string.h>
 #include <stdio.h>
+#include <stdint.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/socket.h>
+#include <fcntl.h>
+#include <err.h>
 #include <arpa/inet.h>
-#include <netinet/in.h>
 
 #include "common.h"
+#include "encoding.h"
 #include "user.h"
 
 struct user users[USERS];
index b947ea4bc2c63a0ba647d2392e55650620d2a86a..2d0d2ad35c7866002f1090c43c009e14e83015f4 100644 (file)
@@ -30,6 +30,7 @@ struct user {
        struct query q;
        struct packet inpacket;
        struct packet outpacket;
+       struct encoder *encoder;
 };
 
 extern struct user users[USERS];
index 8b9f6ca521487b6adf902f473f20aaa681966736..d12c2f9d62de4985ff1d870d6cbad688ccec8e7d 100644 (file)
@@ -19,7 +19,7 @@
 
 /* This is the version of the network protocol
    It is usually equal to the latest iodine version number */
-#define VERSION 0x00000400
+#define VERSION 0x00000402
 
 #endif /* _VERSION_H_ */
 
index c08d443b0b579b8bb672f9b1855353e88913007a..94e808e0d901bd9c95deb795c00c868f737aa3f8 100644 (file)
@@ -1,7 +1,7 @@
 CC = gcc
 TEST = test
-OBJS = test.o base32.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
+OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o 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"`
 
index 34a5da5c0dcb6b94866bc5c7b2aa0b707cc84e00..b020cda06fdcc40b75ceecabfd85bebd81d5e21a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <string.h>
 #include <errno.h>
 
+#include "encoding.h"
 #include "base32.h"
 #include "test.h"
 
-struct touple
+static struct tuple
 {
        char *a;
        char *b;
 } testpairs[] = {
+       { "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
        { "abc123", "mfrggmjsgm" },
        { NULL, NULL }  
 };
@@ -35,46 +37,37 @@ struct touple
 START_TEST(test_base32_encode)
 {
        size_t len;
-       char *buf;
+       char buf[4096];
        int val;
        int i;
 
-       len = 0;
-       buf = NULL;
-
        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(buf != NULL, "buf == NULL");
                fail_unless(strcmp(buf, testpairs[i].b) == 0, 
                                va_str("'%s' != '%s'", buf, testpairs[i].b));
        }
-
-       free(buf);
 }
 END_TEST
 
 START_TEST(test_base32_decode)
 {
        size_t len;
-       void *buf;
+       char buf[4096];
        int val;
        int i;
 
-       len = 0;
-       buf = NULL;
-
        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(buf != NULL, "buf == NULL");
                fail_unless(strcmp(buf, testpairs[i].a) == 0, 
                                va_str("'%s' != '%s'", buf, testpairs[i].a));
        }
-
-       free(buf);
 }
 END_TEST
 
diff --git a/tests/base64.c b/tests/base64.c
new file mode 100644 (file)
index 0000000..7f12bf4
--- /dev/null
@@ -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;
+}
index cbd737a7195d7617dc709ebb46962a2afa43fdc3..1311d33a49218f8230ab0777b1c266213cf6abd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include "common.h"
 #include "dns.h"
 #include "encoding.h"
+#include "base32.h"
 #include "test.h"
 
 static void dump_packet(char *, size_t);
 
 static char queryPacket[] = 
-       "\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x32\x41\x4A\x42\x43"
-       "\x55\x59\x54\x43\x50\x45\x42\x39\x47\x51\x39\x4C\x54\x45\x42\x55\x58"
-       "\x47\x49\x44\x55\x4E\x42\x53\x53\x41\x36\x44\x46\x4F\x4E\x39\x43\x41"
-       "\x5A\x44\x42\x32\x41\x41\x41\x41\x41\x36\x44\x42\x04\x6B\x72\x79\x6F"
-       "\x02\x73\x65\x00\x00\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00"
-       "\x00\x00";
+       "\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x2D\x41\x6A\x62\x63"
+       "\x75\x79\x74\x63\x70\x65\x62\x30\x67\x71\x30\x6C\x74\x65\x62\x75\x78"
+       "\x67\x69\x64\x75\x6E\x62\x73\x73\x61\x33\x64\x66\x6F\x6E\x30\x63\x61"
+       "\x7A\x64\x62\x6F\x72\x71\x71\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00"
+       "\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00";
 
 static char answerPacket[] = 
        "\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 *topdomain = "kryo.se";
        
-static char *queryData = "HELLO this is the test data";
-static char *recData = "AHELLO this is the test data"; /* The A flag is added */
+static char *innerData = "HELLO this is the test data";
 
 START_TEST(test_encode_query)
 {
        char buf[512];
        char resolv[512];
        struct query q;
+       struct encoder *enc;
        char *d;
-       int len;
+       size_t len;
        int ret;
 
        len = sizeof(buf);
@@ -70,9 +70,10 @@ START_TEST(test_encode_query)
        q.type = T_NULL;
        q.id = 1337;
        d = resolv;
+       enc = get_base32_encoder();
 
        *d++ = 'A';
-       encode_data(queryData, strlen(queryData), 100, d);
+       enc->encode(d, &len, innerData, strlen(innerData));
        d = resolv + strlen(resolv);
        if (*d != '.') {
                *d++ = '.';
@@ -96,20 +97,22 @@ START_TEST(test_decode_query)
        char buf[512];
        char *domain;
        struct query q;
-       int len;
-       int ret;
+       struct encoder *enc;
+       size_t len;
 
        memset(&q, 0, sizeof(struct query));
        memset(&buf, 0, sizeof(buf));
        q.id = 0;
        len = sizeof(queryPacket) - 1;
+       enc = get_base32_encoder();
 
        dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len);
        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(strlen(buf) == strlen(recData), va_str("Bad host length: %d, expected %d", strlen(q.name), strlen(recData)));
+       fail_unless(strncmp(buf, innerData, strlen(innerData)) == 0, "Did not extract expected host: '%s'", buf);
+       fail_unless(strlen(buf) == strlen(innerData), va_str("Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf));
 }
 END_TEST
 
index dcde87b5bb5ca14bedc62c2bbde7399ca637dd1d..fcfae492af3885cdae7f1c83477630324916b1c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include "encoding.h"
 #include "test.h"
 
-START_TEST(test_encoding_base32)
+struct tuple
 {
-       char temp[256];
-       char *start = "HELLOTEST";
-       char *out = "1HELLOTEST";
-       char end[256];
-       char *tempend;
-       int codedlength;
-
-       memset(temp, 0, sizeof(temp));
-       memset(end, 0, sizeof(end));
-
-       codedlength = encode_data(start, strlen(start), sizeof(temp) - 1, temp + 1);
-       temp[0] = '1';
-       tempend = temp + strlen(temp);
-       decode_data(end, sizeof(end), temp, tempend);
-
-       fail_unless(strcmp(out, end) == 0, NULL);
+       char *a;
+       char *b;
+} dottests[] = {
+       { "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 
+         "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a"},
+       { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 
+         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
+       { "abc123", "abc123" },
+       { NULL, NULL }
+};
+
+START_TEST(test_inline_dotify)
+{
+       unsigned i;
+       char temp[1024];
+       char *b;
+
+       i = 0;
+       while (dottests[i].a) {
+               memset(temp, 0, sizeof(temp));
+               strcpy(temp, dottests[i].a);
+               b = temp;
+               inline_dotify(b, sizeof(temp));
+
+               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
 
@@ -49,7 +81,8 @@ test_encoding_create_tests()
        TCase *tc;
 
        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;
 }
index cad9b9ac201db01a1f0fd5c4f31a69c52a92d2ed..b698b858d577b69e7655df44b7b7c3512be648fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index e0e447294560e9b027bc42ecf1017077c71bc758..14a139afe6f17b510f7dd1bd16b6b6138eb7bc07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 850d1f75324109ebcbf2efb7f3eb66fbbc4d5c35..b01417f558a9aef5ca8909dddbbabc901b96c0ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -49,6 +49,9 @@ main()
        test = test_base32_create_tests();
        suite_add_tcase(iodine, test);
 
+       test = test_base64_create_tests();
+       suite_add_tcase(iodine, test);
+
        test = test_dns_create_tests();
        suite_add_tcase(iodine, test);
 
index 492cd9bf9b66b6da45fc02ff1bafbf5c745563e9..413ae412b5a738ef361d7be861cf1edef5ee430a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,6 +18,7 @@
 #define __TEST_H__
 
 TCase *test_base32_create_tests();
+TCase *test_base64_create_tests();
 TCase *test_dns_create_tests();
 TCase *test_encoding_create_tests();
 TCase *test_read_create_tests();
index 8f3ee841d168e1e2ee9a8baed596e83459064187..7c3f87a25f861a998ff034a34c9d5524a8afb1af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,7 @@
 #include <netinet/in.h>
 
 #include "common.h"
+#include "encoding.h"
 #include "user.h"
 #include "test.h"