[svn-upgrade] Integrating new upstream version, iodine (0.5.1) upstream/0.5.1
authorgregor herrmann <gregoa@debian.org>
Sat, 21 Mar 2009 17:27:47 +0000 (17:27 -0000)
committergregor herrmann <gregoa@debian.org>
Sat, 21 Mar 2009 17:27:47 +0000 (17:27 -0000)
30 files changed:
CHANGELOG
Makefile
README
README-win32.txt [new file with mode: 0644]
man/iodine.8
src/Makefile
src/base32.c
src/base64.c
src/common.c
src/common.h
src/dns.c
src/dns.h
src/fw_query.c
src/fw_query.h
src/iodine.c
src/iodined.c
src/login.c
src/osflags
src/tun.c
src/user.c
src/windows.h [new file with mode: 0644]
tests/Makefile
tests/base32.c
tests/base64.c
tests/dns.c
tests/fw_query.c [new file with mode: 0644]
tests/login.c
tests/read.c
tests/test.c
tests/test.h

index 6f7fc936ca0e6767769e1b9b783cfda737254031..1b792b8b3881da68eba91021c4c9fbd393359e77 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,21 @@ iodine - http://code.kryo.se/iodine
 
 CHANGES:
 
+2009-03-21: 0.5.1 "Boringo"
+       - Added initial Windows support, fixes #43.
+       - Added length check of autoprobe responses
+       - Refactored and added unit tests
+       - Added syslog logging for iodined on version and login packets
+       - Fixed segfault when encoding just one block, fixes #51.
+               The normal code was never affected by this.
+       - Added win32 code to read DNS server from system, fixes #45.
+       - Disabled password echo on win32, fixes #44.
+       - Fix encoding error making all autoprobing > 1024 bytes fail, #52.
+       - Increase default interface MTU to 1200.
+       - Fix autoprobing error making every third probe fail, set IP flag
+               Dont-Fragment where supported. Fixes #54.
+       - Added TAP32 version 0901 as accepted (#53).
+
 2009-01-23: 0.5.0 "iPassed"
        - Fixed segfault in server when sending version reject.
        - Applied patch to make iodine build on BeOS R5-BONE and Haiku,
index 2f2bd101f225e55bb4b64d3447eb1c10d476b81b..01c232521ca8a19beb4003b24395bacab2a3b361 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,8 +14,25 @@ MKDIR_FLAGS=-p
 RM=rm
 RM_FLAGS=-f
 
+TARGETOS = `uname`
+
 all: 
-       @(cd src; $(MAKE) all)
+       @(cd src; $(MAKE) TARGETOS=$(TARGETOS) all)
+
+cross-mingw: 
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=i686-mingw32-gcc all)
+
+cross-mingw-dist: cross-mingw
+       @rm -rf iodine-latest-win32*
+       @mkdir -p iodine-latest-win32/bin
+       @for i in `ls bin`; do cp bin/$$i iodine-latest-win32/bin/$$i.exe; done
+       @cp /usr/i686-mingw32/usr/bin/zlib1.dll iodine-latest-win32/bin
+       @cp README* CH* TO* iodine-latest-win32
+       @echo "Create date: " > iodine-latest-win32/VERSION
+       @date >> iodine-latest-win32/VERSION
+       @echo "SVN version: " >> iodine-latest-win32/VERSION
+       @svnversion >> iodine-latest-win32/VERSION
+       @zip -r iodine-latest-win32.zip iodine-latest-win32
 
 install: all
        $(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
@@ -35,11 +52,11 @@ uninstall:
 test: all
        @echo "!! The check library is required for compiling and running the tests"
        @echo "!! Get it at http://check.sf.net"
-       @(cd tests; $(MAKE) all)
+       @(cd tests; $(MAKE) TARGETOS=$(TARGETOS) all)
 
 clean:
        @echo "Cleaning..."
        @(cd src; $(MAKE) clean)
        @(cd tests; $(MAKE) clean)
-       @rm -rf bin
+       @rm -rf bin iodine-latest-win32*
 
diff --git a/README b/README
index 4978c6eba32f090cb06a34abc94aa7a76e816d6e..cc201ada6a7fcf0dc609857dee11a6ead5954db2 100644 (file)
--- a/README
+++ b/README
@@ -93,10 +93,11 @@ 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 (ppc and x86, with
-http://tuntaposx.sourceforge.net/). It should be easy to port to other
-unix-like systems that has TUN/TAP tunneling support. Let us know if you get it
-to run on other platforms. 
+(ia64, x86), OpenBSD (x86), NetBSD (x86), MacOS X (ppc and x86, with
+http://tuntaposx.sourceforge.net/). and Windows (with OpenVPN TAP32 driver, see
+win32 readme file).  It should be easy to port to other unix-like systems that
+has TUN/TAP tunneling support. Let us know if you get it to run on other
+platforms. 
 
 
 THE NAME:
diff --git a/README-win32.txt b/README-win32.txt
new file mode 100644 (file)
index 0000000..1df7f64
--- /dev/null
@@ -0,0 +1,62 @@
+\r
+\r
+iodine - http://code.kryo.se/iodine\r
+\r
+***********************************\r
+\r
+Extra README file for Win32 related stuff\r
+\r
+\r
+== Running iodine on Windows:\r
+1. Install the TAP32 driver \r
+ http://openvpn.net/index.php/downloads.html \r
+ choose OpenVPN 2.0.9 Windows Installer, when installing you can\r
+ select to install only the TAP driver.\r
+\r
+2. Have one TAP32 interface installed\r
+\r
+3. Name the interface "dns"\r
+\r
+4. Make sure the interface does not have a default gateway set\r
+\r
+5. Run iodine/iodined as normal.\r
+\r
+6. Enjoy!\r
+\r
+\r
+== Building on Windows:\r
+You need:\r
+       MinGW, MSYS, GCC, zlib\r
+\r
+Then just run make\r
+\r
+\r
+== Cross-compiling for MinGW:\r
+You need:\r
+       MinGW crosscompiler, crosscompiled zlib\r
+\r
+Then run "make cross-mingw"\r
+Note that the binaries will not get a .exe suffix\r
+\r
+\r
+== Zlib download\r
+You can get zlib for MinGW here (both for native and crosscompile):\r
+http://code.kryo.se/iodine/deps/zlib.zip\r
+Unzip it in your MinGW directory on Windows or in $ROOT/usr for\r
+cross-compile.\r
+\r
+\r
+== Results of crappy Win32 API:\r
+The following fixable limitations apply:\r
+- Exactly one TAP32 interface must be installed\r
+- The TAP32 interface must be named "dns" and be version 0801 or 0901\r
+- Server cannot read packet destination address\r
+\r
+The following (probably) un-fixable limitations apply:\r
+- A password entered as -P argument can be shown in process list\r
+- Priviligies cannot be dropped\r
+- chroot() cannot be used\r
+- Detaching from terminal not possible\r
+- Server on windows must be run with /30 netmask\r
+- Client can only talk to server, not other clients\r
+\r
index 9eb88f01a7497e8fbfd38eb5fd0142dee14e7bf7..1eeac2bbf9b4df7406736cc4987a2a987248b044 100644 (file)
@@ -17,6 +17,8 @@ iodine, iodined \- tunnel IPv4 over DNS
 .I chrootdir
 .B ] [-d
 .I device
+.B ] [-m
+.I fragsize
 .B ]
 .B [
 .I nameserver
index 8197c4d12bad78ff54e74214732b8a33f97f7f4a..fe15d934aa95a026feffa2d005d34e42f0c6dd1d 100644 (file)
@@ -5,11 +5,12 @@ CLIENT = ../bin/iodine
 SERVEROBJS = iodined.o user.o fw_query.o
 SERVER = ../bin/iodined
 
-OS = `uname | tr "a-z" "A-Z"`
+OS = `echo $(TARGETOS) | tr "a-z" "A-Z"`
 ARCH = `uname -m`
 
-LDFLAGS =  -lz `sh osflags link`
-CFLAGS = -c -g -Wall -D$(OS) -pedantic `sh osflags cflags`
+LIBPATH = -L.
+LDFLAGS =  -lz `sh osflags $(TARGETOS) link` $(LIBPATH)
+CFLAGS = -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags`
 
 all: stateos $(CLIENT) $(SERVER)
 
@@ -32,5 +33,5 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
 
 clean:
        @echo "Cleaning src/"
-       @rm -f $(CLIENT) $(SERVER) *~ *.o *.core
+       @rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core
 
index af6a2147ac1fa5cf8a3141f7d1327089801483c0..5ee066468694bb5009c7b43ffbdd09a1264e1416 100644 (file)
@@ -27,7 +27,6 @@
 static const char cb32[] = 
        "abcdefghijklmnopqrstuvwxyz012345";
 static unsigned char rev32[128];
-static int reverse_init = 0;
 
 static int base32_decode(void *, size_t *, const char *, size_t);
 static int base32_encode(char *, size_t *, const void *, size_t);
@@ -70,17 +69,13 @@ base32_blksize_enc()
        return BLKSIZE_ENC;
 }
 
-int
-b32_5to8(int in)
-{
-       return cb32[in & 31];
-}
-
-int
-b32_8to5(int in)
+static void
+base32_reverse_init()
 {
        int i;
-       int c;
+       unsigned char c;
+       static int reverse_init = 0;
+
        if (!reverse_init) {
                for (i = 0; i < 32; i++) {
                        c = cb32[i];
@@ -88,6 +83,18 @@ b32_8to5(int in)
                }
                reverse_init = 1;
        }
+}
+
+int
+b32_5to8(int in)
+{
+       return cb32[in & 31];
+}
+
+int
+b32_8to5(int in)
+{
+       base32_reverse_init();
        return rev32[in];
 }
 
@@ -103,9 +110,12 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
        memset(buf, 0, *buflen);
 
        /* how many chars can we encode within the buf */
-       maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
+       maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
        /* how big will the encoded data be */
-       newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
+       newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
+       if (size % BLKSIZE_RAW) {
+               newsize += BLKSIZE_ENC;
+       }
        /* if the buffer is too small, eat some of the data */
        if (*buflen < newsize) {
                size = maxsize;
@@ -132,7 +142,7 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
        /* store number of bytes from data that was used */
        *buflen = size;
 
-       return strlen(buf) - 1;
+       return strlen(buf);
 }
 
 #define DECODE_ERROR 0xffffffff
@@ -183,17 +193,9 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
        size_t newsize;
        size_t maxsize;
        const char *p;
-       unsigned char c;
        int len;
-       int i;
 
-       if (!reverse_init) {
-               for (i = 0; i < 32; i++) {
-                       c = cb32[i];
-                       rev32[(int) c] = i;
-               }
-               reverse_init = 1;
-       }
+       base32_reverse_init();
        
        /* chars needed to decode slen */
        newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
index 803d938a6c85e157235ebf913c05b727df046db1..7da2d2a6e8413984e40fcb5f28ecb360b8b669ca 100644 (file)
@@ -78,7 +78,6 @@ 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;
@@ -86,18 +85,14 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
 
        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 = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
+       maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
        /* how big will the encoded data be */
-       newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
+       newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
+       if (size % BLKSIZE_RAW) {
+               newsize += BLKSIZE_ENC;
+       }
+
        /* if the buffer is too small, eat some of the data */
        if (*buflen < newsize) {
                size = maxsize;
@@ -120,7 +115,7 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
        /* store number of bytes from data that was used */
        *buflen = size;
 
-       return strlen(buf) - 1;
+       return strlen(buf);
 }
 
 #define DECODE_ERROR 0xffffffff
index 9b32f844819d721951b2cbb1e52d1c488d504a02..8511498f2ee1ab80fd34c80aa701333190091bac 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <netinet/in.h>
-#ifdef DARWIN
-#include <arpa/nameser8_compat.h>
-#endif
 #include <time.h>
-#include <err.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <string.h>
 #include <ctype.h>
 #include <fcntl.h>
+
+#ifdef WINDOWS32
+#include <winsock2.h>
+#include <conio.h>
+#else
+#include <arpa/nameser.h>
+#ifdef DARWIN
+#include <arpa/nameser8_compat.h>
+#endif
 #include <termios.h>
+#include <err.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#endif
 
 #include "common.h"
 
 /* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
-#if !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
+#if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
 static int daemon(int nochdir, int noclose)
 {
        int fd, i;
@@ -82,11 +88,24 @@ int setgroups(int count, int *groups)
 }
 #endif
 
+
+void
+check_superuser(void (*usage_fn)(void))
+{
+#ifndef WINDOWS32
+       if (geteuid() != 0) {
+               warnx("Run as root and you'll be happy.\n");
+               usage_fn();
+               /* NOTREACHED */
+       }
+#endif
+}
+
 int 
 open_dns(int localport, in_addr_t listen_ip) 
 {
        struct sockaddr_in addr;
-       int flag;
+       int flag = 1;
        int fd;
 
        memset(&addr, 0, sizeof(addr));
@@ -95,22 +114,32 @@ open_dns(int localport, in_addr_t listen_ip)
        /* listen_ip already in network byte order from inet_addr, or 0 */
        addr.sin_addr.s_addr = listen_ip; 
 
-       if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+       if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+               fprintf(stderr, "got fd %d\n", fd);
                err(1, "socket");
+       }
 
        flag = 1;
 #ifdef SO_REUSEPORT
-       setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
+       setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));
 #endif
-       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
+       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
 
+#ifndef WINDOWS32
        /* To get destination address from each UDP datagram, see iodined.c:read_dns() */
-       setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, &flag, sizeof(flag));
+       setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
+#endif
+
+#ifdef IP_OPT_DONT_FRAG
+       /* Set dont-fragment ip header flag */
+       flag = DONT_FRAG_VALUE;
+       setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
+#endif
 
        if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
                err(1, "bind");
 
-       printf("Opened UDP socket\n");
+       fprintf(stderr, "Opened UDP socket\n");
 
        return fd;
 }
@@ -124,7 +153,7 @@ close_dns(int fd)
 void
 do_chroot(char *newroot)
 {
-#if !defined(__BEOS__) || defined(__HAIKU__)
+#if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))
        if (chroot(newroot) != 0 || chdir("/") != 0)
                err(1, "%s", newroot);
 
@@ -138,31 +167,54 @@ do_chroot(char *newroot)
 void
 do_detach()
 {
-       printf("Detaching from terminal...\n");
+#ifndef WINDOWS32
+       fprintf(stderr, "Detaching from terminal...\n");
        daemon(0, 0);
        umask(0);
        alarm(0);
+#else
+       fprintf(stderr, "Windows version does not support detaching\n");
+#endif
 }
 
 void
 read_password(char *buf, size_t len)
 {
+       char pwd[80];
+#ifndef WINDOWS32
        struct termios old;
        struct termios tp;
-       char pwd[80];
 
        tcgetattr(0, &tp);
        old = tp;
        
        tp.c_lflag &= (~ECHO);
        tcsetattr(0, TCSANOW, &tp);
+#else
+       int i;
+#endif
 
-       printf("Enter password: ");
-       fflush(stdout);
+       fprintf(stderr, "Enter password: ");
+       fflush(stderr);
+#ifndef WINDOWS32
        scanf("%79s", pwd);
-       printf("\n");
+#else
+       for (i = 0; i < sizeof(pwd); i++) {
+               pwd[i] = getch();
+               if (pwd[i] == '\r' || pwd[i] == '\n') {
+                       pwd[i] = 0;
+                       break;
+               } else if (pwd[i] == '\b') {
+                       i--;                    /* Remove the \b char */
+                       if (i >=0) i--;         /* If not first char, remove one more */
+               }
+       }
+#endif
+       fprintf(stderr, "\n");
 
+#ifndef WINDOWS32
        tcsetattr(0, TCSANOW, &old);    
+#endif
 
        strncpy(buf, pwd, len);
        buf[len-1] = '\0';
@@ -184,3 +236,61 @@ check_topdomain(char *str)
        }
        return 0;
 }
+
+#ifdef WINDOWS32
+int
+inet_aton(const char *cp, struct in_addr *inp)
+{
+ inp->s_addr = inet_addr(cp);
+ return inp->s_addr != INADDR_ANY;
+}
+
+void
+warn(const char *fmt, ...)
+{
+       va_list list;
+
+       va_start(list, fmt);
+       if (fmt) fprintf(stderr, fmt, list);
+       if (errno == 0) {
+               fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); 
+       } else {
+               fprintf(stderr, ": %s\n", strerror(errno));
+       }
+       va_end(list);
+}
+
+void
+warnx(const char *fmt, ...)
+{
+       va_list list;
+
+       va_start(list, fmt);
+       if (fmt) fprintf(stderr, fmt, list);
+       fprintf(stderr, "\n");
+       va_end(list);
+}
+
+void
+err(int eval, const char *fmt, ...)
+{
+       va_list list;
+
+       va_start(list, fmt);
+       warn(fmt, list);
+       va_end(list);
+       exit(eval);
+}
+
+void
+errx(int eval, const char *fmt, ...)
+{
+       va_list list;
+
+       va_start(list, fmt);
+       warnx(fmt, list);
+       va_end(list);
+       exit(eval);
+}
+#endif
+
index edc8e82f84e6fed57be223498c2c819c2ad6721f..f39461ac18e7a279b3d8dbd1d1abe28346382f59 100644 (file)
 #ifndef __COMMON_H__
 #define __COMMON_H__
 
-#include <arpa/inet.h>
-#include <sys/types.h>
+#ifdef WINDOWS32
+#include "windows.h"
+#else
 #include <sys/socket.h>
+#include <err.h>
+#include <arpa/inet.h>
 #include <netinet/in.h>
+#endif
+
 
 #ifndef MIN
 #define MIN(a,b) ((a)<(b)?(a):(b))
 # define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr)) 
 #endif
 
+#if defined IP_MTU_DISCOVER
+  /* Linux */
+# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER
+# define DONT_FRAG_VALUE IP_PMTUDISC_DO
+#elif defined IP_DONTFRAG
+  /* FreeBSD */
+# define IP_OPT_DONT_FRAG IP_DONTFRAG
+# define DONT_FRAG_VALUE 1
+#elif defined IP_DONTFRAGMENT
+  /* Winsock2 */
+# define IP_OPT_DONT_FRAG IP_DONTFRAGMENT
+# define DONT_FRAG_VALUE 1
+#endif
+
 struct packet 
 {
        int len;                /* Total packet length */
@@ -58,6 +77,7 @@ struct query {
        int fromlen;
 };
 
+void check_superuser(void (*usage_fn)(void));
 int open_dns(int, in_addr_t);
 void close_dns(int);
 
@@ -68,4 +88,13 @@ void read_password(char*, size_t);
 
 int check_topdomain(char *);
 
+#ifdef WINDOWS32
+int inet_aton(const char *cp, struct in_addr *inp);
+
+void err(int eval, const char *fmt, ...);
+void warn(const char *fmt, ...);
+void errx(int eval, const char *fmt, ...);
+void warnx(const char *fmt, ...);
+#endif
+
 #endif
index df06fd173a4aceb30fac96d9102ed1cc439b813a..4b8199bc70f98473066e63fd3ea6e1ba5e5ad907 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#ifdef DARWIN
-#include <arpa/nameser8_compat.h>
-#endif
 #include <time.h>
-#include <err.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 
+#ifdef WINDOWS32
+#include "windows.h"
+#else
+#include <arpa/nameser.h>
+#ifdef DARWIN
+#include <arpa/nameser8_compat.h>
+#endif
+#include <arpa/inet.h>
+#include <err.h>
+#endif
+
+
 #include "dns.h"
 #include "encoding.h"
 #include "read.h"
@@ -177,7 +183,7 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
        return len;
 }
 
-short
+unsigned short
 dns_get_id(char *packet, size_t packetlen)
 {
        HEADER *header;
index dc3e429c345e713d58702e7da43df3a582c9defd..b5c4cc57f92e1f5536627aeee8308aeaf8cc7c5f 100644 (file)
--- a/src/dns.h
+++ b/src/dns.h
@@ -26,7 +26,7 @@ typedef enum {
 
 int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
 int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain);
-short dns_get_id(char *packet, size_t packetlen);
+unsigned short dns_get_id(char *packet, size_t packetlen);
 int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
 
 #endif /* _DNS_H_ */
index d2269bc1b4a976ba56871be78ba196c97e1a6550..3727f08298c3f68994fe9ed7e1092dd49f9da724 100644 (file)
@@ -35,7 +35,7 @@ void fw_query_put(struct fw_query *fw_query)
                fwq_ix = 0;
 }
 
-void fw_query_get(short query_id, struct fw_query **fw_query)
+void fw_query_get(unsigned short query_id, struct fw_query **fw_query)
 {
        int i;
 
index c47da413acadb0a58cfb3ad5eaf874974e0a5812..7568a5f565d9835fddeb330c16c615ac850e02ec 100644 (file)
 #define __FW_QUERY_H__
 
 #include <sys/types.h>
+#ifdef WINDOWS32
+#include "windows.h"
+#include <winsock2.h>
+#else
 #include <sys/socket.h>
+#endif
 
 #define FW_QUERY_CACHE_SIZE 16
 
 struct fw_query {
        struct sockaddr addr;
        int addrlen;
-       short id;
+       unsigned short id;
 };
 
 void fw_query_init();
 void fw_query_put(struct fw_query *fw_query);
-void fw_query_get(short query_id, struct fw_query **fw_query);
+void fw_query_get(unsigned short query_id, struct fw_query **fw_query);
 
 #endif /*__FW_QUERY_H__*/
 
index 7b1a084307e034fcbd93bb4c3ed51224a3ff57ad..65e47bc8159e13ba0bdb13e4082b916344a594fa 100644 (file)
 #include <string.h>
 #include <signal.h>
 #include <unistd.h>
-#include <netdb.h>
-#include <netinet/in.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
-#include <sys/socket.h>
 #include <fcntl.h>
-#include <err.h>
-#include <grp.h>
-#include <pwd.h>
-#include <arpa/inet.h>
 #include <zlib.h>
+
+#ifdef WINDOWS32
+#include "windows.h"
+#include <winsock2.h>
+#else
 #include <arpa/nameser.h>
 #ifdef DARWIN
 #include <arpa/nameser8_compat.h>
 #endif
+#include <sys/socket.h>
+#include <err.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <grp.h>
+#include <pwd.h>
+#include <netdb.h>
+#endif
 
 #include "common.h"
 #include "encoding.h"
 #include "tun.h"
 #include "version.h"
 
+#ifdef WINDOWS32
+WORD req_version = MAKEWORD(2, 2);
+WSADATA wsa_data;
+#endif
+
 static void send_ping(int fd);
 static void send_chunk(int fd);
 static int build_hostname(char *buf, size_t buflen, 
@@ -64,9 +75,6 @@ static int downstream_fragment;
 static int down_ack_seqno;
 static int down_ack_fragment;
 
-static int max_downstream_frag_size;
-static int autodetect_frag_size;
-
 /* Current up/downstream IP packet */
 static struct packet outpkt;
 static struct packet inpkt;
@@ -132,7 +140,7 @@ build_hostname(char *buf, size_t buflen,
        size_t space;
        char *b;
 
-       space = MIN(0xFF, buflen) - strlen(topdomain) - 5;
+       space = MIN(0xFF, buflen) - strlen(topdomain) - 7;
        if (!encoder->places_dots())
                space -= (space / 57); /* space for dots */
 
@@ -424,7 +432,7 @@ send_fragsize_probe(int fd, int fragsize)
        fragsize &= 2047;
 
        buf[0] = 'r'; /* Probe downstream fragsize packet */
-       buf[1] = b32_5to8((userid << 1) | (fragsize & 1024));
+       buf[1] = b32_5to8((userid << 1) | ((fragsize >> 10) & 1));
        buf[2] = b32_5to8((fragsize >> 5) & 31);
        buf[3] = b32_5to8(fragsize & 31);
 
@@ -487,22 +495,17 @@ send_codec_switch(int fd, int userid, int bits)
        strncat(buf, topdomain, 512 - strlen(buf));
        send_query(fd, buf);
 }
-
+       
 static int
-handshake(int dns_fd)
+handshake_version(int dns_fd, int *seed)
 {
        struct timeval tv;
-       uint32_t payload;
-       char server[65];
-       char client[65];
-       char login[16];
        char in[4096];
        fd_set fds;
-       int read;
-       int mtu;
-       int seed;
+       uint32_t payload;
        int i;
        int r;
+       int read;
 
        for (i = 0; running && i < 5; i++) {
                tv.tv_sec = i + 1;
@@ -533,11 +536,11 @@ handshake(int dns_fd)
                                                ((in[7] & 0xff)));
 
                                if (strncmp("VACK", in, 4) == 0) {
-                                       seed = payload;
+                                       *seed = payload;
                                        userid = in[8];
 
-                                       printf("Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid);
-                                       goto perform_login;
+                                       fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid);
+                                       return 0;
                                } else if (strncmp("VNAK", in, 4) == 0) {
                                        warnx("You use protocol v 0x%08x, server uses v 0x%08x. Giving up", 
                                                        VERSION, payload);
@@ -550,12 +553,26 @@ handshake(int dns_fd)
                                warnx("did not receive proper login challenge");
                }
                
-               printf("Retrying version check...\n");
+               fprintf(stderr, "Retrying version check...\n");
        }
-       errx(1, "couldn't connect to server");
-       /* NOTREACHED */
-       
-perform_login:
+       warnx("couldn't connect to server");
+       return 1;
+}
+
+static int
+handshake_login(int dns_fd, int seed)
+{
+       struct timeval tv;
+       char in[4096];
+       char login[16];
+       char server[65];
+       char client[65];
+       int mtu;
+       fd_set fds;
+       int i;
+       int r;
+       int read;
+
        login_calculate(login, 16, password, seed);
        
        for (i=0; running && i<5 ;i++) {
@@ -580,7 +597,7 @@ perform_login:
                        if (read > 0) {
                                int netmask;
                                if (strncmp("LNAK", in, 4) == 0) {
-                                       printf("Bad password\n");
+                                       fprintf(stderr, "Bad password\n");
                                        return 1;
                                } else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d", 
                                        server, client, &mtu, &netmask) == 4) {
@@ -589,22 +606,32 @@ perform_login:
                                        client[64] = 0;
                                        if (tun_setip(client, netmask) == 0 && 
                                                tun_setmtu(mtu) == 0) {
-                                               goto perform_case_check;
+                                               return 0;
                                        } else {
                                                warnx("Received handshake with bad data");
                                        }
                                } else {
-                                       printf("Received bad handshake\n");
+                                       fprintf(stderr, "Received bad handshake\n");
                                }
                        }
                }
 
-               printf("Retrying login...\n");
+               fprintf(stderr, "Retrying login...\n");
        }
        warnx("couldn't login to server");
        return 1;
+}
+
+static void
+handshake_case_check(int dns_fd)
+{
+       struct timeval tv;
+       char in[4096];
+       fd_set fds;
+       int i;
+       int r;
+       int read;
 
-perform_case_check:
        case_preserved = 0;
        for (i=0; running && i<5 ;i++) {
                tv.tv_sec = i + 1;
@@ -623,8 +650,8 @@ perform_case_check:
                        if (read > 0) {
                                if (in[0] == 'z' || in[0] == 'Z') {
                                        if (read < (27 * 2)) {
-                                               printf("Received short case check reply. Will use base32 encoder\n");
-                                               goto switch_codec;
+                                               fprintf(stderr, "Received short case check reply. Will use base32 encoder\n");
+                                               return;
                                        } else {
                                                int k;
 
@@ -636,27 +663,35 @@ perform_case_check:
                                                                case_preserved = 0;
                                                        }
                                                }
-                                               goto switch_codec;
+                                               return;
                                        }
                                } else {
-                                       printf("Received bad case check reply\n");
+                                       fprintf(stderr, "Received bad case check reply\n");
                                }
                        } else {
-                               printf("Got error on case check, will use base32\n");
-                               goto switch_codec;
+                               fprintf(stderr, "Got error on case check, will use base32\n");
+                               return;
                        }
                }
 
-               printf("Retrying case check...\n");
+               fprintf(stderr, "Retrying case check...\n");
        }
 
-       printf("No reply on case check, continuing\n");
-switch_codec:
-       if (!case_preserved)
-               goto autodetect_max_fragsize;
+       fprintf(stderr, "No reply on case check, continuing\n");
+}
+
+static void
+handshake_switch_codec(int dns_fd)
+{
+       struct timeval tv;
+       char in[4096];
+       fd_set fds;
+       int i;
+       int r;
+       int read;
 
        dataenc = get_base64_encoder();
-       printf("Switching to %s codec\n", dataenc->name);
+       fprintf(stderr, "Switching to %s codec\n", dataenc->name);
        /* Send to server that this user will use base64 from now on */
        for (i=0; running && i<5 ;i++) {
                int bits;
@@ -677,84 +712,120 @@ switch_codec:
                        
                        if (read > 0) {
                                if (strncmp("BADLEN", in, 6) == 0) {
-                                       printf("Server got bad message length. ");
+                                       fprintf(stderr, "Server got bad message length. ");
                                        goto codec_revert;
                                } else if (strncmp("BADIP", in, 5) == 0) {
-                                       printf("Server rejected sender IP address. ");
+                                       fprintf(stderr, "Server rejected sender IP address. ");
                                        goto codec_revert;
                                } else if (strncmp("BADCODEC", in, 8) == 0) {
-                                       printf("Server rejected the selected codec. ");
+                                       fprintf(stderr, "Server rejected the selected codec. ");
                                        goto codec_revert;
                                }
                                in[read] = 0; /* zero terminate */
-                               printf("Server switched to codec %s\n", in);
-                               goto autodetect_max_fragsize;
+                               fprintf(stderr, "Server switched to codec %s\n", in);
+                               return;
                        }
                }
-               printf("Retrying codec switch...\n");
+               fprintf(stderr, "Retrying codec switch...\n");
        }
-       printf("No reply from server on codec switch. ");
+       fprintf(stderr, "No reply from server on codec switch. ");
+
 codec_revert: 
-       printf("Falling back to base32\n");
+       fprintf(stderr, "Falling back to base32\n");
        dataenc = get_base32_encoder();
-autodetect_max_fragsize:
-       if (autodetect_frag_size) {
-               int proposed_fragsize = 768;
-               int range = 768;
-               max_downstream_frag_size = 0;
-               printf("Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); 
-               while (running && range > 0 && (range >= 8 || !max_downstream_frag_size)) {
-                       for (i=0; running && i<3 ;i++) {
-                               tv.tv_sec = 1;
-                               tv.tv_usec = 0;
-                               send_fragsize_probe(dns_fd, proposed_fragsize);
-
-                               FD_ZERO(&fds);
-                               FD_SET(dns_fd, &fds);
-
-                               r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
-
-                               if(r > 0) {
-                                       read = read_dns(dns_fd, in, sizeof(in));
-                                       
-                                       if (read > 0) {
-                                               /* We got a reply */
-                                               int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
-                                               if (acked_fragsize == proposed_fragsize) {
-                                                       printf("%d ok.. ", acked_fragsize);
-                                                       fflush(stdout);
-                                                       max_downstream_frag_size = acked_fragsize;
-                                                       range >>= 1;
-                                                       proposed_fragsize += range;
-                                                       continue;
+}
+
+static int
+handshake_autoprobe_fragsize(int dns_fd)
+{
+       struct timeval tv;
+       char in[4096];
+       fd_set fds;
+       int i;
+       int r;
+       int read;
+       int proposed_fragsize = 768;
+       int range = 768;
+       int max_fragsize = 0;
+
+       max_fragsize = 0;
+       fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); 
+       while (running && range > 0 && (range >= 8 || !max_fragsize)) {
+               for (i=0; running && i<3 ;i++) {
+                       tv.tv_sec = 1;
+                       tv.tv_usec = 0;
+                       send_fragsize_probe(dns_fd, proposed_fragsize);
+
+                       FD_ZERO(&fds);
+                       FD_SET(dns_fd, &fds);
+
+                       r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
+
+                       if(r > 0) {
+                               read = read_dns(dns_fd, in, sizeof(in));
+                               
+                               if (read > 0) {
+                                       /* We got a reply */
+                                       int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
+                                       if (acked_fragsize == proposed_fragsize) {
+                                               if (read == proposed_fragsize) {
+                                                       fprintf(stderr, "%d ok.. ", acked_fragsize);
+                                                       fflush(stderr);
+                                                       max_fragsize = acked_fragsize;
                                                }
                                        }
+                                       if (strncmp("BADIP", in, 5) == 0) {
+                                               fprintf(stderr, "got BADIP.. ");
+                                               fflush(stderr);
+                                       }
+                                       break;
                                }
                        }
-                       printf("%d not ok.. ", proposed_fragsize);
-                       fflush(stdout);
-                       range >>= 1;
-                       proposed_fragsize -= range;
+                       fprintf(stderr, ".");
+                       fflush(stderr);
                }
-               if (!running) {
-                       printf("\n");
-                       warnx("stopped while autodetecting fragment size (Try probing manually with -m)");
-                       return 1;
-               }
-               if (range == 0) {
-                       /* Tried all the way down to 2 and found no good size */
-                       printf("\n");
-                       warnx("found no accepted fragment size. (Try probing manually with -m)");
-                       return 1;
+               range >>= 1;
+               if (max_fragsize == proposed_fragsize) {
+                       /* Try bigger */
+                       proposed_fragsize += range;
+               } else {
+                       /* Try smaller */
+                       fprintf(stderr, "%d not ok.. ", proposed_fragsize);
+                       fflush(stderr);
+                       proposed_fragsize -= range;
                }
-               printf("will use %d\n", max_downstream_frag_size);
        }
-       printf("Setting downstream fragment size to max %d...\n", max_downstream_frag_size);
+       if (!running) {
+               fprintf(stderr, "\n");
+               warnx("stopped while autodetecting fragment size (Try probing manually with -m)");
+               return 0;
+       }
+       if (range == 0) {
+               /* Tried all the way down to 2 and found no good size */
+               fprintf(stderr, "\n");
+               warnx("found no accepted fragment size. (Try probing manually with -m)");
+               return 0;
+       }
+       fprintf(stderr, "will use %d\n", max_fragsize);
+       return max_fragsize;
+}
+
+static void
+handshake_set_fragsize(int dns_fd, int fragsize)
+{
+       struct timeval tv;
+       char in[4096];
+       fd_set fds;
+       int i;
+       int r;
+       int read;
+
+       fprintf(stderr, "Setting downstream fragment size to max %d...\n", fragsize);
        for (i=0; running && i<5 ;i++) {
                tv.tv_sec = i + 1;
                tv.tv_usec = 0;
 
-               send_set_downstream_fragsize(dns_fd, max_downstream_frag_size);
+               send_set_downstream_fragsize(dns_fd, fragsize);
                
                FD_ZERO(&fds);
                FD_SET(dns_fd, &fds);
@@ -768,21 +839,53 @@ autodetect_max_fragsize:
                                int accepted_fragsize;
 
                                if (strncmp("BADFRAG", in, 7) == 0) {
-                                       printf("Server rejected fragsize. Keeping default.");
-                                       goto done;
+                                       fprintf(stderr, "Server rejected fragsize. Keeping default.");
+                                       return;
                                } else if (strncmp("BADIP", in, 5) == 0) {
-                                       printf("Server rejected sender IP address.\n");
-                                       goto done;
+                                       fprintf(stderr, "Server rejected sender IP address.\n");
+                                       return;
                                }
 
                                accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
-                               goto done;
+                               return;
                        }
                }
-               printf("Retrying set fragsize...\n");
+               fprintf(stderr, "Retrying set fragsize...\n");
        }
-       printf("No reply from server when setting fragsize. Keeping default.\n");
-done:
+       fprintf(stderr, "No reply from server when setting fragsize. Keeping default.\n");
+}
+
+static int
+handshake(int dns_fd, int autodetect_frag_size, int fragsize)
+{
+       int seed;
+       int r;
+
+       r = handshake_version(dns_fd, &seed);
+       if (r) {
+               return r;
+       }
+
+       r = handshake_login(dns_fd, seed);
+       if (r) {
+               return r;
+       }
+
+       handshake_case_check(dns_fd);
+
+       if (case_preserved) {
+               handshake_switch_codec(dns_fd);
+       }
+
+       if (autodetect_frag_size) {
+               fragsize = handshake_autoprobe_fragsize(dns_fd);
+               if (!fragsize) {
+                       return 1;
+               }
+       }
+
+       handshake_set_fragsize(dns_fd, fragsize);
+
        return 0;
 }
 
@@ -790,8 +893,9 @@ static char *
 get_resolvconf_addr()
 {
        static char addr[16];
-       char buf[80];
        char *rv;
+#ifndef WINDOWS32
+       char buf[80];
        FILE *fp;
        
        rv = NULL;
@@ -809,7 +913,29 @@ get_resolvconf_addr()
        }
        
        fclose(fp);
+#else /* !WINDOWS32 */
+       FIXED_INFO  *fixed_info;
+       ULONG       buflen;
+       DWORD       ret;
 
+       rv = NULL;
+       fixed_info = malloc(sizeof(FIXED_INFO));
+       buflen = sizeof(FIXED_INFO);
+
+       if (GetNetworkParams(fixed_info, &buflen) == ERROR_BUFFER_OVERFLOW) {
+               /* official ugly api workaround */
+               free(fixed_info);
+               fixed_info = malloc(buflen);
+       }
+
+       ret = GetNetworkParams(fixed_info, &buflen);
+       if (ret == NO_ERROR) {
+               strncpy(addr, fixed_info->DnsServerList.IpAddress.String, sizeof(addr));
+               addr[15] = 0;
+               rv = addr;
+       }
+       free(fixed_info);
+#endif
        return rv;
 }
 
@@ -831,7 +957,7 @@ static void
 usage() {
        extern char *__progname;
 
-       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
+       fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
                        "[-P password] [-m maxfragsize] [nameserver] topdomain\n", __progname);
        exit(2);
 }
@@ -840,19 +966,19 @@ static void
 help() {
        extern char *__progname;
 
-       printf("iodine IP over DNS tunneling client\n");
-       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
+       fprintf(stderr, "iodine IP over DNS tunneling client\n");
+       fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
                        "[-P password] [-m maxfragsize] [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");
-       printf("  -u name to drop privileges and run as user 'name'\n");
-       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("  -m maxfragsize, to limit size of downstream packets\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");
+       fprintf(stderr, "  -v to print version info and exit\n");
+       fprintf(stderr, "  -h to print this help and exit\n");
+       fprintf(stderr, "  -f to keep running in foreground\n");
+       fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n");
+       fprintf(stderr, "  -t dir to chroot to directory dir\n");
+       fprintf(stderr, "  -d device to set tunnel device name\n");
+       fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n");
+       fprintf(stderr, "  -m maxfragsize, to limit size of downstream packets\n");
+       fprintf(stderr, "nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
+       fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
 
        exit(0);
 }
@@ -860,7 +986,7 @@ help() {
 static void
 version() {
        printf("iodine IP over DNS tunneling client\n");
-       printf("version: 0.5.0 from 2009-01-23\n");
+       printf("version: 0.5.1 from 2009-03-21\n");
 
        exit(0);
 }
@@ -869,7 +995,9 @@ int
 main(int argc, char **argv)
 {
        char *nameserv_addr;
+#ifndef WINDOWS32
        struct passwd *pw;
+#endif
        char *username;
        int foreground;
        char *newroot;
@@ -877,6 +1005,8 @@ main(int argc, char **argv)
        int choice;
        int tun_fd;
        int dns_fd;
+       int max_downstream_frag_size;
+       int autodetect_frag_size;
 
        memset(password, 0, 33);
        username = NULL;
@@ -893,6 +1023,10 @@ main(int argc, char **argv)
 
        b32 = get_base32_encoder();
        dataenc = get_base32_encoder();
+
+#ifdef WINDOWS32
+       WSAStartup(req_version, &wsa_data);
+#endif
        
 #if !defined(BSD) && !defined(__GLIBC__)
        __progname = strrchr(argv[0], '/');
@@ -941,11 +1075,7 @@ main(int argc, char **argv)
                }
        }
        
-       if (geteuid() != 0) {
-               warnx("Run as root and you'll be happy.\n");
-               usage();
-               /* NOTREACHED */
-       }
+       check_superuser(usage);
 
        argc -= optind;
        argv += optind;
@@ -985,11 +1115,13 @@ main(int argc, char **argv)
        }
 
        if (username != NULL) {
+#ifndef WINDOWS32
                if ((pw = getpwnam(username)) == NULL) {
                        warnx("User %s does not exist!\n", username);
                        usage();
                        /* NOTREACHED */
                }
+#endif
        }
        
        if (strlen(password) == 0) 
@@ -1003,10 +1135,10 @@ main(int argc, char **argv)
        signal(SIGINT, sighandler);
        signal(SIGTERM, sighandler);
 
-       if(handshake(dns_fd))
+       if(handshake(dns_fd, autodetect_frag_size, max_downstream_frag_size))
                goto cleanup2;
        
-       printf("Sending queries for %s to %s\n", topdomain, nameserv_addr);
+       fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
 
        if (foreground == 0) 
                do_detach();
@@ -1015,6 +1147,7 @@ main(int argc, char **argv)
                do_chroot(newroot);
        
        if (username != NULL) {
+#ifndef WINDOWS32
                gid_t gids[1];
                gids[0] = pw->pw_gid;
                if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
@@ -1022,6 +1155,7 @@ main(int argc, char **argv)
                        usage();
                        /* NOTREACHED */
                }
+#endif
        }
        
        downstream_seqno = 0;
index 25bddc65f3ca9824bcc589c55ae5c01c16b6ff0e..bf35c701d67060c50b915a7b16660ae50aa4d05a 100644 (file)
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
+#include <fcntl.h>
+#include <time.h>
+#include <zlib.h>
+
+#ifdef WINDOWS32
+#include "windows.h"
+#include <winsock2.h>
+#else
+#include <arpa/nameser.h>
+#ifdef DARWIN
+#include <arpa/nameser8_compat.h>
+#endif
 #define _XPG4_2
 #include <sys/socket.h>
-#include <sys/uio.h>
-#include <fcntl.h>
 #include <err.h>
-#include <grp.h>
-#include <time.h>
-#include <pwd.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
-#include <zlib.h>
-#include <arpa/nameser.h>
-#ifdef DARWIN
-#include <arpa/nameser8_compat.h>
+#include <grp.h>
+#include <sys/uio.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <syslog.h>
 #endif
 
 #include "common.h"
 #include "fw_query.h"
 #include "version.h"
 
+#ifdef WINDOWS32
+WORD req_version = MAKEWORD(2, 2);
+WSADATA wsa_data;
+#endif
+
 static int running = 1;
 static char *topdomain;
 static char password[33];
@@ -81,6 +94,23 @@ sigint(int sig)
        running = 0;
 }
 
+#ifdef WINDOWS32
+#define        LOG_EMERG       0
+#define        LOG_ALERT       1
+#define        LOG_CRIT        2
+#define        LOG_ERR         3
+#define        LOG_WARNING     4
+#define        LOG_NOTICE      5
+#define        LOG_INFO        6
+#define        LOG_DEBUG       7
+static void
+syslog(int a, const char *str, ...)
+{
+       /* TODO: implement (add to event log), move to common.c */
+       ;
+}
+#endif
+
 static int
 check_user_and_ip(int userid, struct query *q)
 {
@@ -208,7 +238,7 @@ send_chunk(int dns_fd, int userid) {
                ((users[userid].outpacket.fragment & 15) << 1) | (last & 1);
 
        if (debug >= 1) {
-               printf("OUT  pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n",
+               fprintf(stderr, "OUT  pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n",
                        users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15, 
                        last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid);
        }
@@ -306,13 +336,19 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                                memcpy(&(users[userid].q), q, sizeof(struct query));
                                users[userid].encoder = get_base32_encoder();
                                send_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q);
+                               syslog(LOG_INFO, "accepted version for user #%d from %s",
+                                       userid, inet_ntoa(tempin->sin_addr));
                                users[userid].q.id = 0;
                        } else {
                                /* No space for another user */
                                send_version_response(dns_fd, VERSION_FULL, created_users, 0, q);
+                               syslog(LOG_INFO, "dropped user from %s, server full", 
+                                       inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
                        }
                } else {
                        send_version_response(dns_fd, VERSION_NACK, VERSION, 0, q);
+                       syslog(LOG_INFO, "dropped user from %s, sent bad version %08X", 
+                               inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr), version);
                }
                return;
        } else if(in[0] == 'L' || in[0] == 'l') {
@@ -322,6 +358,8 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                if (check_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5);
+                       syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s",
+                               userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
                        return;
                } else {
                        users[userid].last_pkt = time(NULL);
@@ -340,11 +378,14 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                                write_dns(dns_fd, q, out, read);
                                q->id = 0;
+                               syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]);
 
                                free(tmp[1]);
                                free(tmp[0]);
                        } else {
                                write_dns(dns_fd, q, "LNAK", 4);
+                               syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password",
+                                       userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
                        }
                }
                return;
@@ -441,7 +482,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                }
                                
                if (debug >= 1) {
-                       printf("PING pkt from user %d\n", userid);
+                       fprintf(stderr, "PING pkt from user %d\n", userid);
                }
 
                if (users[userid].q.id != 0) {
@@ -491,7 +532,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                                up_frag <= users[userid].inpacket.fragment) {
                                /* Got repeated old packet, skip it */
                                if (debug >= 1) {
-                                       printf("IN   pkt seq# %d, frag %d, dropped duplicate\n",
+                                       fprintf(stderr, "IN   pkt seq# %d, frag %d, dropped duplicate\n",
                                                up_seq, up_frag);
                                }
                                /* Update seqno and maybe send immediate response packet */
@@ -516,7 +557,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                        users[userid].inpacket.offset += read;
 
                        if (debug >= 1) {
-                               printf("IN   pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n",
+                               fprintf(stderr, "IN   pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n",
                                        up_seq, up_frag, lastfrag, read, users[userid].inpacket.len, userid);
                        }
 
@@ -542,7 +583,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                                                }
                                        }
                                } else {
-                                       printf("Discarded data, uncompress() result: %d\n", ret);
+                                       fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
                                }
                                users[userid].inpacket.len = users[userid].inpacket.offset = 0;
                        }
@@ -567,7 +608,7 @@ handle_ns_request(int dns_fd, struct query *q)
        if (debug >= 2) {
                struct sockaddr_in *tempin;
                tempin = (struct sockaddr_in *) &(q->from);
-               printf("TX: client %s, type %d, name %s, %d bytes NS reply\n", 
+               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n", 
                        inet_ntoa(tempin->sin_addr), q->type, q->name, len);
        }
        if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
@@ -598,7 +639,7 @@ forward_query(int bind_fd, struct query *q)
        myaddr->sin_port = htons(bind_port);
        
        if (debug >= 2) {
-               printf("TX: NS reply \n");
+               fprintf(stderr, "TX: NS reply \n");
        }
 
        if (sendto(bind_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
@@ -613,7 +654,7 @@ tunnel_bind(int bind_fd, int dns_fd)
        struct sockaddr_in from;
        socklen_t fromlen;
        struct fw_query *query;
-       short id;
+       unsigned short id;
        int r;
 
        fromlen = sizeof(struct sockaddr);
@@ -626,20 +667,20 @@ tunnel_bind(int bind_fd, int dns_fd)
        id = dns_get_id(packet, r);
        
        if (debug >= 2) {
-               printf("RX: Got response on query %u from DNS\n", (id & 0xFFFF));
+               fprintf(stderr, "RX: Got response on query %u from DNS\n", (id & 0xFFFF));
        }
 
        /* Get sockaddr from id */
        fw_query_get(id, &query);
        if (!query && debug >= 2) {
-               printf("Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
+               fprintf(stderr, "Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
                return 0;
        }
 
        if (debug >= 2) {
                struct sockaddr_in *in;
                in = (struct sockaddr_in *) &(query->addr);
-               printf("TX: client %s id %u, %d bytes\n",
+               fprintf(stderr, "TX: client %s id %u, %d bytes\n",
                        inet_ntoa(in->sin_addr), (id & 0xffff), r);
        }
        
@@ -666,7 +707,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
        if (debug >= 2) {
                struct sockaddr_in *tempin;
                tempin = (struct sockaddr_in *) &(q.from);
-               printf("RX: client %s, type %d, name %s\n", 
+               fprintf(stderr, "RX: client %s, type %d, name %s\n", 
                        inet_ntoa(tempin->sin_addr), q.type, q.name);
        }
        
@@ -774,11 +815,12 @@ read_dns(int fd, struct query *q)
        struct sockaddr_in from;
        socklen_t addrlen;
        char packet[64*1024];
+       int r;
+#ifndef WINDOWS32
        char address[96];
        struct msghdr msg;
        struct iovec iov;
        struct cmsghdr *cmsg;
-       int r;
 
        addrlen = sizeof(struct sockaddr);
        iov.iov_base = packet;
@@ -793,12 +835,17 @@ read_dns(int fd, struct query *q)
        msg.msg_flags = 0;
        
        r = recvmsg(fd, &msg, 0);
+#else
+       addrlen = sizeof(struct sockaddr);
+       r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
+#endif /* !WINDOWS32 */
 
        if (r > 0) {
                dns_decode(NULL, 0, q, QR_QUERY, packet, r);
                memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
                q->fromlen = addrlen;
                
+#ifndef WINDOWS32
                for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 
                        cmsg = CMSG_NXTHDR(&msg, cmsg)) { 
                        
@@ -809,6 +856,7 @@ read_dns(int fd, struct query *q)
                                break;
                        } 
                }
+#endif
 
                return strlen(q->name);
        } else if (r < 0) { 
@@ -830,7 +878,7 @@ write_dns(int fd, struct query *q, char *data, int datalen)
        if (debug >= 2) {
                struct sockaddr_in *tempin;
                tempin = (struct sockaddr_in *) &(q->from);
-               printf("TX: client %s, type %d, name %s, %d bytes data\n", 
+               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n", 
                        inet_ntoa(tempin->sin_addr), q->type, q->name, datalen);
        }
 
@@ -841,7 +889,7 @@ static void
 usage() {
        extern char *__progname;
 
-       printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
+       fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
                "[-t chrootdir] [-d device] [-m mtu] "
                "[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]"
                " tunnel_ip[/netmask] topdomain\n", __progname);
@@ -852,46 +900,49 @@ static void
 help() {
        extern char *__progname;
 
-       printf("iodine IP over DNS tunneling server\n");
-       printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
+       fprintf(stderr, "iodine IP over DNS tunneling server\n");
+       fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
                "[-t chrootdir] [-d device] [-m mtu] "
                "[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]"
                " tunnel_ip[/netmask] topdomain\n", __progname);
-       printf("  -v to print version info and exit\n");
-       printf("  -h to print this help and exit\n");
-       printf("  -c to disable check of client IP/port on each request\n");
-       printf("  -s to skip creating and configuring the tun device, "
+       fprintf(stderr, "  -v to print version info and exit\n");
+       fprintf(stderr, "  -h to print this help and exit\n");
+       fprintf(stderr, "  -c to disable check of client IP/port on each request\n");
+       fprintf(stderr, "  -s to skip creating and configuring the tun device, "
                "which then has to be created manually\n");
-       printf("  -f to keep running in foreground\n");
-       printf("  -D to increase debug level\n");
-       printf("  -u name to drop privileges and run as user 'name'\n");
-       printf("  -t dir to chroot to directory dir\n");
-       printf("  -d device to set tunnel device name\n");
-       printf("  -m mtu to set tunnel device mtu\n");
-       printf("  -l ip address to listen on for incoming dns traffic "
+       fprintf(stderr, "  -f to keep running in foreground\n");
+       fprintf(stderr, "  -D to increase debug level\n");
+       fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n");
+       fprintf(stderr, "  -t dir to chroot to directory dir\n");
+       fprintf(stderr, "  -d device to set tunnel device name\n");
+       fprintf(stderr, "  -m mtu to set tunnel device mtu\n");
+       fprintf(stderr, "  -l ip address to listen on for incoming dns traffic "
                "(default 0.0.0.0)\n");
-       printf("  -p port to listen on for incoming dns traffic (default 53)\n");
-       printf("  -n ip to respond with to NS queries\n");
-       printf("  -b port to forward normal DNS queries to (on localhost)\n");
-       printf("  -P password used for authentication (max 32 chars will be used)\n");
-       printf("tunnel_ip is the IP number of the local tunnel interface.\n");
-       printf("   /netmask sets the size of the tunnel network.\n");
-       printf("topdomain is the FQDN that is delegated to this server.\n");
+       fprintf(stderr, "  -p port to listen on for incoming dns traffic (default 53)\n");
+       fprintf(stderr, "  -n ip to respond with to NS queries\n");
+       fprintf(stderr, "  -b port to forward normal DNS queries to (on localhost)\n");
+       fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n");
+       fprintf(stderr, "tunnel_ip is the IP number of the local tunnel interface.\n");
+       fprintf(stderr, "   /netmask sets the size of the tunnel network.\n");
+       fprintf(stderr, "topdomain is the FQDN that is delegated to this server.\n");
        exit(0);
 }
 
 static void
 version() {
        printf("iodine IP over DNS tunneling server\n");
-       printf("version: 0.5.0 from 2009-01-23\n");
+       printf("version: 0.5.1 from 2009-03-21\n");
        exit(0);
 }
 
 int
 main(int argc, char **argv)
 {
+       extern char *__progname;
        in_addr_t listen_ip;
+#ifndef WINDOWS32
        struct passwd *pw;
+#endif
        int foreground;
        char *username;
        char *newroot;
@@ -916,7 +967,7 @@ main(int argc, char **argv)
        foreground = 0;
        bind_enable = 0;
        bind_fd = 0;
-       mtu = 1024;
+       mtu = 1200;
        listen_ip = INADDR_ANY;
        port = 53;
        ns_ip = INADDR_ANY;
@@ -926,6 +977,10 @@ main(int argc, char **argv)
        netmask = 27;
 
        b32 = get_base32_encoder();
+       
+#ifdef WINDOWS32
+       WSAStartup(req_version, &wsa_data);
+#endif
 
 #if !defined(BSD) && !defined(__GLIBC__)
        __progname = strrchr(argv[0], '/');
@@ -1000,10 +1055,7 @@ main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
-       if (geteuid() != 0) {
-               warnx("Run as root and you'll be happy.\n");
-               usage();
-       }
+       check_superuser(usage);
 
        if (argc != 2) 
                usage();
@@ -1034,10 +1086,12 @@ main(int argc, char **argv)
        }
 
        if (username != NULL) {
+#ifndef WINDOWS32
                if ((pw = getpwnam(username)) == NULL) {
                        warnx("User %s does not exist!\n", username);
                        usage();
                }
+#endif
        }
 
        if (mtu <= 0) {
@@ -1056,18 +1110,18 @@ main(int argc, char **argv)
                        usage();
                        /* NOTREACHED */
                }
-               printf("Requests for domains outside of %s will be forwarded to port %d\n",
+               fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n",
                        topdomain, bind_port);
        }
        
        if (port != 53) {
-               printf("ALERT! Other dns servers expect you to run on port 53.\n");
-               printf("You must manually forward port 53 to port %d for things to work.\n", port);
+               fprintf(stderr, "ALERT! Other dns servers expect you to run on port 53.\n");
+               fprintf(stderr, "You must manually forward port 53 to port %d for things to work.\n", port);
        }
 
        if (debug) {
-               printf("Debug level %d enabled, will stay in foreground.\n", debug);
-               printf("Add more -D switches to set higher debug level.\n");
+               fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug);
+               fprintf(stderr, "Add more -D switches to set higher debug level.\n");
                foreground = 1;
        }
 
@@ -1104,10 +1158,10 @@ main(int argc, char **argv)
        created_users = init_users(my_ip, netmask);
        
        if (created_users < USERS) {
-               printf("Limiting to %d simultaneous users because of netmask /%d\n",
+               fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n",
                        created_users, netmask);
        }
-       printf("Listening to dns for domain %s\n", topdomain);
+       fprintf(stderr, "Listening to dns for domain %s\n", topdomain);
 
        if (foreground == 0) 
                do_detach();
@@ -1117,16 +1171,24 @@ main(int argc, char **argv)
 
        signal(SIGINT, sigint);
        if (username != NULL) {
+#ifndef WINDOWS32
                gid_t gids[1];
                gids[0] = pw->pw_gid;
                if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
                        warnx("Could not switch to user %s!\n", username);
                        usage();
                }
+#endif
        }
+
+#ifndef WINDOWS32
+       openlog(__progname, LOG_NOWAIT, LOG_DAEMON);
+#endif
+       syslog(LOG_INFO, "started, listening on port %d", port);
        
        tunnel(tun_fd, dnsd_fd, bind_fd);
 
+       syslog(LOG_INFO, "stopping");
 cleanup3:
        close_dns(bind_fd);
 cleanup2:
index 3aee250316db5c5d29a05ab97f97ee2bea2a430a..cce0f317d274575066e8383e9335c953347f29bc 100644 (file)
  */
 
 #include <string.h>
-#include <arpa/inet.h>
 #include <sys/types.h>
 
+#ifdef WINDOWS32
+#include "windows.h"
+#else
+#include <arpa/inet.h>
+#endif
+
 #include "md5.h"
 
 /* 
index 2e28ee886ee627b86aa7c596fc727cd259260ca7..fc6da1cbce2201a1b88955bad3895011e3ef58d1 100644 (file)
@@ -1,9 +1,9 @@
 #!/bin/sh
 
-case $1 in
+case $2 in
 link)
 
-       case `uname` in
+       case $1 in
                SunOS | solaris)
                        echo '-lsocket -lnsl';
                ;;
@@ -13,10 +13,13 @@ link)
                Haiku)
                        echo '-lnetwork';
                ;;
+               windows32)
+                       echo '-lws2_32 -liphlpapi';
+               ;;
        esac
        ;;
 cflags)
-       case `uname` in
+       case $1 in
                BeOS)
                        echo '-Dsocklen_t=int';
                ;;
index ba2be65f114255e7ea2c6a7a3603cc9bdd5f96f8..57b369d915a10ad3394233f8a1866b576e96f31b 100644 (file)
--- a/src/tun.c
+++ b/src/tun.c
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+
+#ifdef WINDOWS32
+#include <winsock2.h>
+#include <winioctl.h>
+#include "windows.h"
+
+HANDLE dev_handle;
+struct tun_data data;
+
+#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
+#define TAP_IOCTL_CONFIG_TUN       TAP_CONTROL_CODE(10, METHOD_BUFFERED)
+#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
+
+#define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+#define TAP_DEVICE_SPACE "\\\\.\\Global\\"
+#define TAP_VERSION_ID_0801 "tap0801"
+#define TAP_VERSION_ID_0901 "tap0901"
+#define KEY_COMPONENT_ID "ComponentId"
+#define NET_CFG_INST_ID "NetCfgInstanceId"
+#else
 #include <err.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 
-#include "tun.h"
-
 #define TUN_MAX_TRY 50
+#endif
+
+#include "tun.h"
+#include "common.h"
 
 char if_name[50];
 
+#ifndef WINDOWS32
 #ifdef LINUX
 
 #include <sys/ioctl.h>
@@ -63,7 +86,7 @@ open_tun(const char *tun_device)
                if_name[sizeof(if_name)-1] = '\0';
 
                if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
-                       printf("Opened %s\n", ifreq.ifr_name);
+                       fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
                        return tun_fd;
                }
 
@@ -76,7 +99,7 @@ open_tun(const char *tun_device)
                        snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
 
                        if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
-                               printf("Opened %s\n", ifreq.ifr_name);
+                               fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
                                snprintf(if_name, sizeof(if_name), "dns%d", i);
                                return tun_fd;
                        }
@@ -111,14 +134,14 @@ open_tun(const char *tun_device)
                        return -1;
                }
 
-               printf("Opened %s\n", tun_name);
+               fprintf(stderr, "Opened %s\n", tun_name);
                return tun_fd;
        } else {
                for (i = 0; i < TUN_MAX_TRY; i++) {
                        snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
 
                        if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
-                               printf("Opened %s\n", tun_name);
+                               fprintf(stderr, "Opened %s\n", tun_name);
                                snprintf(if_name, sizeof(if_name), "tun%d", i);
                                return tun_fd;
                        }
@@ -134,6 +157,148 @@ open_tun(const char *tun_device)
 }
 
 #endif /* !LINUX */
+#else /* WINDOWS32 */
+static void
+get_device(char *device, int device_len)
+{
+       LONG status;
+       HKEY adapter_key;
+       int index;
+
+       index = 0;
+       status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
+
+       if (status != ERROR_SUCCESS) {
+               warnx("Error opening registry key " TAP_ADAPTER_KEY );
+               return;
+       }
+       
+       while (TRUE) {
+               char name[256];
+               char unit[256];
+               char component[256];
+
+               char cid_string[256] = KEY_COMPONENT_ID;
+               HKEY device_key;
+               DWORD datatype;
+               DWORD len;
+
+               /* Iterate through all adapter of this kind */
+               len = sizeof(name);
+               status = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);
+               if (status == ERROR_NO_MORE_ITEMS) {
+                       break;
+               } else if (status != ERROR_SUCCESS) {
+                       warnx("Error enumerating subkeys of registry key " TAP_ADAPTER_KEY );
+                       break;
+               }
+
+               snprintf(unit, sizeof(unit), TAP_ADAPTER_KEY "\\%s", name);
+               status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);
+               if (status != ERROR_SUCCESS) {
+                       warnx("Error opening registry key %s", unit);
+                       goto next;
+               }
+
+               /* Check component id */
+               len = sizeof(component);
+               status = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);
+               if (status != ERROR_SUCCESS || datatype != REG_SZ) {
+                       goto next;
+               }
+               if (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||
+                       strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) {
+                       /* We found a TAP32 device, get its NetCfgInstanceId */
+                       char iid_string[256] = NET_CFG_INST_ID;
+                       
+                       status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);
+                       if (status != ERROR_SUCCESS || datatype != REG_SZ) {
+                               warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string);
+                       } else {
+                               /* Done getting name of TAP device */
+                               RegCloseKey(device_key);
+                               return;
+                       }
+               }
+next:
+               RegCloseKey(device_key);
+               index++;
+       }
+       RegCloseKey(adapter_key);
+}
+
+DWORD WINAPI tun_reader(LPVOID arg)
+{
+       struct tun_data *tun = arg;
+       char buf[64*1024];
+       int len;
+       int res;
+       OVERLAPPED olpd;
+       int sock;
+
+       sock = open_dns(0, INADDR_ANY);
+
+       olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+       while(TRUE) {
+               olpd.Offset = 0;
+               olpd.OffsetHigh = 0;
+               res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
+               if (!res) {
+                       WaitForSingleObject(olpd.hEvent, INFINITE);
+                       res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
+                       res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr), 
+                               sizeof(struct sockaddr_in));
+               }
+       }
+
+       return 0;
+}
+
+int 
+open_tun(const char *tun_device) 
+{
+       char adapter[256];
+       char tapfile[512];
+       int tunfd;
+       in_addr_t local;
+
+       memset(adapter, 0, sizeof(adapter));
+       get_device(adapter, sizeof(adapter));
+
+       if (strlen(adapter) == 0) {
+               warnx("No TAP adapters found. See README-win32.txt for help.\n");
+               return -1;
+       }
+       
+       snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
+       fprintf(stderr, "Opening device %s\n", tapfile);
+       dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
+       if (dev_handle == INVALID_HANDLE_VALUE) {
+               return -1;
+       }
+
+       /* TODO get name of interface */
+       strncpy(if_name, "dns", MIN(4, sizeof(if_name)));
+
+       /* Use a UDP connection to forward packets from tun,
+        * so we can still use select() in main code.
+        * A thread does blocking reads on tun device and 
+        * sends data as udp to this socket */
+       
+       local = htonl(0x7f000001); /* 127.0.0.1 */
+       tunfd = open_dns(55353, local);
+
+       data.tun = dev_handle;
+       memset(&(data.addr), 0, sizeof(data.addr));
+       data.addr.sin_family = AF_INET;
+       data.addr.sin_port = htons(55353);
+       data.addr.sin_addr.s_addr = local;
+       CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
+       
+       return tunfd;
+}
+#endif 
 
 void 
 close_tun(int tun_fd) 
@@ -145,7 +310,7 @@ close_tun(int tun_fd)
 int 
 write_tun(int tun_fd, char *data, size_t len) 
 {
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
        data += 4;
        len -= 4;
 #else /* !FREEBSD/DARWIN */
@@ -162,19 +327,45 @@ write_tun(int tun_fd, char *data, size_t len)
 #endif /* !LINUX */
 #endif /* FREEBSD */
 
+#ifndef WINDOWS32
        if (write(tun_fd, data, len) != len) {
                warn("write_tun");
                return 1;
        }
+#else /* WINDOWS32 */
+       {
+               DWORD written;
+               DWORD res;
+               OVERLAPPED olpd;
+
+               olpd.Offset = 0;
+               olpd.OffsetHigh = 0;
+               olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+               res = WriteFile(dev_handle, data, len, &written, &olpd);
+               if (!res && GetLastError() == ERROR_IO_PENDING) {
+                       WaitForSingleObject(olpd.hEvent, INFINITE);
+                       res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);
+                       if (written != len) {
+                               return -1;
+                       }
+               }
+       }
+#endif
        return 0;
 }
 
 ssize_t
 read_tun(int tun_fd, char *buf, size_t len) 
 {
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
        /* FreeBSD/Darwin/NetBSD has no header */
-       return read(tun_fd, buf + 4, len - 4) + 4;
+       int bytes;
+       bytes = recv(tun_fd, buf + 4, len, 0);
+       if (bytes < 0) {
+               return bytes;
+       } else {
+               return bytes + 4;
+       }
 #else /* !FREEBSD */
        return read(tun_fd, buf, len);
 #endif /* !FREEBSD */
@@ -187,10 +378,16 @@ tun_setip(const char *ip, int netbits)
        int netmask;
        struct in_addr net;
        int i;
-
 #ifndef LINUX
        int r;
 #endif
+#ifdef WINDOWS32
+       DWORD status;
+       DWORD ipdata[3];
+       struct in_addr addr;
+       DWORD len;
+#endif
+
        netmask = 0;
        for (i = 0; i < netbits; i++) {
                netmask = (netmask << 1) | 1;
@@ -198,51 +395,89 @@ tun_setip(const char *ip, int netbits)
        netmask <<= (32 - netbits);
        net.s_addr = htonl(netmask);
 
-       if (inet_addr(ip) != INADDR_NONE) {
-               snprintf(cmdline, sizeof(cmdline), 
-                               "/sbin/ifconfig %s %s %s netmask %s",
-                               if_name,
-                               ip,
-                               ip,
-                               inet_ntoa(net));
-               
-               printf("Setting IP of %s to %s\n", if_name, ip);
+       if (inet_addr(ip) == INADDR_NONE) {
+               fprintf(stderr, "Invalid IP: %s!\n", ip);
+               return 1;
+       }
+#ifndef WINDOWS32
+       snprintf(cmdline, sizeof(cmdline), 
+                       "/sbin/ifconfig %s %s %s netmask %s",
+                       if_name,
+                       ip,
+                       ip,
+                       inet_ntoa(net));
+       
+       fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
 #ifndef LINUX
-               r = system(cmdline);
-               if(r != 0) {
-                       return r;
-               } else {
-                       snprintf(cmdline, sizeof(cmdline),
-                                       "/sbin/route add %s/%d %s",
-                                       ip, netbits, ip);
-               }
-               printf("Adding route %s/%d to %s\n", ip, netbits, ip);
+       r = system(cmdline);
+       if(r != 0) {
+               return r;
+       } else {
+               snprintf(cmdline, sizeof(cmdline),
+                               "/sbin/route add %s/%d %s",
+                               ip, netbits, ip);
+       }
+       fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip);
 #endif
-               return system(cmdline);
+       return system(cmdline);
+#else /* WINDOWS32 */
+
+       /* Set device as connected */
+       fprintf(stderr, "Enabling interface '%s'\n", if_name);
+       status = 1;
+       r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, 
+               sizeof(status), &status, sizeof(status), &len, NULL);
+       if (!r) {
+               fprintf(stderr, "Failed to enable interface\n");
+               return -1;
+       }
+       
+       if (inet_aton(ip, &addr)) {
+               ipdata[0] = (DWORD) addr.s_addr;   /* local ip addr */
+               ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
+               ipdata[2] = (DWORD) net.s_addr;    /* netmask */
        } else {
-               printf("Invalid IP: %s!\n", ip);
+               return -1;
        }
 
-       return 1;
+       /* Tell ip/networkaddr/netmask to device for arp use */
+       r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata, 
+               sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);
+       if (!r) {
+               fprintf(stderr, "Failed to set interface in TUN mode\n");
+               return -1;
+       }
+
+       /* use netsh to set ip address */
+       fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip);
+       snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s",
+               if_name, ip, inet_ntoa(net));
+       return system(cmdline);
+#endif
 }
 
 int 
 tun_setmtu(const unsigned mtu)
 {
+#ifndef WINDOWS32
        char cmdline[512];
 
-       if (mtu > 200 && mtu < 1500) {
+       if (mtu > 200 && mtu <= 1500) {
                snprintf(cmdline, sizeof(cmdline), 
                                "/sbin/ifconfig %s mtu %u",
                                if_name,
                                mtu);
                
-               printf("Setting MTU of %s to %u\n", if_name, mtu);
+               fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu);
                return system(cmdline);
        } else {
                warn("MTU out of range: %u\n", mtu);
        }
 
        return 1;
+#else /* WINDOWS32 */
+
+       return 0;
+#endif
 }
 
index 01b402183572b77237053ec0795b049748f7db4e..b15665b44c356e178df4097dd277e0c2f632c80f 100644 (file)
 #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>
+
+#ifdef WINDOWS32
+#include <winsock2.h>
+#else
 #include <err.h>
 #include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
 
 #include "common.h"
 #include "encoding.h"
diff --git a/src/windows.h b/src/windows.h
new file mode 100644 (file)
index 0000000..f930855
--- /dev/null
@@ -0,0 +1,85 @@
+/*\r
+ * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software for any\r
+ * purpose with or without fee is hereby granted, provided that the above\r
+ * copyright notice and this permission notice appear in all copies.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+ */\r
+\r
+#ifndef __FIX_WINDOWS_H__\r
+#define __FIX_WINDOWS_H__\r
+\r
+typedef unsigned int in_addr_t;\r
+\r
+#include <windows.h>\r
+#include <windns.h>\r
+#include <winsock2.h>\r
+#include <ws2tcpip.h>\r
+#include <iphlpapi.h>\r
+\r
+#define T_A DNS_TYPE_A\r
+#define T_NS DNS_TYPE_NS\r
+#define T_NULL DNS_TYPE_NULL\r
+\r
+#define C_IN 1\r
+\r
+#define SERVFAIL 2\r
+#define NXDOMAIN 3\r
+#define NOTIMP 4\r
+#define REFUSED 5\r
+\r
+typedef struct {\r
+        unsigned        id :16;         /* query identification number */\r
+                        /* fields in third byte */\r
+        unsigned        rd :1;          /* recursion desired */\r
+        unsigned        tc :1;          /* truncated message */\r
+        unsigned        aa :1;          /* authoritive answer */\r
+        unsigned        opcode :4;      /* purpose of message */\r
+        unsigned        qr :1;          /* response flag */\r
+                        /* fields in fourth byte */\r
+        unsigned        rcode :4;       /* response code */\r
+        unsigned        cd: 1;          /* checking disabled by resolver */\r
+        unsigned        ad: 1;          /* authentic data from named */\r
+        unsigned        unused :1;      /* unused bits (MBZ as of 4.9.3a3) */\r
+        unsigned        ra :1;          /* recursion available */\r
+                        /* remaining bytes */\r
+        unsigned        qdcount :16;    /* number of question entries */\r
+        unsigned        ancount :16;    /* number of answer entries */\r
+        unsigned        nscount :16;    /* number of authority entries */\r
+        unsigned        arcount :16;    /* number of resource entries */\r
+} HEADER;\r
+\r
+struct ip\r
+  {\r
+    unsigned int ip_hl:4;               /* header length */\r
+    unsigned int ip_v:4;                /* version */\r
+    u_char ip_tos;                      /* type of service */\r
+    u_short ip_len;                     /* total length */\r
+    u_short ip_id;                      /* identification */\r
+    u_short ip_off;                     /* fragment offset field */\r
+#define IP_RF 0x8000                    /* reserved fragment flag */\r
+#define IP_DF 0x4000                    /* dont fragment flag */\r
+#define IP_MF 0x2000                    /* more fragments flag */\r
+#define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */\r
+    u_char ip_ttl;                      /* time to live */\r
+    u_char ip_p;                        /* protocol */\r
+    u_short ip_sum;                     /* checksum */\r
+    struct in_addr ip_src, ip_dst;      /* source and dest address */\r
+  };\r
+\r
+DWORD WINAPI tun_reader(LPVOID arg);\r
+struct tun_data {\r
+       HANDLE tun;\r
+       int sock;\r
+       struct sockaddr_in addr;\r
+};\r
+\r
+#endif\r
index 79f51f06ca43320e2f28254996bffbbf3d9e7457..3a7ac01ef7fcf6cdd0272a93f4c4b5723cd5f610 100644 (file)
@@ -1,7 +1,7 @@
 CC = gcc
 TEST = test
-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
+OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o user.o fw_query.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 ../src/fw_query.o
 
 OS = `uname | tr "a-z" "A-Z"`
 
index a3f95bbfd5fea2db7015818cea388adc8da5fe99..9ff0cf74ce0cf57cbfe529f246f8feca2d029ce1 100644 (file)
 #include "base32.h"
 #include "test.h"
 
+#define TUPLES 5
+
 static struct tuple
 {
        char *a;
        char *b;
-} testpairs[] = {
+} testpairs[TUPLES] = {
        { "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
        { "abc123", "mfrggmjsgm" },
-       { NULL, NULL }
+       { "test", "orsxg3a" },
+       { "tst", "orzxi" },
+       { "", "" },
 };
 
 START_TEST(test_base32_encode)
@@ -40,18 +44,14 @@ START_TEST(test_base32_encode)
        char buf[4096];
        struct encoder *b32;
        int val;
-       int i;
 
        b32 = get_base32_encoder();
 
-       for (i = 0; testpairs[i].a != NULL; i++) {
-               len = sizeof(buf);
-               val = b32->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
+       len = sizeof(buf);
+       val = b32->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
 
-               fail_unless(val > 0, strerror(errno));
-               fail_unless(strcmp(buf, testpairs[i].b) == 0,
-                               "'%s' != '%s'", buf, testpairs[i].b);
-       }
+       fail_unless(strcmp(buf, testpairs[_i].b) == 0,
+                       "'%s' != '%s'", buf, testpairs[_i].b);
 }
 END_TEST
 
@@ -61,19 +61,15 @@ START_TEST(test_base32_decode)
        char buf[4096];
        struct encoder *b32;
        int val;
-       int i;
        
        b32 = get_base32_encoder();
 
-       for (i = 0; testpairs[i].a != NULL; i++) {
-               len = sizeof(buf);
-               val = b32->decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
+       len = sizeof(buf);
+       val = b32->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
 
-               fail_unless(val > 0, strerror(errno));
-               fail_unless(buf != NULL, "buf == NULL");
-               fail_unless(strcmp(buf, testpairs[i].a) == 0,
-                               "'%s' != '%s'", buf, testpairs[i].a);
-       }
+       fail_unless(buf != NULL, "buf == NULL");
+       fail_unless(strcmp(buf, testpairs[_i].a) == 0,
+                       "'%s' != '%s'", buf, testpairs[_i].a);
 }
 END_TEST
 
@@ -89,15 +85,58 @@ START_TEST(test_base32_5to8_8to5)
 }
 END_TEST
 
+START_TEST(test_base32_blksize)
+{
+       size_t rawlen;
+       size_t enclen;
+       char *rawbuf;
+       char *encbuf;
+       struct encoder *b32;
+       int i;
+       int val;
+
+       b32 = get_base32_encoder();
+
+       rawlen = b32->blocksize_raw();
+       enclen = b32->blocksize_encoded();
+
+       rawbuf = malloc(rawlen + 16);
+       encbuf = malloc(enclen + 16);
+
+       for (i = 0; i < rawlen; i++) {
+               rawbuf[i] = 'A';
+       }
+       rawbuf[i] = 0;
+
+       val = b32->encode(encbuf, &enclen, rawbuf, rawlen);
+
+       fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
+       fail_unless(enclen == 5, "encoded %d bytes, not 5", enclen);
+       fail_unless(val == 8, "encoded string %s was length %d", encbuf, val);
+
+       memset(rawbuf, 0, rawlen + 16);
+
+       enclen = val;
+       val = b32->decode(rawbuf, &rawlen, encbuf, enclen);
+
+       fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
+       fail_unless(val == 5, "val was not 5 but %d", val);
+       for (i = 0; i < rawlen; i++) {
+               fail_unless(rawbuf[i] == 'A');
+       }
+}
+END_TEST
+
 TCase *
 test_base32_create_tests()
 {
        TCase *tc;
 
        tc = tcase_create("Base32");
-       tcase_add_test(tc, test_base32_encode);
-       tcase_add_test(tc, test_base32_decode);
+       tcase_add_loop_test(tc, test_base32_encode, 0, TUPLES);
+       tcase_add_loop_test(tc, test_base32_decode, 0, TUPLES);
        tcase_add_test(tc, test_base32_5to8_8to5);
+       tcase_add_test(tc, test_base32_blksize);
 
        return tc;
 }
index 280963ec153a78345b78ac8543c2977fa50cde3e..bd0e9ce5c7b4890708b43d6c6b92becf0d813f69 100644 (file)
 #include "base64.h"
 #include "test.h"
 
+#define TUPLES 5
+
 static struct tuple
 {
        char *a;
        char *b;
-} testpairs[] = {
+} testpairs[TUPLES] = {
        { "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
        { "abc1231", "ywjJmtiZmq" },
        {
@@ -59,7 +61,7 @@ static struct tuple
          "776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654321"
          "0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
        },
-       { NULL, NULL }
+       { "", "" }
 };
 
 START_TEST(test_base64_encode)
@@ -68,18 +70,14 @@ START_TEST(test_base64_encode)
        char buf[4096];
        struct encoder *b64;
        int val;
-       int i;
 
        b64 = get_base64_encoder();
 
-       for (i = 0; testpairs[i].a != NULL; i++) {
-               len = sizeof(buf);
-               val = b64->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
+       len = sizeof(buf);
+       val = b64->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
 
-               fail_unless(val > 0, strerror(errno));
-               fail_unless(strcmp(buf, testpairs[i].b) == 0,
-                               "'%s' != '%s'", buf, testpairs[i].b);
-       }
+       fail_unless(strcmp(buf, testpairs[_i].b) == 0,
+                       "'%s' != '%s'", buf, testpairs[_i].b);
 }
 END_TEST
 
@@ -89,18 +87,56 @@ START_TEST(test_base64_decode)
        char buf[4096];
        struct encoder *b64;
        int val;
+
+       b64 = get_base64_encoder();
+
+       len = sizeof(buf);
+       val = b64->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
+
+       fail_unless(buf != NULL, "buf == NULL");
+       fail_unless(strcmp(buf, testpairs[_i].a) == 0,
+                       "'%s' != '%s'", buf, testpairs[_i].a);
+}
+END_TEST
+
+START_TEST(test_base64_blksize)
+{
+       size_t rawlen;
+       size_t enclen;
+       char *rawbuf;
+       char *encbuf;
+       struct encoder *b64;
        int i;
+       int val;
 
        b64 = get_base64_encoder();
 
-       for (i = 0; testpairs[i].a != NULL; i++) {
-               len = sizeof(buf);
-               val = b64->decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
+       rawlen = b64->blocksize_raw();
+       enclen = b64->blocksize_encoded();
+
+       rawbuf = malloc(rawlen + 16);
+       encbuf = malloc(enclen + 16);
+
+       for (i = 0; i < rawlen; i++) {
+               rawbuf[i] = 'A';
+       }
+       rawbuf[i] = 0;
+
+       val = b64->encode(encbuf, &enclen, rawbuf, rawlen);
+
+       fail_unless(rawlen == 3, "raw length was %d not 3", rawlen);
+       fail_unless(enclen == 3, "encoded %d bytes, not 3", enclen);
+       fail_unless(val == 4, "encoded string %s was length %d", encbuf, val);
+
+       memset(rawbuf, 0, rawlen + 16);
+
+       enclen = val;
+       val = b64->decode(rawbuf, &rawlen, encbuf, enclen);
 
-               fail_unless(val > 0, strerror(errno));
-               fail_unless(buf != NULL, "buf == NULL");
-               fail_unless(strcmp(buf, testpairs[i].a) == 0,
-                               "'%s' != '%s'", buf, testpairs[i].a);
+       fail_unless(rawlen == 3, "raw length was %d not 3", rawlen);
+       fail_unless(val == 3);
+       for (i = 0; i < rawlen; i++) {
+               fail_unless(rawbuf[i] == 'A');
        }
 }
 END_TEST
@@ -111,8 +147,9 @@ test_base64_create_tests()
        TCase *tc;
 
        tc = tcase_create("Base64");
-       tcase_add_test(tc, test_base64_encode);
-       tcase_add_test(tc, test_base64_decode);
+       tcase_add_loop_test(tc, test_base64_encode, 0, TUPLES);
+       tcase_add_loop_test(tc, test_base64_decode, 0, TUPLES);
+       tcase_add_test(tc, test_base64_blksize);
 
        return tc;
 }
index 185f15834b0bd42313d41ed6858e7ffcb00b4739..55e753b5bf669716cb23bd9cf87f434fb93edb46 100644 (file)
 
 static void dump_packet(char *, size_t);
 
-static char queryPacket[] =
+static char query_packet[] =
        "\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[] =
+static char answer_packet[] =
        "\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
        "\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
        "\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
@@ -48,7 +48,7 @@ static char answerPacket[] =
        "\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
        "\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
 
-static char answerPacketHighTransId[] =
+static char answer_packet_high_trans_id[] =
        "\x85\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
        "\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
        "\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
@@ -87,14 +87,14 @@ START_TEST(test_encode_query)
        }
        strcpy(d, topdomain);
        ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
-       len = sizeof(queryPacket) - 1; /* Skip extra null character */
+       len = sizeof(query_packet) - 1; /* Skip extra null character */
 
-       if (strncmp(queryPacket, buf, sizeof(queryPacket)) || ret != len) {
+       if (strncmp(query_packet, buf, sizeof(query_packet)) || ret != len) {
                printf("\n");
-               dump_packet(queryPacket, len);
+               dump_packet(query_packet, len);
                dump_packet(buf, ret);
        }
-       fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
+       fail_unless(strncmp(query_packet, buf, sizeof(query_packet)) == 0, "Did not compile expected packet");
        fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
 }
 END_TEST
@@ -110,10 +110,10 @@ START_TEST(test_decode_query)
        memset(&q, 0, sizeof(struct query));
        memset(&buf, 0, sizeof(buf));
        q.id = 0;
-       len = sizeof(queryPacket) - 1;
+       len = sizeof(query_packet) - 1;
        enc = get_base32_encoder();
 
-       dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len);
+       dns_decode(buf, sizeof(buf), &q, QR_QUERY, query_packet, len);
        domain = strstr(q.name, topdomain);
        len = sizeof(buf);
        unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);
@@ -139,9 +139,9 @@ START_TEST(test_encode_response)
        q.id = 1337;
 
        ret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData));
-       len = sizeof(answerPacket) - 1; /* Skip extra null character */
+       len = sizeof(answer_packet) - 1; /* Skip extra null character */
 
-       fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
+       fail_unless(strncmp(answer_packet, buf, sizeof(answer_packet)) == 0, "Did not compile expected packet");
        fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
 }
 END_TEST
@@ -156,7 +156,7 @@ START_TEST(test_decode_response)
        len = sizeof(buf);
        memset(&buf, 0, sizeof(buf));
 
-       ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
+       ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet, sizeof(answer_packet)-1);
        fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
        fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
        fail_unless(q.id == 0x0539);
@@ -173,12 +173,45 @@ START_TEST(test_decode_response_with_high_trans_id)
        len = sizeof(buf);
        memset(&buf, 0, sizeof(buf));
 
-       ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacketHighTransId, sizeof(answerPacketHighTransId)-1);
+       ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)-1);
        fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
        fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
        fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539);
 }
 END_TEST
+
+START_TEST(test_get_id_short_packet)
+{
+       char buf[5];
+       int len;
+       unsigned short id;
+
+       len = sizeof(buf);
+       memset(&buf, 5, sizeof(buf));
+
+       id = dns_get_id(buf, len);
+       fail_unless(id == 0);
+}
+END_TEST
+
+START_TEST(test_get_id_low)
+{
+       unsigned short id;
+
+       id = dns_get_id(answer_packet, sizeof(answer_packet));
+       fail_unless(id == 1337);
+}
+END_TEST
+
+START_TEST(test_get_id_high)
+{
+       unsigned short id;
+
+       id = dns_get_id(answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id));
+       fail_unless(id == 0x8539);
+}
+END_TEST
+
 static void
 dump_packet(char *buf, size_t len)
 {
@@ -209,6 +242,9 @@ test_dns_create_tests()
        tcase_add_test(tc, test_encode_response);
        tcase_add_test(tc, test_decode_response);
        tcase_add_test(tc, test_decode_response_with_high_trans_id);
+       tcase_add_test(tc, test_get_id_short_packet);
+       tcase_add_test(tc, test_get_id_low);
+       tcase_add_test(tc, test_get_id_high);
 
        return tc;
 }
diff --git a/tests/fw_query.c b/tests/fw_query.c
new file mode 100644 (file)
index 0000000..6d23924
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2006-2009 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 "fw_query.h"
+#include "test.h"
+
+START_TEST(test_fw_query_simple)
+{
+       struct fw_query q;
+       struct fw_query *qp;
+
+       q.addrlen = 33;
+       q.id = 0x848A;
+
+       fw_query_init();
+       
+       /* Test empty cache */
+       fw_query_get(0x848A, &qp);
+       fail_unless(qp == NULL);
+
+       fw_query_put(&q);
+
+       /* Test cache with one entry */
+       fw_query_get(0x848A, &qp);
+       fail_unless(qp->addrlen == q.addrlen);
+       fail_unless(qp->id == q.id);
+}
+END_TEST
+
+START_TEST(test_fw_query_edge)
+{
+       struct fw_query q;
+       struct fw_query *qp;
+       int i;
+
+       fw_query_init();
+       
+       q.addrlen = 33;
+       q.id = 0x848A;
+       fw_query_put(&q);
+
+       for (i = 1; i < FW_QUERY_CACHE_SIZE; i++) {
+               q.addrlen++;
+               q.id++;
+               fw_query_put(&q);
+       }
+
+       /* The query should still be cached */
+       fw_query_get(0x848A, &qp);
+       fail_unless(qp->addrlen == 33);
+       fail_unless(qp->id == 0x848A);
+               
+       q.addrlen++;
+       q.id++;
+       fw_query_put(&q);
+
+       /* but now it is overwritten */
+       fw_query_get(0x848A, &qp);
+       fail_unless(qp == NULL);
+}
+END_TEST
+
+TCase *
+test_fw_query_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("Forwarded query");
+       tcase_add_test(tc, test_fw_query_simple);
+       tcase_add_test(tc, test_fw_query_edge);
+
+       return tc;
+}
index 2745c92a5478b45ff96573c2d20e2f22c12b39b4..1ef23f4c6a17ed12d953719b98ddf65532aa86f8 100644 (file)
@@ -28,7 +28,7 @@ START_TEST(test_login_hash)
        int len;
        int seed;
 
-       len = 16;
+       len = sizeof(ans);
        seed = 15;
 
        memset(ans, 0, sizeof(ans));
@@ -37,6 +37,26 @@ START_TEST(test_login_hash)
 }
 END_TEST
 
+START_TEST(test_login_hash_short)
+{
+       char ans[8];
+       char check[sizeof(ans)];
+       char pass[32] = "iodine is the shit";
+       int len;
+       int seed;
+
+       len = sizeof(ans);
+       seed = 15;
+
+       memset(ans, 0, sizeof(ans));
+       memset(check, 0, sizeof(check));
+
+       /* If len < 16, it should do nothing */
+       login_calculate(ans, len, pass, seed);
+       fail_if(memcmp(ans, check, sizeof(ans)));
+}
+END_TEST
+
 TCase *
 test_login_create_tests()
 {
@@ -44,6 +64,7 @@ test_login_create_tests()
 
        tc = tcase_create("Login");
        tcase_add_test(tc, test_login_hash);
+       tcase_add_test(tc, test_login_hash_short);
 
        return tc;
 }
index ab55341ef1308187cda33541dd81bf40d4c24217..18cc29ce9b4ce9fe3fe253dfab88e620da755903 100644 (file)
@@ -83,14 +83,42 @@ START_TEST(test_read_putlong)
 }
 END_TEST
 
-START_TEST(test_read_name)
+START_TEST(test_read_name_empty_loop)
 {
        unsigned char emptyloop[] = {
                'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
+       char buf[1024];
+       char *data;
+       int rv;
+
+       memset(buf, 0, sizeof(buf));
+       data = (char*) emptyloop + sizeof(HEADER);
+       buf[1023] = 'A';
+       rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
+       fail_unless(buf[1023] == 'A');
+}
+END_TEST
+
+START_TEST(test_read_name_inf_loop)
+{
        unsigned char infloop[] = {
                'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
+       char buf[1024];
+       char *data;
+       int rv;
+
+       memset(buf, 0, sizeof(buf));
+       data = (char*) infloop + sizeof(HEADER);
+       buf[4] = '\a';
+       rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
+       fail_unless(buf[4] == '\a');
+}
+END_TEST
+
+START_TEST(test_read_name_longname)
+{
        unsigned char longname[] =
                "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
                "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
@@ -100,44 +128,45 @@ START_TEST(test_read_name)
                "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
                "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
                "\x00\x00\x01\x00\x01";
-       unsigned char onejump[] =
-               "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
-               "\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
-       unsigned char badjump[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
-       unsigned char badjump2[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
-       unsigned char *jumper;
        char buf[1024];
        char *data;
        int rv;
 
-       memset(buf, 0, sizeof(buf));
-       data = (char*) emptyloop + sizeof(HEADER);
-       buf[1023] = 'A';
-       rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
-       fail_unless(buf[1023] == 'A', NULL);
-
-       memset(buf, 0, sizeof(buf));
-       data = (char*) infloop + sizeof(HEADER);
-       buf[4] = '\a';
-       rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
-       fail_unless(buf[4] == '\a', NULL);
-
        memset(buf, 0, sizeof(buf));
        data = (char*) longname + sizeof(HEADER);
        buf[256] = '\a';
        rv = readname((char*) longname, sizeof(longname), &data, buf, 256);
-       fail_unless(buf[256] == '\a', NULL);
+       fail_unless(buf[256] == '\a');
+}
+END_TEST
+
+START_TEST(test_read_name_onejump)
+{
+       unsigned char onejump[] =
+               "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+               "\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
+       char buf[1024];
+       char *data;
+       int rv;
 
        memset(buf, 0, sizeof(buf));
        data = (char*) onejump + sizeof(HEADER);
        rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);
-       fail_unless(rv == 9, NULL);
+       fail_unless(rv == 9);
+}
+END_TEST
+
+START_TEST(test_read_name_badjump_start)
+{
+       unsigned char badjump[] = {
+               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
+       unsigned char *jumper;
+       char buf[1024];
+       char *data;
+       int rv;
 
-       /* These two tests use malloc to cause segfault if jump is executed */
+       /* This test uses malloc to cause segfault if jump is executed */
        memset(buf, 0, sizeof(buf));
        jumper = malloc(sizeof(badjump));
        if (jumper) {
@@ -145,11 +174,24 @@ START_TEST(test_read_name)
                data = (char*) jumper + sizeof(HEADER);
                rv = readname((char*) jumper, sizeof(badjump), &data, buf, 256);
 
-               fail_unless(rv == 0, NULL);
-               fail_unless(buf[0] == 0, NULL);
+               fail_unless(rv == 0);
+               fail_unless(buf[0] == 0);
        }
        free(jumper);
+}
+END_TEST
+
+START_TEST(test_read_name_badjump_second)
+{
+       unsigned char badjump2[] = {
+               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
+       unsigned char *jumper;
+       char buf[1024];
+       char *data;
+       int rv;
 
+       /* This test uses malloc to cause segfault if jump is executed */
        memset(buf, 0, sizeof(buf));
        jumper = malloc(sizeof(badjump2));
        if (jumper) {
@@ -157,7 +199,7 @@ START_TEST(test_read_name)
                data = (char*) jumper + sizeof(HEADER);
                rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
 
-               fail_unless(rv == 4, NULL);
+               fail_unless(rv == 4);
                fail_unless(strcmp("BA.", buf) == 0,
                                "buf is not BA: %s", buf);
        }
@@ -180,7 +222,7 @@ START_TEST(test_putname)
        b = buf;
        ret = putname(&b, 256, domain);
 
-       fail_unless(ret == strlen(domain) + 1, NULL);
+       fail_unless(ret == strlen(domain) + 1);
        fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
 }
 END_TEST
@@ -201,8 +243,8 @@ START_TEST(test_putname_nodot)
        b = buf;
        ret = putname(&b, 256, nodot);
 
-       fail_unless(ret == -1, NULL);
-       fail_unless(b == buf, NULL);
+       fail_unless(ret == -1);
+       fail_unless(b == buf);
 }
 END_TEST
 
@@ -226,8 +268,8 @@ START_TEST(test_putname_toolong)
        b = buf;
        ret = putname(&b, 256, toolong);
 
-       fail_unless(ret == -1, NULL);
-       fail_unless(b == buf, NULL);
+       fail_unless(ret == -1);
+       fail_unless(b == buf);
 }
 END_TEST
 
@@ -241,7 +283,12 @@ test_read_create_tests()
        tcase_set_timeout(tc, 60);
        tcase_add_test(tc, test_read_putshort);
        tcase_add_test(tc, test_read_putlong);
-       tcase_add_test(tc, test_read_name);
+       tcase_add_test(tc, test_read_name_empty_loop);
+       tcase_add_test(tc, test_read_name_inf_loop);
+       tcase_add_test(tc, test_read_name_longname);
+       tcase_add_test(tc, test_read_name_onejump);
+       tcase_add_test(tc, test_read_name_badjump_start);
+       tcase_add_test(tc, test_read_name_badjump_second);
        tcase_add_test(tc, test_putname);
        tcase_add_test(tc, test_putname_nodot);
        tcase_add_test(tc, test_putname_toolong);
index 8e6359791f7222c427c082d48b29e3338c477b40..5bee9d23be8879f4f898f5084758d14c99d87336 100644 (file)
@@ -53,6 +53,9 @@ main()
        test = test_user_create_tests();
        suite_add_tcase(iodine, test);
 
+       test = test_fw_query_create_tests();
+       suite_add_tcase(iodine, test);
+
        runner = srunner_create(iodine);
        srunner_run_all(runner, CK_NORMAL);
        failed = srunner_ntests_failed(runner);
index 54a3fffa027995bf523c761480866c9251b3628c..1022a9ea1159b44754682c8a39334c12d050d59f 100644 (file)
@@ -24,6 +24,7 @@ TCase *test_encoding_create_tests();
 TCase *test_read_create_tests();
 TCase *test_login_create_tests();
 TCase *test_user_create_tests();
+TCase *test_fw_query_create_tests();
 
 char *va_str(const char *, ...);