[svn-upgrade] Integrating new upstream version, iodine (0.4.0) upstream/0.4.0
authorgregor herrmann <gregoa@debian.org>
Fri, 30 Mar 2007 19:35:28 +0000 (19:35 -0000)
committergregor herrmann <gregoa@debian.org>
Fri, 30 Mar 2007 19:35:28 +0000 (19:35 -0000)
48 files changed:
CHANGELOG
Makefile
README
TODO
dns.c [deleted file]
dns.h [deleted file]
encoding.c [deleted file]
encoding.h [deleted file]
iodine.c [deleted file]
iodined.c [deleted file]
man/iodine.8 [new file with mode: 0644]
read.c [deleted file]
read.h [deleted file]
src/Makefile [new file with mode: 0644]
src/base32.c [new file with mode: 0644]
src/base32.h [new file with mode: 0644]
src/common.c [new file with mode: 0644]
src/common.h [new file with mode: 0644]
src/dns.c [new file with mode: 0644]
src/dns.h [new file with mode: 0644]
src/encoding.c [new file with mode: 0644]
src/encoding.h [new file with mode: 0644]
src/iodine.c [new file with mode: 0644]
src/iodined.c [new file with mode: 0644]
src/login.c [new file with mode: 0644]
src/login.h [new file with mode: 0644]
src/md5.c [new file with mode: 0644]
src/md5.h [new file with mode: 0644]
src/read.c [new file with mode: 0644]
src/read.h [new file with mode: 0644]
src/tun.c [new file with mode: 0644]
src/tun.h [new file with mode: 0644]
src/user.c [new file with mode: 0644]
src/user.h [new file with mode: 0644]
src/version.h [new file with mode: 0644]
structs.h [deleted file]
test.c [deleted file]
tests/Makefile [new file with mode: 0644]
tests/base32.c [new file with mode: 0644]
tests/dns.c [new file with mode: 0644]
tests/encoding.c [new file with mode: 0644]
tests/login.c [new file with mode: 0644]
tests/read.c [new file with mode: 0644]
tests/test.c [new file with mode: 0644]
tests/test.h [new file with mode: 0644]
tests/user.c [new file with mode: 0644]
tun.c [deleted file]
tun.h [deleted file]

index 70dd54bfeb20f0157f566916266d9aa5da9e99de..3ecee1fa7df085b18fc034aef3654cf5a59566f2 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,6 +7,14 @@ iodine - IP over DNS is now easy
 
 CHANGES:
 
+2007-03-25: 0.4.0 "Run Home"
+       - Added multiuser support (up to 8 users simultaneously)
+       - Added authentication (password entered as argument or on stdin)
+       - Added manpage
+       - Added install/uninstall make target
+       - Cleanup of dns code, more test cases, use check library
+       - Changed directory structure
+
 2006-11-08: 0.3.4
        - Fixed handshake() buffer overflow
          (Found by poplix, Secunia: SA22674 / FrSIRT/ADV-2006-4333)
index 207b4e3f44295d0a3aa101b48236ffadbff6ffe1..c6d63a2b022a5b650dcc8d1c119291a2aef5374c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,43 +1,35 @@
-CC = gcc
-CLIENT = iodine
-CLIENTOBJS = iodine.o tun.o dns.o read.o encoding.o
-SERVER = iodined
-SERVEROBJS = iodined.o tun.o dns.o read.o encoding.o
-TESTSUITE = tester
-TESTOBJS = test.o dns.o read.o encoding.o
+PREFIX=/usr/local
 
-OS = `uname | tr "a-z" "A-Z"`
+INSTALL=/usr/bin/install
+INSTALL_FLAGS=
 
-LDFLAGS =  -lz
-CFLAGS = -c -g -Wall -D$(OS)
+MKDIR=mkdir
+MKDIR_FLAGS=-p
 
-all: stateos $(CLIENT) $(SERVER) $(TESTSUITE) 
+RM=rm
+RM_FLAGS=-f
 
-test:  $(TESTSUITE)
-       @./$(TESTSUITE)
+all: 
+       @(cd src; make all)
 
-stateos:
-       @echo OS is $(OS)
+install: all
+       $(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/sbin
+       $(INSTALL) $(INSTALL_FLAGS) bin/iodine $(PREFIX)/sbin/iodine
+       $(INSTALL) $(INSTALL_FLAGS) bin/iodined $(PREFIX)/sbin/iodined
+       $(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/man/man8
+       $(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(PREFIX)/man/man8/iodine.8
 
-$(CLIENT): $(CLIENTOBJS)
-       @echo LD $@
-       @$(CC) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
-
-$(SERVER): $(SERVEROBJS)
-       @echo LD $@
-       @$(CC) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
-
-$(TESTSUITE): $(TESTOBJS)
-       @echo LD $@
-       @$(CC) $(TESTOBJS) -o $(TESTSUITE) $(LDFLAGS)
-       @echo Running tests... 
-       @./$(TESTSUITE)
-
-.c.o: 
-       @echo CC $<
-       @$(CC) $(CFLAGS) $< -o $@
+uninstall:
+       $(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodine
+       $(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodined
+       $(RM) $(RM_FLAGS) $(PREFIX)/man/man8/iodine.8
+       
+test: all
+       @(cd tests; make all)
 
 clean:
        @echo "Cleaning..."
-       @rm -f $(CLIENT) $(SERVER) $(TESTSUITE) *~ *.o *.core
+       @(cd src; make clean)
+       @(cd tests; make clean)
+       @rm -rf bin
 
diff --git a/README b/README
index 0803fc12ba625f8484ed02694632d90761d6cf5f..f52ed4f370762f6cd5d9f517f42c2debe7c650f0 100644 (file)
--- a/README
+++ b/README
@@ -16,8 +16,10 @@ Try it out within your own LAN! Follow these simple steps:
 - On your server, run: ./iodined -f 10.0.0.1 test.asdf
   (If you already use the 10.0.0.0 network, use another internal net like 
   172.16.0.0)
+- Enter a password
 - On the client, run: ./iodine -f 192.168.0.1 test.asdf
   (Replace 192.168.0.1 with the server's ip address)
+- Enter the same password
 - Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
 - Try pinging each other through the tunnel
 - Done! :)
@@ -40,8 +42,9 @@ to your server. Start iodined on the server. The first argument is the tunnel
 IP address (like 192.168.99.1) and the second is the assigned domain (in this
 case tunnel1.mytunnel.com). The -f argument will keep iodined running in the
 foreground, which helps when testing. iodined will start a virtual interface,
-and also start listening for DNS queries on UDP port 53. Now everything is
-ready for the client.
+and also start listening for DNS queries on UDP port 53. Either enter a
+password on the commandline (-P pass) or after the server has started. Now 
+everything is ready for the client.
 
 Client side: 
 All the setup is done, just start iodine. It also takes two
@@ -49,8 +52,10 @@ arguments, the first is the local relaying DNS server and the second is the
 domain used (tunnel1.mytunnnel.com). If DNS queries are allowed to any
 computer, you can use the tunnel endpoint (example: 10.15.213.99 or
 tunnel1host.mytunnel.com) as the first argument. The tunnel interface will get
-an IP close to the servers (in this case 192.168.99.2) and a suitable MTU. Now
-you should be able to ping the other end of the tunnel from either side.  
+an IP close to the servers (in this case 192.168.99.2) and a suitable MTU. 
+Enter the same password as on the server either by argument or after the client
+has started. Now you should be able to ping the other end of the tunnel from 
+either side.  
 
 
 MISC. INFO:
@@ -84,8 +89,8 @@ iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
 
 PORTABILITY:
 
-iodine has been tested on Linux (x86, AMD64 and SPARC64), FreeBSD (x86), 
-OpenBSD (x86), NetBSD (x86) and MacOS X (10.3, ppc, with 
+iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD 
+(ia64, x86), OpenBSD (x86), NetBSD (x86) and MacOS X (10.3, ppc, with 
 http://www-user.rhrk.uni-kl.de/~nissler/tuntap/). It should work on other 
 unix-like systems as well that has TUN/TAP tunneling support (after some 
 patching). Let us know if you get it to run on other platforms. 
@@ -105,7 +110,7 @@ THANKS:
 
 AUTHORS & LICENSE:
 
-Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
 
 Permission to use, copy, modify, and distribute this software for any purpose
 with or without fee is hereby granted, provided that the above copyright notice
@@ -118,3 +123,7 @@ 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.
+
+
+MD5 implementation by L. Peter Deutsch (license and source in src/md5.[ch])
+Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
diff --git a/TODO b/TODO
index 31467fd4a0e9350562a7a236296fe65a64e1d0dc..766d37b88eb9d908b8ce08fd6b9b625874e0ba83 100644 (file)
--- a/TODO
+++ b/TODO
@@ -5,15 +5,10 @@ iodine - IP over DNS is now easy
 
 ********************************
 
-STUFF TO DO:
+The TODO list is now located at
 
-- Handle multiple concurrent users on one server
+http://dev.kryo.se/iodine/
 
-- Some kind of authentication?
-
-- Detect if EDNS0 can be used, probe MTU size
-
-- Port to more platforms (Solaris? Windows?)
-
-- More/better documentation (as always)
+The list is under the "View tickets" page
 
+Feel free to add your own wishes and bug reports
diff --git a/dns.c b/dns.c
deleted file mode 100644 (file)
index ade40de..0000000
--- a/dns.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#ifdef DARWIN
-#include <arpa/nameser8_compat.h>
-#endif
-#include <netdb.h>
-#include <time.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "structs.h"
-#include "dns.h"
-#include "encoding.h"
-#include "read.h"
-
-// For FreeBSD
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-
-
-static int dns_write(int, int, char *, int, char);
-static void dns_query(int, int, char *, int);
-
-struct sockaddr_in peer;
-char topdomain[256];
-
-// Current IP packet
-char activepacket[4096];
-int lastlen;
-int packetpos;
-int packetlen;
-uint16_t chunkid;
-
-uint16_t pingid;
-
-
-int 
-open_dns(const char *domain, int localport, in_addr_t listen_ip) 
-{
-       int fd;
-       int flag;
-       struct sockaddr_in addr;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_port = htons(localport);
-       /* listen_ip already in network byte order from inet_addr, or 0 */
-       addr.sin_addr.s_addr = listen_ip; 
-
-       fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if(fd < 0) {
-               warn("socket");
-               return -1;
-       }
-
-       flag = 1;
-#ifdef SO_REUSEPORT
-       setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
-#endif
-       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
-
-       if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
-               warn("bind");
-               return -1;
-       }
-
-       // Save top domain used
-       strncpy(topdomain, domain, sizeof(topdomain) - 1);
-       topdomain[sizeof(topdomain) - 1] = '\0';
-
-       printf("Opened UDP socket\n");
-
-       return fd;
-}
-
-int 
-dns_settarget(const char *host) 
-{
-       struct hostent *h;
-
-       // Init dns target struct
-       h = gethostbyname(host);
-       if (!h) {
-               printf("Could not resolve name %s, exiting\n", host);
-               return -1;
-       }
-
-       memset(&peer, 0, sizeof(peer));
-       peer.sin_family = AF_INET;
-       peer.sin_port = htons(53);
-       peer.sin_addr = *((struct in_addr *) h->h_addr);
-
-       // Init chunk id
-       chunkid = 0;
-       pingid = 0;
-
-       return 0;
-}
-
-void
-close_dns(int fd)
-{
-       close(fd);
-}
-
-int
-dns_sending()
-{
-       return (packetlen != 0);
-}
-
-static void
-dns_send_chunk(int fd)
-{
-       int avail;
-       char *p;
-
-       p = activepacket;
-       p += packetpos;
-       avail = packetlen - packetpos;
-       lastlen = dns_write(fd, ++chunkid, p, avail, 0);
-}
-
-void
-dns_handle_tun(int fd, char *data, int len)
-{
-       memcpy(activepacket, data, MIN(len, sizeof(activepacket)));
-       lastlen = 0;
-       packetpos = 0;
-       packetlen = len;
-
-       dns_send_chunk(fd);
-}
-
-void
-dns_ping(int dns_fd)
-{
-       char data[2];
-       if (dns_sending()) {
-               lastlen = 0;
-               packetpos = 0;
-               packetlen = 0;
-       }
-       data[0] = (pingid & 0xFF00) >> 8;
-       data[1] = (pingid & 0xFF);
-       dns_write(dns_fd, ++pingid, data, 2, 'P');
-}
-
-void 
-dns_handshake(int dns_fd)
-{
-       char data[2];
-       data[0] = (pingid & 0xFF00) >> 8;
-       data[1] = (pingid & 0xFF);
-       dns_write(dns_fd, ++pingid, data, 2, 'H');
-}
-
-static void 
-dns_query(int fd, int id, char *host, int type)
-{
-       char *p;
-       int len;
-       int peerlen;
-       char buf[1024];
-       HEADER *header;
-       
-       len = 0;
-       memset(buf, 0, sizeof(buf));
-
-       header = (HEADER*)buf;  
-       
-       header->id = htons(id);
-       header->qr = 0;
-       header->opcode = 0;
-       header->aa = 0;
-       header->tc = 0;
-       header->rd = 1;
-       header->ra = 0;
-
-       header->qdcount = htons(1);
-       header->arcount = htons(1);
-
-       p = buf + sizeof(HEADER);
-       p += dns_encode_hostname(host, p, strlen(host));        
-
-       putshort(&p, type);
-       putshort(&p, C_IN);
-
-       // EDNS0
-       putbyte(&p, 0x00); //Root
-       putshort(&p, 0x0029); // OPT
-       putshort(&p, 0x1000); // Payload size: 4096
-       putshort(&p, 0x0000); // Higher bits/edns version
-       putshort(&p, 0x8000); // Z
-       putshort(&p, 0x0000); // Data length
-
-       peerlen = sizeof(peer);
-
-       len = p - buf;
-       sendto(fd, buf, len, 0, (struct sockaddr*)&peer, peerlen);
-}
-
-static int
-dns_write(int fd, int id, char *buf, int len, char flag)
-{
-       int avail;
-       int written;
-       int encoded;
-       char data[257];
-       char *d;
-
-       avail = 0xFF - strlen(topdomain) - 2;
-       memset(data, 0, sizeof(data));
-       d = data;
-       written = encode_data(buf, len, avail, d, flag);
-       encoded = strlen(data);
-       d += encoded;
-       if (*d != '.') {
-               *d++ = '.';
-       }
-       strncpy(d, topdomain, strlen(topdomain)+1);
-       
-       dns_query(fd, id, data, T_NULL);
-       return written;
-}
-
-int
-dns_read(int fd, char *buf, int buflen)
-{
-       int r;
-       socklen_t addrlen;
-       char packet[64*1024];
-       struct sockaddr_in from;
-       HEADER *header;
-
-       addrlen = sizeof(struct sockaddr);
-       r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
-       if(r == -1) {
-               perror("recvfrom");
-               return 0;
-       }
-
-       header = (HEADER*)packet;
-       if (dns_sending() && chunkid == ntohs(header->id)) {
-               /* Got ACK on sent packet */
-               packetpos += lastlen;
-               if (packetpos == packetlen) {
-                       /* Packet completed */
-                       packetpos = 0;
-                       packetlen = 0;
-                       lastlen = 0;
-               } else {
-                       /* More to send */
-                       dns_send_chunk(fd);
-               }
-       }
-       return dns_parse_reply(buf, buflen, packet, r);
-}
-
-int
-dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen)
-{
-       int rv;
-       uint32_t ttl;
-       short rlen;
-       short type;
-       short class;
-       short qdcount;
-       short ancount;
-       char *data;
-       char name[255];
-       char rdata[4*1024];
-       HEADER *header;
-
-       rv = 0;
-       header = (HEADER*)packet;
-       
-       data = packet + sizeof(HEADER);
-
-       if(header->qr) { /* qr=1 => response */
-               qdcount = ntohs(header->qdcount);
-               ancount = ntohs(header->ancount);
-
-               rlen = 0;
-
-               if(qdcount == 1) {
-                       readname(packet, packetlen, &data, name, sizeof(name));
-                       readshort(packet, &data, &type);
-                       readshort(packet, &data, &class);
-               }
-               if(ancount == 1) {
-                       readname(packet, packetlen, &data, name, sizeof(name));
-                       readshort(packet, &data, &type);
-                       readshort(packet, &data, &class);
-                       readlong(packet, &data, &ttl);
-                       readshort(packet, &data, &rlen);
-                       rv = MIN(rlen, sizeof(rdata));
-                       readdata(packet, &data, rdata, rv);
-               }
-
-               if(type == T_NULL && rv > 2) {
-                       rv = MIN(rv, buflen);
-                       memcpy(outbuf, rdata, rv);
-               }
-       }
-
-       return rv;
-}
-
-int
-dns_encode_hostname(const char *host, char *buffer, int size)
-{
-       char *h;
-       char *p;
-       char *word;
-       int left;
-
-       h = strdup(host);
-       memset(buffer, 0, size);
-       p = buffer;
-       left = size;
-       
-       word = strtok(h, ".");
-       while(word) {
-               if (strlen(word) > 63 || strlen(word) > left) {
-                       return -1;
-               }
-               left -= (strlen(word) + 1);
-               *p++ = (char)strlen(word);
-               memcpy(p, word, strlen(word));
-               p += strlen(word);
-
-               word = strtok(NULL, ".");
-       }
-
-       *p++ = 0;
-
-       free(h);
-
-       return p - buffer;
-}
-
-void
-dnsd_send(int fd, struct query *q, char *data, int datalen)
-{
-       int len;
-       char *p;
-       char buf[64*1024];
-       short name;
-       HEADER *header;
-
-       memset(buf, 0, sizeof(buf));
-
-       len = 0;
-       header = (HEADER*)buf;  
-
-       header->id = htons(q->id);
-       header->qr = 1;
-       header->opcode = 0;
-       header->aa = 1;
-       header->tc = 0;
-       header->rd = 0;
-       header->ra = 0;
-
-       header->qdcount = htons(1);
-       header->ancount = htons(1);
-
-       p = buf + sizeof(HEADER);
-       
-       name = 0xc000 | ((p - buf) & 0x3fff);
-       p += dns_encode_hostname(q->name, p, strlen(q->name));
-       putshort(&p, q->type);
-       putshort(&p, C_IN);
-
-       putshort(&p, name);     
-       putshort(&p, q->type);
-       putshort(&p, C_IN);
-       putlong(&p, 0);
-
-       q->id = 0;
-
-       putshort(&p, datalen);
-       putdata(&p, data, datalen);
-
-       len = p - buf;
-       sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
-}
-
-static int
-decodepacket(const char *name, char *buf, int buflen)
-{
-       int len;
-       char *domain;
-
-       domain = strstr(name, topdomain);
-
-       len = decode_data(buf, buflen, name, domain);
-       if (len == buflen)
-               return -1; 
-       return len;
-}
-
-int
-dnsd_read(int fd, struct query *q, char *buf, int buflen)
-{
-       int r;
-       int rv;
-       short id;
-       short type;
-       short class;
-       short qdcount;
-       char *data;
-       char name[257];
-       HEADER *header;
-       socklen_t addrlen;
-       char packet[64*1024];
-       struct sockaddr_in from;
-
-       addrlen = sizeof(struct sockaddr);
-       r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
-
-       if (r >= sizeof(HEADER)) {
-               header = (HEADER*)packet;
-
-               id = ntohs(header->id);
-
-               data = packet + sizeof(HEADER);
-
-               if(!header->qr) {
-                       qdcount = ntohs(header->qdcount);
-
-                       if(qdcount == 1) {
-                               readname(packet, r, &data, name, sizeof(name) -1);
-                               name[256] = 0;
-                               readshort(packet, &data, &type);
-                               readshort(packet, &data, &class);
-
-                               strncpy(q->name, name, 257);
-                               q->type = type;
-                               q->id = id;
-                               q->fromlen = addrlen;
-                               memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
-
-                               rv = decodepacket(name, buf, buflen);
-                       }
-               }
-       } else if (r < 0) {     // Error
-               perror("recvfrom");
-               rv = 0;
-       } else {                // Packet too small to be dns protocol
-               rv = 0;
-       }
-
-       return rv;
-}
diff --git a/dns.h b/dns.h
deleted file mode 100644 (file)
index f8da628..0000000
--- a/dns.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _DNS_H_
-#define _DNS_H_
-
-int open_dns(const char *, int, in_addr_t);
-int dns_settarget(const char*);
-void close_dns(int);
-
-int dns_sending();
-void dns_handle_tun(int, char *, int);
-void dns_ping(int);
-void dns_handshake(int);
-int dns_read(int, char *, int);
-int dns_encode_hostname(const char *, char *, int);
-
-extern struct sockaddr_in peer;
-
-int dnsd_read(int, struct query*, char *, int);
-void dnsd_send(int, struct query*, char *, int);
-
-int dnsd_haspacket();
-int dnsd_hasack();
-void dnsd_forceack(int);
-void dnsd_queuepacket(const char *, const int);
-
-int dns_parse_reply(char *, int, char *, int);
-
-
-#endif /* _DNS_H_ */
diff --git a/encoding.c b/encoding.c
deleted file mode 100644 (file)
index 17092b0..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <strings.h>
-#include <string.h>
-
-// For FreeBSD
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-
-#define SPACING 63
-#define ENC_CHUNK 8
-#define RAW_CHUNK 5
-
-static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-";
-static const char padder[] = " 1234";
-static char reverse32[128];
-static int reverse_init = 0;
-
-/* Eat 5 bytes from src, write 8 bytes to dest */
-static void
-encode_chunk(char *dest, char *src)
-{
-       unsigned char c;
-
-       *dest++ = base32[(*src & 0xF8) >> 3];   // 1111 1000 first byte
-
-       c = (*src++ & 0x07) << 2;               // 0000 0111 first byte
-       c |=  ((*src & 0xC0) >> 6);             // 1100 0000 second byte
-       *dest++ = base32[(int) c];
-
-       *dest++ = base32[(*src & 0x3E) >> 1];   // 0011 1110 second byte
-
-       c = (*src++ & 0x01) << 4;               // 0000 0001 second byte
-       c |=  ((*src & 0xF0) >> 4);             // 1111 0000 third byte
-       *dest++ = base32[(int) c];
-       
-       c = (*src++ & 0x0F) << 1;               // 0000 1111 third byte
-       c |=  ((*src & 0x80) >> 7);             // 1000 0000 fourth byte
-       *dest++ = base32[(int) c];
-       
-       *dest++ = base32[(*src & 0x7C) >> 2];   // 0111 1100 fourth byte
-
-       c = (*src++ & 0x03) << 3;               // 0000 0011 fourth byte
-       c |=  ((*src & 0xE0) >> 5);             // 1110 0000 fifth byte
-       *dest++ = base32[(int) c];
-
-       *dest++ = base32[*src++ & 0x1F];        // 0001 1111 fifth byte
-}
-
-/* Eat 8 bytes from src, write 5 bytes to dest */
-static void
-decode_chunk(char *dest, char *src)
-{
-       unsigned char c;
-       int i;
-
-       if (!reverse_init) {
-               for (i = 0; i < 32; i++) {
-                       c = base32[i];
-                       reverse32[(int) c] = i;
-               }
-               reverse_init = 1;
-       }
-
-       c = reverse32[(int) *src++] << 3;               // Take bits 11111 from byte 1
-       c |= (reverse32[(int) *src] & 0x1C) >> 2;       // Take bits 11100 from byte 2
-       *dest++ = c;
-       
-       c = (reverse32[(int) *src++] & 0x3) << 6;       // Take bits 00011 from byte 2
-       c |= reverse32[(int) *src++] << 1;              // Take bits 11111 from byte 3
-       c |= (reverse32[(int) *src] & 0x10) >> 4;       // Take bits 10000 from byte 4
-       *dest++ = c;
-       
-       c = (reverse32[(int) *src++] & 0xF) << 4;       // Take bits 01111 from byte 4
-       c |= (reverse32[(int) *src] & 0x1E) >> 1;       // Take bits 11110 from byte 5
-       *dest++ = c;
-       
-       c = reverse32[(int) *src++] << 7;               // Take bits 00001 from byte 5
-       c |= reverse32[(int) *src++] << 2;              // Take bits 11111 from byte 6
-       c |= (reverse32[(int) *src] & 0x18) >> 3;       // Take bits 11000 from byte 7
-       *dest++ = c;
-       
-       c = (reverse32[(int) *src++] & 0x7) << 5;       // Take bits 00111 from byte 7
-       c |= reverse32[(int) *src++];                   // Take bits 11111 from byte 8
-       *dest++ = c;
-}
-
-int
-encode_data(char *buf, int len, int space, char *dest, char flag)
-{
-       int final;
-       int write;
-       int realwrite;
-       int chunks;
-       int leftovers;
-       int i;
-       char encoded[255];
-       char padding[5];
-       char *pp;
-       char *dp;
-       char *ep;
-
-       space -= space / SPACING;
-       chunks = (space - 1) / ENC_CHUNK;
-       while ((chunks + 1) * ENC_CHUNK + 1 > space) {
-               chunks--;
-       }
-       write = RAW_CHUNK * chunks;
-       write = MIN(write, len); // do not use more bytes than is available;
-       final = (write == len); // is this the last block?
-       chunks = write / RAW_CHUNK;
-       leftovers = write % RAW_CHUNK;
-
-       // flag is special character to be placed first in the encoded data
-       if (flag != 0) {
-               *dest = flag;
-       } else {
-               // First byte is 0 for middle packet and 1 for last packet
-               *dest = '0' + final;
-       }
-       dest++;
-
-       memset(encoded, 0, sizeof(encoded));
-       ep = encoded;
-       dp = buf;
-       for (i = 0; i < chunks; i++) {
-               encode_chunk(ep, dp);
-               ep += ENC_CHUNK;
-               dp += RAW_CHUNK;
-       }
-       realwrite = ENC_CHUNK * chunks;
-       memset(padding, 0, sizeof(padding));
-       pp = padding;
-       if (leftovers) {
-               pp += RAW_CHUNK - leftovers;
-               memcpy(pp, dp, leftovers);
-
-               pp = padding;
-               *ep++ = padder[leftovers];
-               encode_chunk(ep, pp);
-               
-               realwrite += ENC_CHUNK + 1;     // plus padding character
-       }
-       ep = encoded;
-       if (len > 0) {
-               for (i = 1; i <= realwrite; i++) {
-                       if (i % SPACING == 0) {
-                               *dest++ = '.';
-                       }
-                       *dest++ = *ep++;
-               }
-       }
-       
-       return write;
-}
-
-int
-decode_data(char *dest, int size, const char *src, char *srcend)
-{
-       int len;
-       int i;
-       int chunks;
-       int padded;
-       char encoded[255];
-       char padding[5];
-       char *pp;
-       char *ep;
-
-       // Copy flag
-       len = 1;
-       *dest = *src;
-       dest++;
-       src++;
-
-       memset(encoded, 0, sizeof(encoded));
-       ep = encoded;
-       while(len < size && src < srcend) {
-               if(*src == '.') {
-                       src++;
-                       continue;
-               }
-
-               *ep++ = *src++;
-       }
-       chunks = strlen(encoded) / 8;
-       padded = strlen(encoded) % 8;
-
-       ep = encoded;
-       for (i = 0; i < chunks-1; i++) {
-               decode_chunk(dest, ep);
-               dest += RAW_CHUNK;
-               ep += ENC_CHUNK;
-               len += RAW_CHUNK;
-       }
-       // Read last chunk:
-       if (padded) {
-               pp = padding;
-               padded = *ep++ - '0';
-               decode_chunk(pp, ep);
-               pp += RAW_CHUNK - padded;
-               memcpy(dest, pp, padded);
-               len += padded;
-       } else {
-               decode_chunk(dest, ep);
-               len += RAW_CHUNK;
-       }
-
-       return len;
-}
-
diff --git a/encoding.h b/encoding.h
deleted file mode 100644 (file)
index 3d1ef34..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _ENCODING_H_
-#define _ENCODING_H_
-
-int encode_data(char *, int, int, char *, char);
-int decode_data(char *, int, const char *, char *);
-
-#endif /* _ENCODING_H_ */
diff --git a/iodine.c b/iodine.c
deleted file mode 100644 (file)
index 8dddc32..0000000
--- a/iodine.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <err.h>
-#include <pwd.h>
-#include <arpa/inet.h>
-#include <zlib.h>
-
-#include "tun.h"
-#include "structs.h"
-#include "dns.h"
-
-#ifndef MAX
-#define MAX(a,b) ((a)>(b)?(a):(b))
-#endif
-       
-int running = 1;
-
-static void
-sighandler(int sig) {
-       running = 0;
-}
-
-static int
-tunnel(int tun_fd, int dns_fd)
-{
-       char out[64*1024];
-       char in[64*1024];
-       struct timeval tv;
-       long outlen;
-       fd_set fds;
-       int read;
-       int i;
-       int rv;
-
-       rv = 0;
-
-       while (running) {
-               tv.tv_sec = 1;
-               tv.tv_usec = 0;
-
-               FD_ZERO(&fds);
-               if (!dns_sending()) 
-                       FD_SET(tun_fd, &fds);
-               FD_SET(dns_fd, &fds);
-
-               i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
-
-               if (!running) {
-                       rv = 1;
-                       break;
-               }
-               
-               if(i < 0) {
-                       warn("select");
-                       rv = 1;
-                       break;
-               } else if (i > 0) {
-                       if(FD_ISSET(tun_fd, &fds)) {
-                               read = read_tun(tun_fd, in, sizeof(in));
-                               if(read <= 0)
-                                       continue;
-
-                               outlen = sizeof(out);
-                               compress2(out, &outlen, in, read, 9);
-                               dns_handle_tun(dns_fd, out, outlen);
-                       }
-                       if(FD_ISSET(dns_fd, &fds)) {
-                               read = dns_read(dns_fd, in, sizeof(in));
-                               if (read <= 0) 
-                                       continue;
-
-                               outlen = sizeof(out);
-                               uncompress(out, &outlen, in, read);
-
-                               write_tun(tun_fd, out, outlen);
-                               if (!dns_sending()) 
-                                       dns_ping(dns_fd);
-                       } 
-               } else
-                       dns_ping(dns_fd);
-       }
-
-       return rv;
-}
-
-static int
-handshake(int dns_fd)
-{
-       struct timeval tv;
-       char server[65];
-       char client[65];
-       char in[4096];
-       int timeout;
-       fd_set fds;
-       int read;
-       int mtu;
-       int i;
-       int r;
-
-       timeout = 1;
-       
-       for (i=0; running && i<5 ;i++) {
-               tv.tv_sec = timeout++;
-               tv.tv_usec = 0;
-
-               dns_handshake(dns_fd);
-               
-               FD_ZERO(&fds);
-               FD_SET(dns_fd, &fds);
-
-               r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
-
-               if(r > 0) {
-                       read = dns_read(dns_fd, in, sizeof(in));
-                       
-                       if(read < 0) {
-                               perror("read");
-                               continue;
-                       }
-
-                       if (read > 0) {
-                               if (sscanf(in, "%64[^-]-%64[^-]-%d", 
-                                       server, client, &mtu) == 3) {
-                                       
-                                       server[64] = 0;
-                                       client[64] = 0;
-                                       if (tun_setip(client) == 0 && 
-                                               tun_setmtu(mtu) == 0) {
-
-                                               return 0;
-                                       } else {
-                                               warn("Received handshake with bad data");
-                                       }
-                               } else {
-                                       printf("Received bad handshake\n");
-                               }
-                       }
-               }
-
-               printf("Retrying...\n");
-       }
-
-       return 1;
-}
-
-static void
-usage() {
-       extern char *__progname;
-
-       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
-                       "nameserver topdomain\n", __progname);
-       exit(2);
-}
-
-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] "
-                       "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("nameserver is the IP number of the relaying nameserver\n");
-       printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
-       exit(0);
-}
-
-static void
-version() {
-       printf("iodine IP over DNS tunneling client\n");
-       printf("version: 0.3.4 from 2006-11-08\n");
-       exit(0);
-}
-
-int
-main(int argc, char **argv)
-{
-       struct passwd *pw;
-       char *username;
-       int foreground;
-       char *newroot;
-       char *device;
-       int choice;
-       int tun_fd;
-       int dns_fd;
-
-       username = NULL;
-       foreground = 0;
-       newroot = NULL;
-       device = NULL;
-       
-       while ((choice = getopt(argc, argv, "vfhu:t:d:")) != -1) {
-               switch(choice) {
-               case 'v':
-                       version();
-                       break;
-               case 'f':
-                       foreground = 1;
-                       break;
-               case 'h':
-                       help();
-                       break;
-               case 'u':
-                       username = optarg;
-                       break;
-               case 't':
-                       newroot = optarg;
-                       break;
-               case 'd':
-                       device = optarg;
-                       break;
-               default:
-                       usage();
-                       break;
-               }
-       }
-       
-       if (geteuid() != 0) {
-               printf("Run as root and you'll be happy.\n");
-               usage();
-       }
-
-       argc -= optind;
-       argv += optind;
-       
-       if (argc != 2) 
-               usage();
-       
-       if(username) {
-               pw = getpwnam(username);
-               if (!pw) {
-                       printf("User %s does not exist!\n", username);
-                       usage();
-               }
-       }
-
-       if ((tun_fd = open_tun(device)) == -1)
-               goto cleanup1;
-       if ((dns_fd = open_dns(argv[1], 0, INADDR_ANY)) == -1)
-               goto cleanup2;
-       if (dns_settarget(argv[0]) == -1)
-               goto cleanup2;
-
-       printf("Sending queries for %s to %s\n", argv[1], argv[0]);
-
-       signal(SIGINT, sighandler);
-       signal(SIGTERM, sighandler);
-
-       if(handshake(dns_fd))
-               goto cleanup2;
-
-       if (newroot) {
-               if (chroot(newroot) != 0 || chdir("/") != 0)
-                       err(1, "%s", newroot);
-               seteuid(geteuid());
-               setuid(getuid());
-       }
-       
-       if (!foreground) {
-               printf("Detaching from terminal...\n");
-               daemon(0, 0);
-               umask(0);
-               alarm(0);
-       }
-       
-       if (username) {
-               if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
-                       printf("Could not switch to user %s!\n", username);
-                       usage();
-               }
-       }
-
-       tunnel(tun_fd, dns_fd);
-
-cleanup2:
-       close_dns(dns_fd);
-       close_tun(tun_fd);
-cleanup1:
-
-       return 0;
-}
diff --git a/iodined.c b/iodined.c
deleted file mode 100644 (file)
index 9321a53..0000000
--- a/iodined.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <err.h>
-#include <pwd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <zlib.h>
-
-#include "tun.h"
-#include "structs.h"
-#include "dns.h"
-
-#ifndef MAX
-#define MAX(a,b) ((a)>(b)?(a):(b))
-#endif
-
-int running = 1;
-
-struct packet packetbuf;
-struct packet outpacket;
-int outid;
-
-struct query q;
-
-int my_mtu;
-in_addr_t my_ip;
-
-static void
-sigint(int sig) {
-       running = 0;
-}
-
-static int
-tunnel(int tun_fd, int dns_fd)
-{
-       struct in_addr clientip;
-       struct in_addr myip;
-       struct timeval tv;
-       char out[64*1024];
-       char in[64*1024];
-       char *tmp[2];
-       long outlen;
-       fd_set fds;
-       int read;
-       int code;
-       int i;
-
-       while (running) {
-               if (q.id != 0) {
-                       tv.tv_sec = 0;
-                       tv.tv_usec = 5000;
-               } else {
-                       tv.tv_sec = 1;
-                       tv.tv_usec = 0;
-               }
-
-               FD_ZERO(&fds);
-               if(outpacket.len == 0)
-                       FD_SET(tun_fd, &fds);
-               FD_SET(dns_fd, &fds);
-
-               i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
-               
-               if(i < 0) {
-                       if (running) 
-                               warn("select");
-                       return 1;
-               }
-       
-               if (i==0) {     
-                       if (q.id != 0) {
-                               dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
-                               outpacket.len = 0;
-                               q.id = 0;
-                       }
-               } else {
-                       if(FD_ISSET(tun_fd, &fds)) {
-                               read = read_tun(tun_fd, in, sizeof(in));
-                               if (read <= 0)
-                                       continue;
-                               
-                               outlen = sizeof(out);
-                               compress2(out, &outlen, in, read, 9);
-                               memcpy(outpacket.data, out, outlen);
-                               outpacket.len = outlen;
-                       }
-                       if(FD_ISSET(dns_fd, &fds)) {
-                               read = dnsd_read(dns_fd, &q, in, sizeof(in));
-                               if (read <= 0)
-                                       continue;
-
-                               if(in[0] == 'H' || in[0] == 'h') {
-                                       myip.s_addr = my_ip;    
-                                       clientip.s_addr = my_ip + inet_addr("0.0.0.1");
-
-                                       tmp[0] = strdup(inet_ntoa(myip));
-                                       tmp[1] = strdup(inet_ntoa(clientip));
-                                       
-                                       read = snprintf(out, sizeof(out), "%s-%s-%d", 
-                                                       tmp[0], tmp[1], my_mtu);
-
-                                       dnsd_send(dns_fd, &q, out, read);
-                                       q.id = 0;
-
-                                       free(tmp[1]);
-                                       free(tmp[0]);
-                               } else if((in[0] >= '0' && in[0] <= '9')
-                                               || (in[0] >= 'a' && in[0] <= 'f')
-                                               || (in[0] >= 'A' && in[0] <= 'F')) {
-                                       if ((in[0] >= '0' && in[0] <= '9'))
-                                               code = in[0] - '0';
-                                       if ((in[0] >= 'a' && in[0] <= 'f'))
-                                               code = in[0] - 'a' + 10;
-                                       if ((in[0] >= 'A' && in[0] <= 'F'))
-                                               code = in[0] - 'A' + 10;
-
-                                       memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1);
-                                       packetbuf.len += read - 1;
-                                       packetbuf.offset += read - 1;
-
-                                       if (code & 1) {
-                                               outlen = sizeof(out);
-                                               uncompress(out, &outlen, packetbuf.data, packetbuf.len);
-
-                                               write_tun(tun_fd, out, outlen);
-
-                                               packetbuf.len = packetbuf.offset = 0;
-                                       }
-                               }
-                               if (outpacket.len > 0) {
-                                       dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
-                                       outpacket.len = 0;
-                                       q.id = 0;
-                               }
-                       } 
-               }
-       }
-
-       return 0;
-}
-
-static void
-usage() {
-       extern char *__progname;
-
-       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
-                       " tunnel_ip topdomain\n", __progname);
-       exit(2);
-}
-
-static void
-help() {
-       extern char *__progname;
-
-       printf("iodine IP over DNS tunneling server\n");
-       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
-                  " tunnel_ip 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("  -m mtu to set tunnel device mtu\n");
-       printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
-       printf("  -p port to listen on for incoming dns traffic (default 53)\n");
-       printf("tunnel_ip is the IP number of the local tunnel interface.\n");
-       printf("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.3.4 from 2006-11-08\n");
-       exit(0);
-}
-
-int
-main(int argc, char **argv)
-{
-       int choice;
-       int tun_fd;
-       int dnsd_fd;
-       char *newroot;
-       char *username;
-       char *device;
-       int foreground;
-       int mtu;
-       struct passwd *pw;
-       in_addr_t listen_ip;
-       int port;
-
-       username = NULL;
-       newroot = NULL;
-       device = NULL;
-       foreground = 0;
-       mtu = 1024;
-       listen_ip = INADDR_ANY;
-       port = 53;
-
-       packetbuf.len = 0;
-       packetbuf.offset = 0;
-       outpacket.len = 0;
-       q.id = 0;
-       
-       while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:")) != -1) {
-               switch(choice) {
-               case 'v':
-                       version();
-                       break;
-               case 'f':
-                       foreground = 1;
-                       break;
-               case 'h':
-                       help();
-                       break;
-               case 'u':
-                       username = optarg;
-                       break;
-               case 't':
-                       newroot = optarg;
-                       break;
-               case 'd':
-                       device = optarg;
-                       break;
-               case 'm':
-                       mtu = atoi(optarg);
-                       break;
-               case 'l':
-                       listen_ip = inet_addr(optarg);
-                       break;
-               case 'p':
-                       port = atoi(optarg);
-                       break;
-               default:
-                       usage();
-                       break;
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       
-       if (geteuid() != 0) {
-               printf("Run as root and you'll be happy.\n");
-               usage();
-       }
-
-       if (argc != 2) 
-               usage();
-
-       if (username) {
-               pw = getpwnam(username);
-               if (!pw) {
-                       printf("User %s does not exist!\n", username);
-                       usage();
-               }
-       }
-
-       if (mtu == 0) {
-               printf("Bad MTU given.\n");
-               usage();
-       }
-
-       if (listen_ip == INADDR_NONE) {
-               printf("Bad IP address to listen on.\n");
-               usage();
-       }
-
-       if ((tun_fd = open_tun(device)) == -1)
-               goto cleanup0;
-       if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
-               goto cleanup1;
-       if ((dnsd_fd = open_dns(argv[1], port, listen_ip)) == -1) 
-               goto cleanup2;
-
-       my_ip = inet_addr(argv[0]);
-       my_mtu = mtu;
-
-       printf("Listening to dns for domain %s\n", argv[1]);
-
-       if (newroot) {
-               if (chroot(newroot) != 0 || chdir("/") != 0)
-                       err(1, "%s", newroot);
-               seteuid(geteuid());
-               setuid(getuid());
-       }
-       
-       if (!foreground) {
-               printf("Detaching from terminal...\n");
-               daemon(0, 0);
-               umask(0);
-               alarm(0);
-       }
-
-       signal(SIGINT, sigint);
-       if (username) {
-               if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
-                       printf("Could not switch to user %s!\n", username);
-                       usage();
-               }
-       }
-       
-       tunnel(tun_fd, dnsd_fd);
-
-cleanup2:
-       close_dns(dnsd_fd);
-cleanup1:
-       close_tun(tun_fd);      
-cleanup0:
-
-       return 0;
-}
diff --git a/man/iodine.8 b/man/iodine.8
new file mode 100644 (file)
index 0000000..69921c7
--- /dev/null
@@ -0,0 +1,185 @@
+.\" groff -man -Tascii iodine.8
+.TH IODINE 8 "FEB 2007" "User Manuals"
+.SH NAME
+iodine, iodined \- tunnel IPv4 over DNS
+.SH SYNOPSIS
+.B iodine [-v]
+
+.B iodine [-h]
+
+.B iodine [-f] [-u
+.I user
+.B ] [-P
+.I password
+.B ] [-t
+.I chrootdir
+.B ] [-d
+.I device
+.B ]
+.I nameserver
+.I topdomain
+
+.B iodined [-v]
+
+.B iodined [-h]
+
+.B iodined [-f] [-u
+.I user
+.B ] [-P
+.I password
+.B ] [-t
+.I chrootdir
+.B ] [-m
+.I mtu
+.B ] [-l
+.I listen_ip
+.B ] [-d
+.I device
+.B ]
+.I tunnel_ip
+.I topdomain
+.SH DESCRIPTION
+.B iodine
+lets you tunnel IPv4 data through a DNS 
+server. This can be useful in situations where Internet access is firewalled,
+but DNS queries are allowed. It needs a TUN/TAP device to operate. The 
+bandwidth is asymmetrical with limited upstream and up to 1 Mbit/s downstream.
+.B iodine
+is the client application,
+.B iodined
+is the server.
+.SH OPTIONS
+.SS Common Options:
+.TP
+.B -v
+Print version info and exit.
+.TP
+.B -h
+Print usage info and exit.
+.TP
+.B -f
+Keep running in foreground.
+.TP
+.B -u user
+Drop privileges and run as user 'user' after setting up tunnel.
+.TP
+.B -t chrootdir
+Chroot to 'chrootdir' after setting up tunnel.
+.TP
+.B -P password
+Use 'password' to authenticate. If not used, 
+.B stdin
+will be used as input. Only the first 32 characters will be used.
+.TP
+.B -d device
+Use the TUN device 'device' instead of the normal one, which is dnsX on Linux
+and otherwise tunX.
+.SS Server Options:
+.TP
+.B -m mtu
+Set 'mtu' as mtu size for the tunnel device. This will be sent to the client
+on connect, and the client will use the same mtu.
+.TP
+.B -l listen_ip
+Make the server listen only on 'listen_ip' instead of on 0.0.0.0 for incoming
+connections.
+.TP
+.B -p port
+Make the server listen on 'port' instead of 53 for traffic. 
+.B Note:
+You must make sure the dns requests are forwarded to this port yourself.
+.SS Client Arguments:
+.TP
+.B nameserver
+The nameserver to use to relay the dns traffic. This can be any relaying
+nameserver  or the ip number of the server running iodined if reachable.
+Normally, you should specify a nameserver from your 
+.I /etc/resolv.conf
+file.
+.TP
+.B topdomain
+The dns traffic will be sent as querys of type NULL for subdomains under
+\'topdomain'. This is normally a subdomain to a domain you own. Use a short
+domain name to get better throughput. If 
+.B nameserver
+is the iodined server, then the topdomain can be chosen freely. This argument
+must be the same on both the client and the server.
+.SS Server Arguments:
+.TP
+.B tunnel_ip
+This is the servers ip address on the tunnel interface. The client will be
+given the next ip number in the range. It is recommended to use the 
+10.0.0.0/8 or 172.16.0.0/12 ranges.
+.TP
+.B topdomain
+The dns traffic will is expected to be sent as querys of type NULL for 
+subdomains under 'topdomain'. This is normally a subdomain to a domain you 
+own. Use a short domain name to get better throughput. This argument must be 
+the same on both the client and the server.
+.SH EXAMPLES
+.SS Quickstart:
+.TP
+Try it out within your own LAN! Follow these simple steps:
+.TP
+- On your server, run: ./iodined -f 10.0.0.1 test.asdf
+(If you already use the 10.0.0.0 network, use another internal net like 
+172.16.0.0)
+.TP
+- Enter a password
+.TP
+- On the client, run: ./iodine -f 192.168.0.1 test.asdf
+(Replace 192.168.0.1 with the server's ip address)
+.TP
+- Enter the same password
+.TP
+- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
+.TP
+- Try pinging each other through the tunnel
+.TP
+- Done! :)
+.TP
+To actually use it through a relaying nameserver, see below.
+.SS Full setup:
+
+.TP
+.B Server side:
+To use this tunnel, you need control over a real domain (like mytunnel.com),
+and a server with a static public IP number that does not yet run a DNS
+server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server.
+If you use BIND for the domain, add these lines to the zone file (replace
+10.15.213.99 with your server ip):
+
+.nf
+tunnel1host    IN      A       10.15.213.99
+tunnel1                IN      NS      tunnel1host.mytunnel.com.
+.fi
+
+Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
+to your server. Start iodined on the server. The first argument is the tunnel
+IP address (like 192.168.99.1) and the second is the assigned domain (in this
+case tunnel1.mytunnel.com). The -f argument will keep iodined running in the
+foreground, which helps when testing. iodined will start a virtual interface,
+and also start listening for DNS queries on UDP port 53. Either enter a
+password on the commandline (-P pass) or after the server has started. Now 
+everything is ready for the client.
+.TP
+.B Client side: 
+All the setup is done, just start iodine. It also takes two
+arguments, the first is the local relaying DNS server and the second is the
+domain used (tunnel1.mytunnnel.com). If DNS queries are allowed to any
+computer, you can use the tunnel endpoint (example: 10.15.213.99 or
+tunnel1host.mytunnel.com) as the first argument. The tunnel interface will get
+an IP close to the servers (in this case 192.168.99.2) and a suitable MTU. 
+Enter the same password as on the server either by argument or after the client
+has started. Now you should be able to ping the other end of the tunnel from 
+either side.  
+.TP
+.B Routing:
+The normal case is to route all traffic through the DNS tunnel. To do this, first
+add a route to the nameserver you use with the default gateway as gateway. Then
+replace the default gateway with the servers IP address within the DNS tunnel,
+and configure the server to do NAT.
+.SH BUGS
+File bugs at http://dev.kryo.se/iodine/
+.SH AUTHORS
+Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>
diff --git a/read.c b/read.c
deleted file mode 100644 (file)
index 1e40dba..0000000
--- a/read.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <string.h>
-#include <stdint.h>
-
-static int
-readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
-{
-       char *dummy;
-       char *s;
-       char *d;
-       int len;
-       int offset;
-       char c;
-
-       if (loop <= 0)
-               return 0;
-
-       len = 0;
-       s = *src;
-       d = dst;
-       while(*s && len < length - 2) {
-               c = *s++;
-
-               /* is this a compressed label? */
-               if((c & 0xc0) == 0xc0) {
-                       offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
-                       if (offset > packetlen) {
-                               if (len == 0) {
-                                       // Bad jump first in packet
-                                       return 0;
-                               } else {
-                                       // Bad jump after some data
-                                       break;
-                               }
-                       }
-                       dummy = packet + offset;
-                       len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
-                       goto end;
-               }
-
-               while(c && len < length - 1) {
-                       *d++ = *s++;
-                       len++;
-
-                       c--;
-               }
-               
-               if (len >= length - 1) {
-                       break; /* We used up all space */
-               }
-
-               if (*s != 0) {
-                       *d++ = '.';
-                       len++;
-               }
-       }
-       dst[len++] = '\0';
-
-end:
-       (*src) = s+1;
-       return len;
-}
-
-int
-readname(char *packet, int packetlen, char **src, char *dst, size_t length)
-{
-       return readname_loop(packet, packetlen, src, dst, length, 10);
-}
-
-int
-readshort(char *packet, char **src, short *dst)
-{
-       unsigned char *p;
-
-       p = *src;
-       *dst = (p[0] << 8) | p[1];
-
-       (*src) += sizeof(short);
-       return sizeof(short);
-}
-
-int
-readlong(char *packet, char **src, uint32_t *dst)
-{
-       // A long as described in dns protocol is always 32 bits
-       unsigned char *p;
-
-       p = *src;
-
-       *dst = ((uint32_t)p[0] << 24) 
-                | ((uint32_t)p[1] << 16) 
-                | ((uint32_t)p[2] << 8)
-                | ((uint32_t)p[3]);
-
-       (*src) += sizeof(uint32_t);
-       return sizeof(uint32_t);
-}
-
-int
-readdata(char *packet, char **src, char *dst, size_t len)
-{
-       if (len < 0)
-               return 0;
-
-       memcpy(dst, *src, len);
-
-       (*src) += len;
-
-       return len;
-}
-
-int
-putbyte(char **dst, char value)
-{
-       **dst = value;
-       (*dst)++;
-
-       return sizeof(char);
-}
-
-int
-putshort(char **dst, short value)
-{
-       unsigned char *p;
-
-       p = *dst;
-
-       *p++ = (value >> 8);
-       *p++ = value;
-
-       (*dst) = p;
-       return sizeof(short);
-}
-
-int
-putlong(char **dst, uint32_t value)
-{
-       // A long as described in dns protocol is always 32 bits
-       unsigned char *p;
-
-       p = *dst;
-
-       *p++ = (value >> 24);
-       *p++ = (value >> 16);
-       *p++ = (value >> 8);
-       *p++ = (value);
-
-       (*dst) = p;
-       return sizeof(uint32_t);
-}
-
-int
-putdata(char **dst, char *data, size_t len)
-{
-       if (len < 0)
-               return 0;
-
-       memcpy(*dst, data, len);
-       
-       (*dst) += len;
-       return len;
-}
-
diff --git a/read.h b/read.h
deleted file mode 100644 (file)
index d695a7e..0000000
--- a/read.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _READ_H_
-#define _READ_H_
-
-int readname(char *, int, char **, char *, size_t);
-int readshort(char *, char **, short *);
-int readlong(char *, char **, uint32_t *);
-int readdata(char *, char **, char *, size_t);
-
-int putbyte(char **, char);
-int putshort(char **, short);
-int putlong(char **, uint32_t);
-int putdata(char **, char *, size_t);
-
-#endif
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..ebf27e9
--- /dev/null
@@ -0,0 +1,35 @@
+CC = gcc
+CLIENT = ../bin/iodine
+CLIENTOBJS = iodine.o tun.o dns.o read.o encoding.o login.o base32.o md5.o common.o
+SERVER = ../bin/iodined
+SERVEROBJS = iodined.o tun.o dns.o read.o encoding.o login.o base32.o md5.o common.o user.o
+
+OS = `uname | tr "a-z" "A-Z"`
+ARCH = `uname -m`
+
+LDFLAGS =  -lz
+CFLAGS = -c -g -Wall -D$(OS) -pedantic
+
+all: stateos $(CLIENT) $(SERVER) $(TESTSUITE) 
+
+stateos:
+       @echo OS is $(OS), arch is $(ARCH)
+
+$(CLIENT): $(CLIENTOBJS)
+       @echo LD $@
+       @mkdir -p ../bin
+       @$(CC) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
+
+$(SERVER): $(SERVEROBJS)
+       @echo LD $@
+       @mkdir -p ../bin
+       @$(CC) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
+
+.c.o: 
+       @echo CC $<
+       @$(CC) $(CFLAGS) $< -o $@
+
+clean:
+       @echo "Cleaning src/"
+       @rm -f $(CLIENT) $(SERVER) *~ *.o *.core
+
diff --git a/src/base32.c b/src/base32.c
new file mode 100644 (file)
index 0000000..7357604
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base32.h"
+
+static const char cb32[] = 
+       "abcdefghijklmnopqrstuvwxyz0123456789";
+
+int 
+base32_encode(char **buf, size_t *buflen, const void *data, size_t size)
+{
+       size_t newsize;
+       char *newbuf;
+       char *s;
+       char *p;
+       char *q;
+       int i;
+
+       newsize = 8 * (size / 5 + 1) + 1;
+       if (newsize > *buflen) {
+               if ((newbuf = realloc(*buf, newsize)) == NULL) {
+                       free(*buf);
+                       *buf = NULL;
+                       *buflen = 0;
+                       return 0;
+               }
+
+               *buf = newbuf;
+               *buflen = newsize;
+       }
+
+       p = s = *buf;
+       q = (char*)data;
+
+       for(i=0;i<size;i+=5) {
+               p[0] = cb32[(q[0] >> 3)];
+               p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)];
+               p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
+               p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
+               p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
+               p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0';
+               p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0';
+               p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
+               
+               q += 5;
+               p += 8;
+       }       
+       *p = 0;
+       return strlen(s);
+}
+
+#define DECODE_ERROR 0xffffffff
+
+static int
+pos(char c)
+{
+    const char *p;
+    for (p = cb32; *p; p++)
+               if (*p == c)
+                       return p - cb32;
+    return -1;
+}
+
+static int
+decode_token(const char *t, char *data) 
+{
+       int len;
+
+       len = strlen(t);
+
+       if (len < 2)
+               return 0;
+
+       data[0] = ((pos(t[0]) & 0x1f) << 3) | 
+                         ((pos(t[1]) & 0x1c) >> 2);
+       
+       if (len < 4)
+               return 1;
+
+       data[1] = ((pos(t[1]) & 0x03) << 6) | 
+                         ((pos(t[2]) & 0x1f) << 1) | 
+                         ((pos(t[3]) & 0x10) >> 4);
+
+       if (len < 5)
+               return 2;
+
+       data[2] = ((pos(t[3]) & 0x0f) << 4) |
+                         ((pos(t[4]) & 0x1e) >> 1);
+
+       if (len < 7)
+               return 3;
+
+       data[3] = ((pos(t[4]) & 0x01) << 7) |
+                         ((pos(t[5]) & 0x1f) << 2) |
+                         ((pos(t[6]) & 0x18) >> 3);
+
+       if (len < 8)
+               return 4;
+
+       data[4] = ((pos(t[6]) & 0x07) << 5) |
+                         ((pos(t[7]) & 0x1f));
+
+       return 5;
+}
+
+int
+base32_decode(void **buf, size_t *buflen, const char *str)
+{
+       unsigned char *q;
+       size_t newsize;
+       const char *p;
+       char *newbuf;
+       int len;
+       
+       newsize = 5 * (strlen(str) / 8 + 1) + 1;
+       if (newsize > *buflen) {
+               if ((newbuf = realloc(*buf, newsize)) == NULL) {
+                       free(*buf);
+                       *buf = NULL;
+                       *buflen = 0;
+                       return 0;
+               }
+
+               *buf = newbuf;
+               *buflen = newsize;
+       }
+
+       q = *buf;
+       for (p = str; *p && strchr(cb32, *p); p += 8) {
+               len = decode_token(p, (char *) q);      
+               q += len;
+               
+               if (len < 5)
+                       break;
+       }
+       *q = '\0';
+       
+       return q - (unsigned char *) *buf;
+}
+
diff --git a/src/base32.h b/src/base32.h
new file mode 100644 (file)
index 0000000..be3b7ea
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __BASE32_H__
+#define __BASE32_H__
+
+int base32_encode(char **, size_t *, const void *, size_t);
+int base32_decode(void **, size_t *, const char *);
+
+#endif
diff --git a/src/common.c b/src/common.c
new file mode 100644 (file)
index 0000000..521d2e6
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <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/stat.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "common.h"
+
+int 
+open_dns(int localport, in_addr_t listen_ip) 
+{
+       struct sockaddr_in addr;
+       int flag;
+       int fd;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(localport);
+       /* 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)
+               err(1, "socket");
+
+       flag = 1;
+#ifdef SO_REUSEPORT
+       setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
+#endif
+       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
+
+       if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
+               err(1, "bind");
+
+       printf("Opened UDP socket\n");
+
+       return fd;
+}
+
+void
+close_dns(int fd)
+{
+       close(fd);
+}
+
+void
+do_chroot(char *newroot)
+{
+       if (newroot) {
+               if (chroot(newroot) != 0 || chdir("/") != 0)
+                       err(1, "%s", newroot);
+
+               seteuid(geteuid());
+               setuid(getuid());
+       }
+}
+
+void
+do_detach()
+{
+       printf("Detaching from terminal...\n");
+       daemon(0, 0);
+       umask(0);
+       alarm(0);
+}
diff --git a/src/common.h b/src/common.h
new file mode 100644 (file)
index 0000000..40b80f1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+struct packet 
+{
+       int len;
+       int offset;
+       char data[64*1024];
+};
+
+struct query {
+       char name[258];
+       short type;
+       short id;
+       struct sockaddr from;
+       int fromlen;
+};
+
+int open_dns(int, in_addr_t);
+void close_dns(int);
+
+void do_chroot(char *);
+void do_detach();
+
+#endif
diff --git a/src/dns.c b/src/dns.c
new file mode 100644 (file)
index 0000000..f50ffc8
--- /dev/null
+++ b/src/dns.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <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 <stdint.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "dns.h"
+#include "encoding.h"
+#include "read.h"
+
+int
+dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
+{
+       HEADER *header;
+       short name;
+       char *p;
+       int len;
+
+       memset(buf, 0, buflen);
+       
+       header = (HEADER*)buf;
+       
+       header->id = htons(q->id);
+       header->qr = (qr == QR_ANSWER);
+       header->opcode = 0;
+       header->aa = (qr == QR_ANSWER);
+       header->tc = 0;
+       header->rd = (qr == QR_QUERY);
+       header->ra = 0;
+
+       p = buf + sizeof(HEADER);
+
+       switch (qr) {
+       case QR_ANSWER:
+               header->ancount = htons(1);
+               header->qdcount = htons(1);
+       
+               name = 0xc000 | ((p - buf) & 0x3fff);
+
+               putname(&p, 256, q->name);
+
+               putshort(&p, q->type);
+               putshort(&p, C_IN);
+
+               putshort(&p, name);     
+               putshort(&p, q->type);
+               putshort(&p, C_IN);
+               putlong(&p, 0);
+
+               putshort(&p, datalen);
+               putdata(&p, data, datalen);
+               break;
+       case QR_QUERY:
+               header->qdcount = htons(1);
+               header->arcount = htons(1);
+       
+               putname(&p, 256, data);
+
+               putshort(&p, q->type);
+               putshort(&p, C_IN);
+
+               /* EDNS0 */
+               putbyte(&p, 0x00);    /* Root */
+               putshort(&p, 0x0029); /* OPT */
+               putshort(&p, 0x1000); /* Payload size: 4096 */
+               putshort(&p, 0x0000); /* Higher bits/edns version */
+               putshort(&p, 0x8000); /* Z */
+               putshort(&p, 0x0000); /* Data length */
+               break;
+       }
+       
+       len = p - buf;
+
+       return len;
+}
+
+int
+dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
+{
+       char rdata[4*1024];
+       HEADER *header;
+       short qdcount;
+       short ancount;
+       char name[255];
+       uint32_t ttl;
+       short class;
+       short type;
+       char *data;
+       short rlen;
+       int id; 
+       int rv;
+
+       rv = 0;
+       header = (HEADER*)packet;
+
+       /* Reject short packets */
+       if (packetlen < sizeof(HEADER)) 
+               return 0;
+       
+       if (header->qr != qr) {
+               warnx("header->qr does not match the requested qr");
+               return -1;
+       }
+
+       data = packet + sizeof(HEADER);
+       qdcount = ntohs(header->qdcount);
+       ancount = ntohs(header->ancount);
+       
+       id = ntohs(header->id);
+               
+       rlen = 0;
+
+       switch (qr) {
+       case QR_ANSWER:
+               if(qdcount != 1 || ancount != 1) {
+                       warnx("no query or answer in answer");
+                       return -1;
+               }
+
+               if (q != NULL) 
+                       q->id = id;
+
+               readname(packet, packetlen, &data, name, sizeof(name));
+               readshort(packet, &data, &type);
+               readshort(packet, &data, &class);
+               
+               readname(packet, packetlen, &data, name, sizeof(name));
+               readshort(packet, &data, &type);
+               readshort(packet, &data, &class);
+               readlong(packet, &data, &ttl);
+               readshort(packet, &data, &rlen);
+               rv = MIN(rlen, sizeof(rdata));
+               rv = readdata(packet, &data, rdata, rv);
+
+               if(type == T_NULL && rv > 2) {
+                       rv = MIN(rv, buflen);
+                       memcpy(buf, rdata, rv);
+               }
+               break;
+       case QR_QUERY:
+               if (qdcount != 1) {
+                       warnx("no query on query");
+                       return -1;
+               }
+
+               readname(packet, packetlen, &data, name, sizeof(name) -1);
+               name[256] = 0;
+               readshort(packet, &data, &type);
+               readshort(packet, &data, &class);
+
+               if(type != T_NULL) {
+                       rv = 0;
+                       break;
+               }
+
+               strncpy(q->name, name, 257);
+               q->type = type;
+               q->id = id;
+
+               rv = strlen(q->name);
+               break;
+       }
+
+       return rv;
+}
+
+int
+dns_build_hostname(char *buf, size_t buflen, 
+                                  const char *data, const size_t datalen, 
+                                  const char *topdomain)
+{
+       int consumed;
+       int avail;
+       char *b;
+
+       avail = MIN(0xFF, buflen) - strlen(topdomain) - 2;
+       memset(buf, 0, buflen);
+       b = buf;
+       
+       consumed = encode_data(data, datalen, avail, b);
+
+       b += strlen(buf);
+       if (*b != '.') 
+               *b++ = '.';
+
+       strncpy(b, topdomain, strlen(topdomain)+1);
+       
+       return consumed;
+}
+
diff --git a/src/dns.h b/src/dns.h
new file mode 100644 (file)
index 0000000..5a96f22
--- /dev/null
+++ b/src/dns.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __DNS_H__
+#define __DNS_H__
+
+#include "common.h"
+
+typedef enum {
+       QR_QUERY = 0,
+       QR_ANSWER = 1
+} qr_t;
+
+int dns_build_hostname(char *, size_t, const char *, const size_t, const char *);
+
+int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
+int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
+
+#endif /* _DNS_H_ */
diff --git a/src/encoding.c b/src/encoding.c
new file mode 100644 (file)
index 0000000..4de10c6
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+
+/* For FreeBSD */
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#define SPACING 63
+#define ENC_CHUNK 8
+#define RAW_CHUNK 5
+
+static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-";
+static const char padder[] = " 1234";
+static char reverse32[128];
+static int reverse_init = 0;
+
+/* Eat 5 bytes from src, write 8 bytes to dest */
+static void
+encode_chunk(char *dest, const char *src)
+{
+       unsigned char c;
+
+       *dest++ = base32[(*src & 0xF8) >> 3];   /* 1111 1000 first byte */
+
+       c = (*src++ & 0x07) << 2;               /* 0000 0111 first byte */
+       c |=  ((*src & 0xC0) >> 6);             /* 1100 0000 second byte */
+       *dest++ = base32[(int) c];
+
+       *dest++ = base32[(*src & 0x3E) >> 1];   /* 0011 1110 second byte */
+
+       c = (*src++ & 0x01) << 4;               /* 0000 0001 second byte */
+       c |=  ((*src & 0xF0) >> 4);             /* 1111 0000 third byte */
+       *dest++ = base32[(int) c];
+       
+       c = (*src++ & 0x0F) << 1;               /* 0000 1111 third byte */
+       c |=  ((*src & 0x80) >> 7);             /* 1000 0000 fourth byte */
+       *dest++ = base32[(int) c];
+       
+       *dest++ = base32[(*src & 0x7C) >> 2];   /* 0111 1100 fourth byte */
+
+       c = (*src++ & 0x03) << 3;               /* 0000 0011 fourth byte */
+       c |=  ((*src & 0xE0) >> 5);             /* 1110 0000 fifth byte */
+       *dest++ = base32[(int) c];
+
+       *dest++ = base32[*src++ & 0x1F];        /* 0001 1111 fifth byte */
+}
+
+/* Eat 8 bytes from src, write 5 bytes to dest */
+static void
+decode_chunk(char *dest, char *src)
+{
+       unsigned char c;
+       int i;
+
+       if (!reverse_init) {
+               for (i = 0; i < 32; i++) {
+                       c = base32[i];
+                       reverse32[(int) c] = i;
+               }
+               reverse_init = 1;
+       }
+
+       c = reverse32[(int) *src++] << 3;               /* Take bits 11111 from byte 1 */
+       c |= (reverse32[(int) *src] & 0x1C) >> 2;       /* Take bits 11100 from byte 2 */
+       *dest++ = c;
+       
+       c = (reverse32[(int) *src++] & 0x3) << 6;       /* Take bits 00011 from byte 2 */
+       c |= reverse32[(int) *src++] << 1;              /* Take bits 11111 from byte 3 */
+       c |= (reverse32[(int) *src] & 0x10) >> 4;       /* Take bits 10000 from byte 4 */
+       *dest++ = c;
+       
+       c = (reverse32[(int) *src++] & 0xF) << 4;       /* Take bits 01111 from byte 4 */
+       c |= (reverse32[(int) *src] & 0x1E) >> 1;       /* Take bits 11110 from byte 5 */
+       *dest++ = c;
+       
+       c = reverse32[(int) *src++] << 7;               /* Take bits 00001 from byte 5 */
+       c |= reverse32[(int) *src++] << 2;              /* Take bits 11111 from byte 6 */
+       c |= (reverse32[(int) *src] & 0x18) >> 3;       /* Take bits 11000 from byte 7 */
+       *dest++ = c;
+       
+       c = (reverse32[(int) *src++] & 0x7) << 5;       /* Take bits 00111 from byte 7 */
+       c |= reverse32[(int) *src++];                   /* Take bits 11111 from byte 8 */
+       *dest++ = c;
+}
+
+int
+encode_data(const char *buf, const size_t len, int space, char *dest)
+{
+       int final;
+       int write;
+       int realwrite;
+       int chunks;
+       int leftovers;
+       int i;
+       char encoded[255];
+       char padding[5];
+       const char *dp;
+       char *pp;
+       char *ep;
+
+       space -= space / SPACING;
+       chunks = (space - 1) / ENC_CHUNK;
+       while ((chunks + 1) * ENC_CHUNK + 1 > space) {
+               chunks--;
+       }
+       write = RAW_CHUNK * chunks;
+       write = MIN(write, len); /* do not use more bytes than is available; */
+       final = (write == len); /* is this the last block? */
+       chunks = write / RAW_CHUNK;
+       leftovers = write % RAW_CHUNK;
+
+       memset(encoded, 0, sizeof(encoded));
+       ep = encoded;
+       dp = buf;
+       for (i = 0; i < chunks; i++) {
+               encode_chunk(ep, dp);
+               ep += ENC_CHUNK;
+               dp += RAW_CHUNK;
+       }
+       realwrite = ENC_CHUNK * chunks;
+       memset(padding, 0, sizeof(padding));
+       pp = padding;
+       if (leftovers) {
+               pp += RAW_CHUNK - leftovers;
+               memcpy(pp, dp, leftovers);
+
+               pp = padding;
+               *ep++ = padder[leftovers];
+               encode_chunk(ep, pp);
+               
+               realwrite += ENC_CHUNK + 1;     /* plus padding character */
+       }
+       ep = encoded;
+       if (len > 0) {
+               for (i = 1; i <= realwrite; i++) {
+                       if (i % SPACING == 0) {
+                               *dest++ = '.';
+                       }
+                       *dest++ = *ep++;
+               }
+       }
+       
+       return write;
+}
+
+int
+decode_data(char *dest, int size, const char *src, char *srcend)
+{
+       int len;
+       int i;
+       int chunks;
+       int padded;
+       char encoded[255];
+       char padding[5];
+       int enclen;
+       char *pp;
+       char *ep;
+
+       memset(encoded, 0, sizeof(encoded));
+       memset(dest, 0, size);
+
+       /* First byte is not encoded */
+       *dest++ = *src++;
+       len = 1;
+
+       ep = encoded;
+       enclen = 0;
+       while(enclen < sizeof(encoded) && src < srcend) {
+               if(*src == '.') {
+                       src++;
+                       continue;
+               }
+
+               *ep++ = *src++;
+               enclen++;
+       }
+       chunks = enclen / 8;
+       padded = enclen % 8;
+
+       ep = encoded;
+       for (i = 0; i < chunks-1; i++) {
+               decode_chunk(dest, ep);
+               dest += RAW_CHUNK;
+               ep += ENC_CHUNK;
+               len += RAW_CHUNK;
+       }
+       /* Read last chunk */
+       if (padded) {
+               pp = padding;
+               padded = *ep++ - '0';
+               decode_chunk(pp, ep);
+               pp += RAW_CHUNK - padded;
+               memcpy(dest, pp, padded);
+               len += padded;
+       } else {
+               decode_chunk(dest, ep);
+               len += RAW_CHUNK;
+       }
+
+       return len;
+}
+
diff --git a/src/encoding.h b/src/encoding.h
new file mode 100644 (file)
index 0000000..2e4351b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ENCODING_H_
+#define _ENCODING_H_
+
+int encode_data(const char *, const size_t, int, char *);
+int decode_data(char *, int, const char *, char *);
+
+#endif /* _ENCODING_H_ */
diff --git a/src/iodine.c b/src/iodine.c
new file mode 100644 (file)
index 0000000..a26281f
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <err.h>
+#include <pwd.h>
+#include <arpa/inet.h>
+#include <zlib.h>
+#include <arpa/nameser.h>
+#ifdef DARWIN
+#include <arpa/nameser8_compat.h>
+#endif
+
+#include "common.h"
+#include "dns.h"
+#include "login.h"
+#include "tun.h"
+#include "version.h"
+
+static void send_ping(int fd);
+static void send_chunk(int fd);
+
+int running = 1;
+char password[33];
+
+struct sockaddr_in peer;
+static char *topdomain;
+
+uint16_t rand_seed;
+
+/* Current IP packet */
+static char activepacket[4096];
+static char userid;
+static int lastlen;
+static int packetpos;
+static int packetlen;
+static uint16_t chunkid;
+
+static void
+sighandler(int sig) 
+{
+       running = 0;
+}
+
+static void
+send_packet(int fd, char cmd, const char *data, const size_t datalen)
+{
+       char packet[4096];
+       struct query q;
+       char buf[4096];
+       size_t len;
+
+       q.id = ++chunkid;
+       q.type = T_NULL;
+
+       buf[0] = cmd;
+       
+       len = dns_build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain);
+       len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
+
+       sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
+}
+
+int
+is_sending()
+{
+       return (packetlen != 0);
+}
+
+int
+read_dns(int fd, char *buf, int buflen)
+{
+       struct sockaddr_in from;
+       char packet[64*1024];
+       socklen_t addrlen;
+       struct query q;
+       int rv;
+       int r;
+
+       addrlen = sizeof(struct sockaddr);
+       if ((r = recvfrom(fd, packet, sizeof(packet), 0, 
+                                         (struct sockaddr*)&from, &addrlen)) == -1) {
+               warn("recvfrom");
+               return 0;
+       }
+
+       rv = dns_decode(buf, buflen, &q, QR_ANSWER, packet, r);
+
+       if (is_sending() && chunkid == q.id) {
+               /* Got ACK on sent packet */
+               packetpos += lastlen;
+               if (packetpos == packetlen) {
+                       /* Packet completed */
+                       packetpos = 0;
+                       packetlen = 0;
+                       lastlen = 0;
+               } else {
+                       /* More to send */
+                       send_chunk(fd);
+               }
+       }
+       return rv;
+}
+
+
+static int
+tunnel_tun(int tun_fd, int dns_fd)
+{
+       unsigned long outlen;
+       unsigned long inlen;
+       char out[64*1024];
+       char in[64*1024];
+       size_t read;
+
+       if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
+               return -1;
+
+       outlen = sizeof(out);
+       inlen = read;
+       compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
+
+       memcpy(activepacket, out, MIN(outlen, sizeof(activepacket)));
+       lastlen = 0;
+       packetpos = 0;
+       packetlen = outlen;
+
+       send_chunk(dns_fd);
+
+       return read;
+}
+
+static int
+tunnel_dns(int tun_fd, int dns_fd)
+{
+       unsigned long outlen;
+       unsigned long inlen;
+       char out[64*1024];
+       char in[64*1024];
+       size_t read;
+
+       if ((read = read_dns(dns_fd, in, sizeof(in))) <= 0) 
+               return -1;
+               
+       outlen = sizeof(out);
+       inlen = read;
+       if (uncompress((uint8_t*)out, &outlen, (uint8_t*)in, inlen) != Z_OK)
+               return -1;
+
+       write_tun(tun_fd, out, outlen);
+       if (!is_sending()) 
+               send_ping(dns_fd);
+       
+       return read;
+}
+
+static int
+tunnel(int tun_fd, int dns_fd)
+{
+       struct timeval tv;
+       fd_set fds;
+       int rv;
+       int i;
+
+       rv = 0;
+
+       while (running) {
+               tv.tv_sec = 1;
+               tv.tv_usec = 0;
+
+               FD_ZERO(&fds);
+               if (!is_sending()) 
+                       FD_SET(tun_fd, &fds);
+               FD_SET(dns_fd, &fds);
+
+               i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
+               
+               if (running == 0)
+                       break;
+
+               if (i < 0) 
+                       err(1, "select");
+
+               if (i == 0) /* timeout */
+                       send_ping(dns_fd);
+               else {
+                       if (FD_ISSET(tun_fd, &fds)) {
+                               if (tunnel_tun(tun_fd, dns_fd) <= 0)
+                                       continue;
+                       }
+                       if (FD_ISSET(dns_fd, &fds)) {
+                               if (tunnel_dns(tun_fd, dns_fd) <= 0)
+                                       continue;
+                       } 
+               }
+       }
+
+       return rv;
+}
+
+static void
+send_chunk(int fd)
+{
+       char hex[] = "0123456789ABCDEF";
+       char packet[4096];
+       struct query q;
+       char buf[4096];
+       int avail;
+       int code;
+       char *p;
+       int len;
+
+       q.id = ++chunkid;
+       q.type = T_NULL;
+
+       p = activepacket;
+       p += packetpos;
+       avail = packetlen - packetpos;
+
+       lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain);
+
+       if (lastlen == avail)
+               code = 1;
+       else
+               code = 0;
+               
+       code |= (userid << 1);
+       buf[0] = hex[code];
+       len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
+
+       sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
+}
+
+void
+send_login(int fd, char *login, int len)
+{
+       char data[19];
+
+       memset(data, 0, sizeof(data));
+       data[0] = userid;
+       memcpy(&data[1], login, MIN(len, 16));
+
+       data[17] = (rand_seed >> 8) & 0xff;
+       data[18] = (rand_seed >> 0) & 0xff;
+       
+       rand_seed++;
+
+       send_packet(fd, 'L', data, sizeof(data));
+}
+
+static void
+send_ping(int fd)
+{
+       char data[3];
+       
+       if (is_sending()) {
+               lastlen = 0;
+               packetpos = 0;
+               packetlen = 0;
+       }
+
+       data[0] = userid;
+       data[1] = (rand_seed >> 8) & 0xff;
+       data[2] = (rand_seed >> 0) & 0xff;
+       
+       rand_seed++;
+
+       send_packet(fd, 'P', data, sizeof(data));
+}
+
+void 
+send_version(int fd, uint32_t version)
+{
+       char data[6];
+
+       data[0] = (version >> 24) & 0xff;
+       data[1] = (version >> 16) & 0xff;
+       data[2] = (version >> 8) & 0xff;
+       data[3] = (version >> 0) & 0xff;
+
+       data[4] = (rand_seed >> 8) & 0xff;
+       data[5] = (rand_seed >> 0) & 0xff;
+       
+       rand_seed++;
+
+       send_packet(fd, 'V', data, sizeof(data));
+}
+
+static int
+handshake(int dns_fd)
+{
+       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;
+       int i;
+       int r;
+
+       for (i = 0; running && i < 5; i++) {
+               tv.tv_sec = i + 1;
+               tv.tv_usec = 0;
+
+               send_version(dns_fd, VERSION);
+               
+               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) {
+                               perror("read");
+                               continue;
+                       }
+
+                       if (read >= 9) {
+                               payload =  (((in[4] & 0xff) << 24) |
+                                                       ((in[5] & 0xff) << 16) |
+                                                       ((in[6] & 0xff) << 8) |
+                                                       ((in[7] & 0xff)));
+
+                               if (strncmp("VACK", in, 4) == 0) {
+                                       seed = payload;
+                                       userid = in[8];
+
+                                       printf("Version ok, both running 0x%08x. You are user #%d\n", VERSION, userid);
+                                       goto perform_login;
+                               } else if (strncmp("VNAK", in, 4) == 0) {
+                                       errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n", 
+                                                       VERSION, payload);
+                                       /* NOTREACHED */
+                               } else if (strncmp("VFUL", in, 4) == 0) {
+                                       errx(1, "server full, all %d slots are taken. try again later\n", payload);
+                                       /* NOTREACHED */
+                               }
+                       } else 
+                               warnx("did not receive proper login challenge\n");
+               }
+               
+               printf("Retrying version check...\n");
+       }
+       errx(1, "couldn't connect to server");
+       /* NOTREACHED */
+       
+perform_login:
+       login_calculate(login, 16, password, seed);
+       
+       for (i=0; running && i<5 ;i++) {
+               tv.tv_sec = i + 1;
+               tv.tv_usec = 0;
+
+               send_login(dns_fd, login, 16);
+               
+               FD_ZERO(&fds);
+               FD_SET(dns_fd, &fds);
+
+               r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
+
+               if(r > 0) {
+                       read = read_dns(dns_fd, in, sizeof(in));
+                       
+                       if(read <= 0) {
+                               warn("read");
+                               continue;
+                       }
+
+                       if (read > 0) {
+                               if (strncmp("LNAK", in, 4) == 0) {
+                                       printf("Bad password\n");
+                                       return 1;
+                               } else if (sscanf(in, "%64[^-]-%64[^-]-%d", 
+                                       server, client, &mtu) == 3) {
+                                       
+                                       server[64] = 0;
+                                       client[64] = 0;
+                                       if (tun_setip(client) == 0 && 
+                                               tun_setmtu(mtu) == 0) {
+                                               return 0;
+                                       } else {
+                                               warnx("Received handshake with bad data");
+                                       }
+                               } else {
+                                       printf("Received bad handshake\n");
+                               }
+                       }
+               }
+
+               printf("Retrying login...\n");
+       }
+
+       return 1;
+}
+
+static void 
+set_target(const char *host) 
+{
+       struct hostent *h;
+
+       h = gethostbyname(host);
+       if (!h)
+               err(1, "couldn't resolve name %s", host);
+
+       memset(&peer, 0, sizeof(peer));
+       peer.sin_family = AF_INET;
+       peer.sin_port = htons(53);
+       peer.sin_addr = *((struct in_addr *) h->h_addr);
+}
+
+static void
+usage() {
+       extern char *__progname;
+
+       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
+                       "nameserver topdomain\n", __progname);
+       exit(2);
+}
+
+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] "
+                       "[-P password] nameserver topdomain\n", __progname);
+       printf("  -v to print version info and exit\n");
+       printf("  -h to print this help and exit\n");
+       printf("  -f to keep running in foreground\n");
+       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("nameserver is the IP number of the relaying nameserver\n");
+       printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
+
+       exit(0);
+}
+
+static void
+version() {
+
+       printf("iodine IP over DNS tunneling client\n");
+       printf("version: 0.4.0 from 2007-03-25\n");
+
+       exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+       struct passwd *pw;
+       char *username;
+       int foreground;
+       char *newroot;
+       char *device;
+       int choice;
+       int tun_fd;
+       int dns_fd;
+
+       memset(password, 0, 33);
+       username = NULL;
+       foreground = 0;
+       newroot = NULL;
+       device = NULL;
+       chunkid = 0;
+       
+       while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
+               switch(choice) {
+               case 'v':
+                       version();
+                       break;
+               case 'f':
+                       foreground = 1;
+                       break;
+               case 'h':
+                       help();
+                       break;
+               case 'u':
+                       username = optarg;
+                       break;
+               case 't':
+                       newroot = optarg;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'P':
+                       strncpy(password, optarg, 32);
+                       password[32] = 0;
+                       break;
+               default:
+                       usage();
+                       /* NOTREACHED */
+               }
+       }
+       
+       if (geteuid() != 0) {
+               printf("Run as root and you'll be happy.\n");
+               usage();
+       }
+
+       argc -= optind;
+       argv += optind;
+       
+       if (argc != 2) 
+               usage();
+
+       topdomain = strdup(argv[1]);
+
+       if(username) {
+               pw = getpwnam(username);
+               if (!pw) {
+                       printf("User %s does not exist!\n", username);
+                       usage();
+               }
+       }
+       
+       if (strlen(password) == 0) {
+               printf("Enter password on stdin:\n");
+               scanf("%32s", password);
+               password[32] = 0;
+       }
+
+       if ((tun_fd = open_tun(device)) == -1)
+               goto cleanup1;
+       if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
+               goto cleanup2;
+       set_target(argv[0]);
+
+       signal(SIGINT, sighandler);
+       signal(SIGTERM, sighandler);
+
+       if(handshake(dns_fd))
+               goto cleanup2;
+       
+       printf("Sending queries for %s to %s\n", argv[1], argv[0]);
+
+       do_chroot(newroot);
+       
+       if (username) {
+               if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
+                       printf("Could not switch to user %s!\n", username);
+                       usage();
+               }
+       }
+       
+       if (!foreground) {
+               do_detach();
+       }
+
+       tunnel(tun_fd, dns_fd);
+
+cleanup2:
+       close_dns(dns_fd);
+       close_tun(tun_fd);
+cleanup1:
+
+       return 0;
+}
diff --git a/src/iodined.c b/src/iodined.c
new file mode 100644 (file)
index 0000000..950b0d8
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <err.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 "common.h"
+#include "dns.h"
+#include "user.h"
+#include "login.h"
+#include "tun.h"
+#include "encoding.h"
+#include "version.h"
+
+int running = 1;
+
+char *topdomain;
+
+char password[33];
+
+int my_mtu;
+in_addr_t my_ip;
+
+static int read_dns(int, struct query *, char *, int);
+static void write_dns(int, struct query *, char *, int);
+
+static void
+sigint(int sig) 
+{
+       running = 0;
+}
+
+static int
+tunnel_tun(int tun_fd, int dns_fd)
+{
+       unsigned long outlen;
+       struct ip *header;
+       char out[64*1024];
+       char in[64*1024];
+       int userid;
+       int read;
+
+       if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
+               return 0;
+       
+       /* find target ip in packet, in is padded with 4 bytes TUN header */
+       header = (struct ip*) (in + 4);
+       userid = find_user_by_ip(header->ip_dst.s_addr);
+       if (userid < 0)
+               return 0;
+
+       outlen = sizeof(out);
+       compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
+
+       /* if another packet is queued, throw away this one. TODO build queue */
+       if (users[userid].outpacket.len == 0) {
+               memcpy(users[userid].outpacket.data, out, outlen);
+               users[userid].outpacket.len = outlen;
+               return outlen;
+       } else {
+               return 0;
+       }
+}
+
+typedef enum {
+       VERSION_ACK,
+       VERSION_NACK,
+       VERSION_FULL
+} version_ack_t;
+
+static void
+send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *u)
+{
+       char out[9];
+       
+       switch (ack) {
+       case VERSION_ACK:
+               strncpy(out, "VACK", sizeof(out));
+               break;
+       case VERSION_NACK:
+               strncpy(out, "VNAK", sizeof(out));
+               break;
+       case VERSION_FULL:
+               strncpy(out, "VFUL", sizeof(out));
+               break;
+       }
+       
+       out[4] = ((payload >> 24) & 0xff);
+       out[5] = ((payload >> 16) & 0xff);
+       out[6] = ((payload >> 8) & 0xff);
+       out[7] = ((payload) & 0xff);
+       out[8] = u->id;
+
+
+       write_dns(fd, &u->q, out, sizeof(out));
+}
+
+static int
+tunnel_dns(int tun_fd, int dns_fd)
+{
+       struct in_addr tempip;
+       struct user dummy;
+       struct ip *hdr;
+       unsigned long outlen;
+       char logindata[16];
+       char out[64*1024];
+       char in[64*1024];
+       char *tmp[2];
+       int userid;
+       int touser;
+       int version;
+       int read;
+       int code;
+
+       userid = -1;
+       if ((read = read_dns(dns_fd, &(dummy.q), in, sizeof(in))) <= 0)
+               return 0;
+                               
+       if(in[0] == 'V' || in[0] == 'v') {
+               /* Version greeting, compare and send ack/nak */
+               if (read > 4) { 
+                       /* Received V + 32bits version */
+
+                       version = (((in[1] & 0xff) << 24) |
+                                          ((in[2] & 0xff) << 16) |
+                                          ((in[3] & 0xff) << 8) |
+                                          ((in[4] & 0xff)));
+
+                       if (version == VERSION) {
+                               userid = find_available_user();
+                               if (userid >= 0) {
+                                       users[userid].seed = rand();
+                                       memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
+                                       memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
+                                       users[userid].addrlen = dummy.q.fromlen;
+                                       send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
+                                       users[userid].q.id = 0;
+                               } else {
+                                       /* No space for another user */
+                                       send_version_response(dns_fd, VERSION_FULL, USERS, &dummy);
+                               }
+                       } else {
+                               send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
+                       }
+               } else {
+                       send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
+               }
+       } else if(in[0] == 'L' || in[0] == 'l') {
+               /* Login phase, handle auth */
+               userid = in[1];
+               if (userid < 0 || userid >= USERS) {
+                       write_dns(dns_fd, &(dummy.q), "BADIP", 5);
+                       return 0; /* illegal id */
+               }
+               users[userid].last_pkt = time(NULL);
+               login_calculate(logindata, 16, password, users[userid].seed);
+
+               if (dummy.q.fromlen != users[userid].addrlen ||
+                               memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
+                       write_dns(dns_fd, &(dummy.q), "BADIP", 5);
+               } else {
+                       if (read >= 18 && (memcmp(logindata, in+2, 16) == 0)) {
+                               /* Login ok, send ip/mtu info */
+
+                               tempip.s_addr = my_ip;
+                               tmp[0] = strdup(inet_ntoa(tempip));
+                               tempip.s_addr = users[userid].tun_ip;
+                               tmp[1] = strdup(inet_ntoa(tempip));
+
+                               read = snprintf(out, sizeof(out), "%s-%s-%d", 
+                                               tmp[0], tmp[1], my_mtu);
+
+                               write_dns(dns_fd, &(dummy.q), out, read);
+                               dummy.q.id = 0;
+
+                               free(tmp[1]);
+                               free(tmp[0]);
+                       } else {
+                               write_dns(dns_fd, &(dummy.q), "LNAK", 4);
+                       }
+               }
+       } else if(in[0] == 'P' || in[0] == 'p') {
+               /* Ping packet, store userid */
+               userid = in[1];
+               if (userid < 0 || userid >= USERS) {
+                       write_dns(dns_fd, &(dummy.q), "BADIP", 5);
+                       return 0; /* illegal id */
+               }
+               memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
+               users[userid].last_pkt = time(NULL);
+       } else if((in[0] >= '0' && in[0] <= '9')
+                       || (in[0] >= 'a' && in[0] <= 'f')
+                       || (in[0] >= 'A' && in[0] <= 'F')) {
+               if ((in[0] >= '0' && in[0] <= '9'))
+                       code = in[0] - '0';
+               if ((in[0] >= 'a' && in[0] <= 'f'))
+                       code = in[0] - 'a' + 10;
+               if ((in[0] >= 'A' && in[0] <= 'F'))
+                       code = in[0] - 'A' + 10;
+
+               userid = code >> 1;
+               if (userid < 0 || userid >= USERS) {
+                       write_dns(dns_fd, &(dummy.q), "BADIP", 5);
+                       return 0; /* illegal id */
+               }
+
+               /* Check sending ip number */
+               if (dummy.q.fromlen != users[userid].addrlen ||
+                               memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
+                       write_dns(dns_fd, &(dummy.q), "BADIP", 5);
+               } else {
+                       users[userid].last_pkt = time(NULL);
+                       memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
+                       users[userid].addrlen = dummy.q.fromlen;
+                       memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1);
+                       users[userid].inpacket.len += read - 1;
+                       users[userid].inpacket.offset += read - 1;
+
+                       if (code & 1) {
+                               outlen = sizeof(out);
+                               uncompress((uint8_t*)out, &outlen, 
+                                                  (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
+
+                               hdr = (struct ip*) (out + 4);
+                               touser = find_user_by_ip(hdr->ip_dst.s_addr);
+
+                               if (touser == -1) {
+                                       /* send the uncompressed packet to tun device */
+                                       write_tun(tun_fd, out, outlen);
+                               } else {
+                                       /* send the compressed packet to other client
+                                        * if another packet is queued, throw away this one. TODO build queue */
+                                       if (users[touser].outpacket.len == 0) {
+                                               memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
+                                               users[touser].outpacket.len = users[userid].inpacket.len;
+                                       }
+                               }
+                               users[userid].inpacket.len = users[userid].inpacket.offset = 0;
+                       }
+               }
+       }
+       /* userid must be set for a reply to be sent */
+       if (userid >= 0 && userid < USERS && dummy.q.fromlen == users[userid].addrlen &&
+                       memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) == 0 &&
+                       users[userid].outpacket.len > 0) {
+
+               write_dns(dns_fd, &(dummy.q), users[userid].outpacket.data, users[userid].outpacket.len);
+               users[userid].outpacket.len = 0;
+               users[userid].q.id = 0;
+       }
+
+       return 0;
+}
+
+static int
+tunnel(int tun_fd, int dns_fd)
+{
+       struct timeval tv;
+       fd_set fds;
+       int i;
+       int j;
+
+       while (running) {
+               if (users_waiting_on_reply()) {
+                       tv.tv_sec = 0;
+                       tv.tv_usec = 5000;
+               } else {
+                       tv.tv_sec = 1;
+                       tv.tv_usec = 0;
+               }
+
+               FD_ZERO(&fds);
+               /* TODO : use some kind of packet queue */
+               if(!all_users_waiting_to_send()) {
+                       FD_SET(tun_fd, &fds);
+               }
+               FD_SET(dns_fd, &fds);
+
+               i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
+               
+               if(i < 0) {
+                       if (running) 
+                               warn("select");
+                       return 1;
+               }
+       
+               if (i==0) {     
+                       for (j = 0; j < USERS; j++) {
+                               if (users[j].q.id != 0) {
+                                       write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len);
+                                       users[j].outpacket.len = 0;
+                                       users[j].q.id = 0;
+                               }
+                       }
+               } else {
+                       if(FD_ISSET(tun_fd, &fds)) {
+                               tunnel_tun(tun_fd, dns_fd);
+                               continue;
+                       }
+                       if(FD_ISSET(dns_fd, &fds)) {
+                               tunnel_dns(tun_fd, dns_fd);
+                               continue;
+                       } 
+               }
+       }
+
+       return 0;
+}
+
+static int
+read_dns(int fd, struct query *q, char *buf, int buflen)
+{
+       struct sockaddr_in from;
+       char packet[64*1024];
+       char *domain;
+       socklen_t addrlen;
+       int rv;
+       int r;
+
+       addrlen = sizeof(struct sockaddr);
+       r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
+
+       if (r > 0) {
+               dns_decode(buf, buflen, q, QR_QUERY, packet, r);
+               domain = strstr(q->name, topdomain);
+               rv = decode_data(buf, buflen, q->name, domain);
+               q->fromlen = addrlen;
+               memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
+       } else if (r < 0) {     
+               /* Error */
+               perror("recvfrom");
+               rv = 0;
+       }
+
+       return rv;
+}
+
+static void
+write_dns(int fd, struct query *q, char *data, int datalen)
+{
+       char buf[64*1024];
+       int len;
+
+       len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
+       
+       sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
+}
+
+static void
+usage() {
+       extern char *__progname;
+
+       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
+               "[-l ip address to listen on] [-p port] [-P password]"
+               " tunnel_ip topdomain\n", __progname);
+       exit(2);
+}
+
+static void
+help() {
+       extern char *__progname;
+
+       printf("iodine IP over DNS tunneling server\n");
+       printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
+               "[-l ip address to listen on] [-p port] [-P password]"
+               " tunnel_ip 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("  -m mtu to set tunnel device mtu\n");
+       printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
+       printf("  -p port to listen on for incoming dns traffic (default 53)\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("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.4.0 from 2007-03-25\n");
+       exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+       int choice;
+       int tun_fd;
+       int dnsd_fd;
+       char *newroot;
+       char *username;
+       char *device;
+       int foreground;
+       int mtu;
+       struct passwd *pw;
+       in_addr_t listen_ip;
+       int port;
+
+       username = NULL;
+       newroot = NULL;
+       device = NULL;
+       foreground = 0;
+       mtu = 1024;
+       listen_ip = INADDR_ANY;
+       port = 53;
+
+       memset(password, 0, 33);
+       srand(time(NULL));
+       
+       while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
+               switch(choice) {
+               case 'v':
+                       version();
+                       break;
+               case 'f':
+                       foreground = 1;
+                       break;
+               case 'h':
+                       help();
+                       break;
+               case 'u':
+                       username = optarg;
+                       break;
+               case 't':
+                       newroot = optarg;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'm':
+                       mtu = atoi(optarg);
+                       break;
+               case 'l':
+                       listen_ip = inet_addr(optarg);
+                       break;
+               case 'p':
+                       port = atoi(optarg);
+                       if (port) {
+                               printf("ALERT! Other dns servers expect you to run on port 53.\n");
+                               printf("You must manually forward port 53 to port %d for things to work.\n", port);
+                       }
+                       break;
+               case 'P':
+                       strncpy(password, optarg, 32);
+                       password[32] = 0;
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (geteuid() != 0) {
+               printf("Run as root and you'll be happy.\n");
+               usage();
+       }
+
+       if (argc != 2) 
+               usage();
+
+       topdomain = strdup(argv[1]);
+
+       if (username) {
+               pw = getpwnam(username);
+               if (!pw) {
+                       printf("User %s does not exist!\n", username);
+                       usage();
+               }
+       }
+
+       if (mtu == 0) {
+               printf("Bad MTU given.\n");
+               usage();
+       }
+
+       if (listen_ip == INADDR_NONE) {
+               printf("Bad IP address to listen on.\n");
+               usage();
+       }
+
+       if (strlen(password) == 0) {
+               printf("Enter password on stdin:\n");
+               scanf("%32s", password);
+               password[32] = 0;
+       }
+
+       if ((tun_fd = open_tun(device)) == -1)
+               goto cleanup0;
+       if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
+               goto cleanup1;
+       if ((dnsd_fd = open_dns(port, listen_ip)) == -1) 
+               goto cleanup2;
+
+       my_ip = inet_addr(argv[0]);
+       my_mtu = mtu;
+       init_users(my_ip);
+
+       printf("Listening to dns for domain %s\n", argv[1]);
+
+       do_chroot(newroot);
+
+       signal(SIGINT, sigint);
+       if (username) {
+               if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
+                       printf("Could not switch to user %s!\n", username);
+                       usage();
+               }
+       }
+       
+       if (!foreground) {
+               do_detach();
+       }
+       
+       tunnel(tun_fd, dnsd_fd);
+
+cleanup2:
+       close_dns(dnsd_fd);
+cleanup1:
+       close_tun(tun_fd);      
+cleanup0:
+
+       return 0;
+}
diff --git a/src/login.c b/src/login.c
new file mode 100644 (file)
index 0000000..b3f942a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+
+#include "md5.h"
+
+/* 
+ * Needs a 16byte array for output, and 32 bytes password 
+ */
+void 
+login_calculate(char *buf, int buflen, char *pass, int seed) 
+{
+       unsigned char temp[32];
+       md5_state_t ctx;
+       int *ix;
+       int i;
+       int k;
+
+       if (buflen < 16) 
+               return;
+
+       memcpy(temp, pass, 32);
+       ix = (int*) temp;
+
+       for (i = 0; i < 8; i++) {
+               k = ntohl(*ix);
+               k ^= seed;
+               *ix++ = htonl(k);
+       }
+
+       md5_init(&ctx);
+       md5_append(&ctx, temp, 32);
+       md5_finish(&ctx, (unsigned char *) buf);
+}
+
diff --git a/src/login.h b/src/login.h
new file mode 100644 (file)
index 0000000..d0c335f
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __LOGIN_H__
+#define __LOGIN_H__
+
+void login_calculate(char *, int, char *, int);
+
+#endif
+
diff --git a/src/md5.c b/src/md5.c
new file mode 100644 (file)
index 0000000..89d3d5e
--- /dev/null
+++ b/src/md5.c
@@ -0,0 +1,384 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+       http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+       either statically or dynamically; added missing #include <string.h>
+       in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+       type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+       unsigned in ANSI C, signed in traditional"; made test program
+       self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER      /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+       a = pms->abcd[0], b = pms->abcd[1],
+       c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+       /*
+        * Determine dynamically whether this is a big-endian or
+        * little-endian machine, since we can use a more efficient
+        * algorithm on the latter.
+        */
+       static const int w = 1;
+
+       if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0            /* little-endian */
+       {
+           /*
+            * On little-endian machines, we can process properly aligned
+            * data without copying it.
+            */
+           if (!((data - (const md5_byte_t *)0) & 3)) {
+               /* data are properly aligned */
+               X = (const md5_word_t *)data;
+           } else {
+               /* not aligned */
+               memcpy(xbuf, data, 64);
+               X = xbuf;
+           }
+       }
+#endif
+#if BYTE_ORDER == 0
+       else                    /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0            /* big-endian */
+       {
+           /*
+            * On big-endian machines, we must arrange the bytes in the
+            * right order.
+            */
+           const md5_byte_t *xp = data;
+           int i;
+
+#  if BYTE_ORDER == 0
+           X = xbuf;           /* (dynamic only) */
+#  else
+#    define xbuf X             /* (static only) */
+#  endif
+           for (i = 0; i < 16; ++i, xp += 4)
+               xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+       }
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+       return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+       pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+       int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+       memcpy(pms->buf + offset, p, copy);
+       if (offset + copy < 64)
+           return;
+       p += copy;
+       left -= copy;
+       md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+       md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+       memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+       0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+       data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+       digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+
+
diff --git a/src/md5.h b/src/md5.h
new file mode 100644 (file)
index 0000000..698c995
--- /dev/null
+++ b/src/md5.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+       http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+       references to Ghostscript; clarified derivation from RFC 1321;
+       now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+       added conditionalization for C++ compilation from Martin
+       Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];       /* message length in bits, lsw first */
+    md5_word_t abcd[4];                /* digest buffer */
+    md5_byte_t buf[64];                /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/src/read.c b/src/read.c
new file mode 100644 (file)
index 0000000..299bc3e
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+static int
+readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
+{
+       char *dummy;
+       char *s;
+       char *d;
+       int len;
+       int offset;
+       char c;
+
+       if (loop <= 0)
+               return 0;
+
+       len = 0;
+       s = *src;
+       d = dst;
+       while(*s && len < length - 2) {
+               c = *s++;
+
+               /* is this a compressed label? */
+               if((c & 0xc0) == 0xc0) {
+                       offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
+                       if (offset > packetlen) {
+                               if (len == 0) {
+                                       /* Bad jump first in packet */
+                                       return 0;
+                               } else {
+                                       /* Bad jump after some data */
+                                       break;
+                               }
+                       }
+                       dummy = packet + offset;
+                       len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
+                       goto end;
+               }
+
+               while(c && len < length - 1) {
+                       *d++ = *s++;
+                       len++;
+
+                       c--;
+               }
+               
+               if (len >= length - 1) {
+                       break; /* We used up all space */
+               }
+
+               if (*s != 0) {
+                       *d++ = '.';
+                       len++;
+               }
+       }
+       dst[len++] = '\0';
+
+end:
+       (*src) = s+1;
+       return len;
+}
+
+int
+readname(char *packet, int packetlen, char **src, char *dst, size_t length)
+{
+       return readname_loop(packet, packetlen, src, dst, length, 10);
+}
+
+int
+readshort(char *packet, char **src, short *dst)
+{
+       unsigned char *p;
+
+       p = (unsigned char *) *src;
+       *dst = (p[0] << 8) | p[1];
+
+       (*src) += sizeof(short);
+       return sizeof(short);
+}
+
+int
+readlong(char *packet, char **src, uint32_t *dst)
+{
+       /* A long as described in dns protocol is always 32 bits */
+       unsigned char *p;
+
+       p = (unsigned char *) *src;
+
+       *dst = ((uint32_t)p[0] << 24) 
+                | ((uint32_t)p[1] << 16) 
+                | ((uint32_t)p[2] << 8)
+                | ((uint32_t)p[3]);
+
+       (*src) += sizeof(uint32_t);
+       return sizeof(uint32_t);
+}
+
+int
+readdata(char *packet, char **src, char *dst, size_t len)
+{
+       if (len < 0)
+               return 0;
+
+       memcpy(dst, *src, len);
+
+       (*src) += len;
+
+       return len;
+}
+
+int
+putname(char **buf, size_t buflen, const char *host)
+{
+       char *word;
+       int left;
+       char *h;
+       char *p;
+
+       h = strdup(host);
+       left = buflen;
+       p = *buf;
+       
+       word = strtok(h, ".");
+       while(word) {
+               if (strlen(word) > 63 || strlen(word) > left) {
+                       free(h);
+                       return -1;
+               }
+
+               left -= (strlen(word) + 1);
+               *p++ = (char)strlen(word);
+               memcpy(p, word, strlen(word));
+               p += strlen(word);
+
+               word = strtok(NULL, ".");
+       }
+
+       *p++ = 0;
+
+       free(h);
+
+       *buf = p;
+       return buflen - left;
+}
+
+int
+putbyte(char **dst, unsigned char value)
+{
+       **dst = value;
+       (*dst)++;
+
+       return sizeof(char);
+}
+
+int
+putshort(char **dst, unsigned short value)
+{
+       unsigned char *p;
+
+       p = (unsigned char *) *dst;
+
+       *p++ = (value >> 8);
+       *p++ = value;
+
+       (*dst) = (char *) p;
+       return sizeof(short);
+}
+
+int
+putlong(char **dst, uint32_t value)
+{
+       /* A long as described in dns protocol is always 32 bits */
+       unsigned char *p;
+
+       p = (unsigned char *) *dst;
+
+       *p++ = (value >> 24);
+       *p++ = (value >> 16);
+       *p++ = (value >> 8);
+       *p++ = (value);
+
+       (*dst) = (char *) p;
+       return sizeof(uint32_t);
+}
+
+int
+putdata(char **dst, char *data, size_t len)
+{
+       if (len < 0)
+               return 0;
+
+       memcpy(*dst, data, len);
+       
+       (*dst) += len;
+       return len;
+}
+
diff --git a/src/read.h b/src/read.h
new file mode 100644 (file)
index 0000000..241447b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _READ_H_
+#define _READ_H_
+
+int readname(char *, int, char **, char *, size_t);
+int readshort(char *, char **, short *);
+int readlong(char *, char **, uint32_t *);
+int readdata(char *, char **, char *, size_t);
+
+int putname(char **, size_t, const char *);
+int putbyte(char **, unsigned char);
+int putshort(char **, unsigned short);
+int putlong(char **, uint32_t);
+int putdata(char **, char *, size_t);
+
+#endif
diff --git a/src/tun.c b/src/tun.c
new file mode 100644 (file)
index 0000000..cdc9124
--- /dev/null
+++ b/src/tun.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <err.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "tun.h"
+
+#define TUN_MAX_TRY 50
+
+char if_name[50];
+
+#ifdef LINUX
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+
+int 
+open_tun(const char *tun_device) 
+{
+       int i;
+       int tun_fd;
+       struct ifreq ifreq;
+       char *tunnel = "/dev/net/tun";
+
+       if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
+               warn("open_tun: %s: %s", tunnel, strerror(errno));
+               return -1;
+       }
+
+       memset(&ifreq, 0, sizeof(ifreq));
+
+       ifreq.ifr_flags = IFF_TUN; 
+
+       if (tun_device != NULL) {
+               strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
+               strncpy(if_name, tun_device, sizeof(if_name));
+
+               if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
+                       printf("Opened %s\n", ifreq.ifr_name);
+                       return tun_fd;
+               }
+
+               if (errno != EBUSY) {
+                       warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
+                       return -1;
+               }
+       } else {
+               for (i = 0; i < TUN_MAX_TRY; i++) {
+                       snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
+
+                       if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
+                               printf("Opened %s\n", ifreq.ifr_name);
+                               snprintf(if_name, sizeof(if_name), "dns%d", i);
+                               return tun_fd;
+                       }
+
+                       if (errno != EBUSY) {
+                               warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
+                               return -1;
+                       }
+               }
+
+               warn("open_tun: Couldn't set interface name");
+       }
+       return -1;
+}
+
+#else /* BSD */
+
+int 
+open_tun(const char *tun_device) 
+{
+       int i;
+       int tun_fd;
+       char tun_name[50];
+
+       if (tun_device != NULL) {
+               snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
+               strncpy(if_name, tun_device, sizeof(if_name));
+
+               if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
+                       warn("open_tun: %s: %s", tun_name, strerror(errno));
+                       return -1;
+               }
+
+               printf("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);
+                               snprintf(if_name, sizeof(if_name), "tun%d", i);
+                               return tun_fd;
+                       }
+
+                       if (errno == ENOENT)
+                               break;
+               }
+
+               warn("open_tun: Failed to open tunneling device");
+       }
+
+       return -1;
+}
+
+#endif /* !LINUX */
+
+void 
+close_tun(int tun_fd) 
+{
+       if (tun_fd >= 0)
+               close(tun_fd);
+}
+
+int 
+write_tun(int tun_fd, char *data, int len) 
+{
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
+       data += 4;
+       len -= 4;
+#else /* !FREEBSD/DARWIN */
+#ifdef LINUX
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0x08;
+       data[3] = 0x00;
+#else /* OPENBSD */
+       data[0] = 0x00;
+       data[1] = 0x00;
+       data[2] = 0x00;
+       data[3] = 0x02;
+#endif /* !LINUX */
+#endif /* FREEBSD */
+
+       if (write(tun_fd, data, len) != len) {
+               warn("write_tun");
+               return 1;
+       }
+       return 0;
+}
+
+int 
+read_tun(int tun_fd, char *buf, int len) 
+{
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
+       /* FreeBSD/Darwin/NetBSD has no header */
+       return read(tun_fd, buf + 4, len - 4) + 4;
+#else /* !FREEBSD */
+       return read(tun_fd, buf, len);
+#endif /* !FREEBSD */
+}
+
+int
+tun_setip(const char *ip)
+{
+       char cmdline[512];
+
+       if (inet_addr(ip) != INADDR_NONE) {
+               snprintf(cmdline, sizeof(cmdline), 
+                               "/sbin/ifconfig %s %s %s netmask 255.255.255.0",
+                               if_name,
+                               ip,
+                               ip);
+               
+               printf("Setting IP of %s to %s\n", if_name, ip);
+#ifndef LINUX
+               int r;
+
+               r = system(cmdline);
+               if(r != 0) {
+                       return r;
+               } else {
+                       snprintf(cmdline, sizeof(cmdline),
+                                       "/sbin/route add %s/24 %s",
+                                       ip, ip);
+               }
+               printf("Adding route %s/24 to %s\n", ip, ip);
+#endif
+               return system(cmdline);
+       } else {
+               printf("Invalid IP: %s!\n", ip);
+       }
+
+       return 1;
+}
+
+int 
+tun_setmtu(const int mtu)
+{
+       char cmdline[512];
+
+       if (mtu > 200 && mtu < 1500) {
+               snprintf(cmdline, sizeof(cmdline), 
+                               "/sbin/ifconfig %s mtu %d",
+                               if_name,
+                               mtu);
+               
+               printf("Setting MTU of %s to %d\n", if_name, mtu);
+               return system(cmdline);
+       } else {
+               warn("MTU out of range: %d\n", mtu);
+       }
+
+       return 1;
+}
+
diff --git a/src/tun.h b/src/tun.h
new file mode 100644 (file)
index 0000000..2313b3a
--- /dev/null
+++ b/src/tun.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TUN_H_
+#define _TUN_H_
+
+int open_tun(const char *);
+void close_tun(int);
+int write_tun(int, char *, int);
+int read_tun(int, char *, int);
+int tun_setip(const char *);
+int tun_setmtu(const int);
+
+#endif /* _TUN_H_ */
diff --git a/src/user.c b/src/user.c
new file mode 100644 (file)
index 0000000..ed809b8
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "common.h"
+#include "user.h"
+
+struct user users[USERS];
+
+void
+init_users(in_addr_t my_ip)
+{
+       int i;
+       char newip[16];
+       
+       memset(users, 0, USERS * sizeof(struct user));
+       for (i = 0; i < USERS; i++) {
+               users[i].id = i;
+               snprintf(newip, sizeof(newip), "0.0.0.%d", i + 1);
+               users[i].tun_ip = my_ip + inet_addr(newip);;
+               users[i].inpacket.len = 0;
+               users[i].inpacket.offset = 0;
+               users[i].outpacket.len = 0;
+               users[i].q.id = 0;
+       }
+}
+
+int
+users_waiting_on_reply()
+{
+       int ret;
+       int i;
+
+       ret = 0;
+       for (i = 0; i < USERS; i++) {
+               if (users[i].active && users[i].last_pkt + 60 > time(NULL) &&
+                       users[i].q.id != 0) {
+                       ret++;
+               }
+       }
+       
+       return ret;
+}
+
+int
+find_user_by_ip(uint32_t ip)
+{
+       int ret;
+       int i;
+
+       ret = -1;
+       for (i = 0; i < USERS; i++) {
+               if (users[i].active && users[i].last_pkt + 60 > time(NULL) &&
+                       ip == users[i].tun_ip) {
+                       ret = i;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int
+all_users_waiting_to_send()
+{
+       time_t now;
+       int ret;
+       int i;
+
+       ret = 1;
+       now = time(NULL);
+       for (i = 0; i < USERS; i++) {
+               if (users[i].active && users[i].last_pkt + 60 > now &&
+                       users[i].outpacket.len == 0) {
+                       ret = 0;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int
+find_available_user()
+{
+       int ret = -1;
+       int i;
+       for (i = 0; i < USERS; i++) {
+               /* Not used at all or not used in one minute */
+               if (!users[i].active || users[i].last_pkt + 60 < time(NULL)) {
+                       users[i].active = 1;
+                       users[i].last_pkt = time(NULL);
+                       ret = i;
+                       break;
+               }
+       }
+       return ret;
+}
+
diff --git a/src/user.h b/src/user.h
new file mode 100644 (file)
index 0000000..b947ea4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __USER_H__
+#define __USER_H__
+
+#define USERS 8
+
+struct user {
+       char id;
+       int active;
+       time_t last_pkt;
+       int seed;
+       in_addr_t tun_ip;
+       struct sockaddr host;
+       int addrlen;
+       struct query q;
+       struct packet inpacket;
+       struct packet outpacket;
+};
+
+extern struct user users[USERS];
+
+void init_users(in_addr_t);
+int users_waiting_on_reply();
+int find_user_by_ip(uint32_t);
+int all_users_waiting_to_send();
+int find_available_user();
+
+#endif
diff --git a/src/version.h b/src/version.h
new file mode 100644 (file)
index 0000000..8b9f6ca
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _VERSION_H_
+#define _VERSION_H_
+
+/* This is the version of the network protocol
+   It is usually equal to the latest iodine version number */
+#define VERSION 0x00000400
+
+#endif /* _VERSION_H_ */
+
diff --git a/structs.h b/structs.h
deleted file mode 100644 (file)
index 534f59c..0000000
--- a/structs.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _STRUCTS_H_
-#define _STRUCTS_H_
-
-struct packet 
-{
-       int len;
-       int offset;
-       char data[64*1024];
-};
-
-struct query {
-       char name[258];
-       short type;
-       short id;
-       struct sockaddr from;
-       int fromlen;
-};
-
-#endif /* _STRUCTS_H_ */
diff --git a/test.c b/test.c
deleted file mode 100644 (file)
index a2098cf..0000000
--- a/test.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/stat.h>
-#include <arpa/nameser.h>
-#ifdef DARWIN
-#include <arpa/nameser8_compat.h>
-#endif
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "structs.h"
-#include "encoding.h"
-#include "dns.h"
-#include "read.h"
-       
-static void
-test_readputshort()
-{
-       short tshort;
-       short putted;
-       short temps;
-       char buf[4];
-       short *s;
-       char* p;
-       int i;
-
-       printf(" * Testing read/putshort... ");
-       fflush(stdout);
-
-       for (i = 0; i < 65536; i++) {
-               tshort = (unsigned short) i;
-               temps = htons(tshort);
-               p = buf;
-               putshort(&p, tshort);
-               s = &putted;
-               memcpy(s, buf, sizeof(short));
-               if (putted != temps) {
-                       printf("Bad value on putshort for %d\n", i);
-                       exit(1);
-               }
-               s = &temps;
-               memcpy(buf, s, sizeof(short));
-               p = buf;
-               readshort(NULL, &p, &temps);
-               if (temps != tshort) {
-                       printf("Bad value on readshort for %d\n", i);
-                       exit(1);
-               }
-       }
-
-       printf("OK\n");
-}
-
-static void
-test_readputlong()
-{
-       char buf[4];
-       uint32_t putint;
-       uint32_t tempi;
-       uint32_t tint;
-       uint32_t *l;
-       char* p;
-       int i;
-
-       printf(" * Testing read/putlong... ");
-       fflush(stdout);
-
-       for (i = 0; i < 32; i++) {
-               tint = 0xF << i;
-               tempi = htonl(tint);
-               p = buf;
-               putlong(&p, tint);
-               l = &putint;
-               memcpy(l, buf, sizeof(uint32_t));
-               if (putint != tempi) {
-                       printf("Bad value on putlong for %d\n", i);
-                       exit(2);
-               }
-               l = &tempi;
-               memcpy(buf, l, sizeof(uint32_t));
-               p = buf;
-               readlong(NULL, &p, &tempi);
-               if (tempi != tint) {
-                       printf("Bad value on readlong for %d\n", i);
-                       exit(2);
-               }
-       }
-
-       printf("OK\n");
-}
-
-
-static void
-test_readname()
-{
-       char emptyloop[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 
-       char infloop[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 
-       char longname[] = 
-               "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
-               "\x00\x00\x01\x00\x01";
-       char onejump[] = 
-               "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
-               "\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
-       char badjump[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 }; 
-       char badjump2[] = {
-               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 }; 
-       char *jumper;
-       char buf[1024];
-       char *data;
-       int rv;
-
-       printf(" * Testing readname... ");
-       fflush(stdout);
-
-       memset(buf, 0, sizeof(buf));
-       data = emptyloop + sizeof(HEADER);
-       buf[1023] = 'A';
-       rv = readname(emptyloop, sizeof(emptyloop), &data, buf, 1023);
-       assert(buf[1023] == 'A');
-       
-       memset(buf, 0, sizeof(buf));
-       data = infloop + sizeof(HEADER);
-       buf[4] = '\a';
-       rv = readname(infloop, sizeof(infloop), &data, buf, 4);
-       assert(buf[4] == '\a');
-       
-       memset(buf, 0, sizeof(buf));
-       data = longname + sizeof(HEADER);
-       buf[256] = '\a';
-       rv = readname(longname, sizeof(longname), &data, buf, 256);
-       assert(buf[256] == '\a');
-
-       memset(buf, 0, sizeof(buf));
-       data = onejump + sizeof(HEADER);
-       rv = readname(onejump, sizeof(onejump), &data, buf, 256);
-       assert(rv == 9);
-       
-       // These two tests use malloc to cause segfault if jump is executed
-       memset(buf, 0, sizeof(buf));
-       jumper = malloc(sizeof(badjump));
-       if (jumper) {
-               memcpy(jumper, badjump, sizeof(badjump));
-               data = jumper + sizeof(HEADER);
-               rv = readname(jumper, sizeof(badjump), &data, buf, 256);
-               assert(rv == 0);
-       }
-       free(jumper);
-       
-       memset(buf, 0, sizeof(buf));
-       jumper = malloc(sizeof(badjump2));
-       if (jumper) {
-               memcpy(jumper, badjump2, sizeof(badjump2));
-               data = jumper + sizeof(HEADER);
-               rv = readname(jumper, sizeof(badjump2), &data, buf, 256);
-               assert(rv == 4);
-               assert(strcmp("BA.", buf) == 0);
-       }
-       free(jumper);
-
-       printf("OK\n");
-}
-
-static void
-test_encode_hostname() {
-       char buf[256];
-       int len;
-       int ret;
-
-       len = 256;
-       printf(" * Testing hostname encoding... ");
-       fflush(stdout);
-
-       memset(buf, 0, 256);
-       ret = dns_encode_hostname(      // More than 63 chars between dots
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
-               , buf, len);
-       assert(ret == -1);
-       
-       memset(buf, 0, 256);
-       ret = dns_encode_hostname(      // More chars than fits into array
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
-               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
-               , buf, len);
-       assert(ret == -1);
-       assert(strlen(buf) < len);
-       
-       printf("OK\n");
-}
-
-static void
-test_base32() {
-       char temp[256];
-       char *start = "HELLOTEST";
-       char *out = "1HELLOTEST";
-       char *end;
-       char *tempend;
-       int codedlength;
-
-       printf(" * Testing base32 encoding... ");
-       fflush(stdout);
-
-       memset(temp, 0, sizeof(temp));
-       end = malloc(16);
-       memset(end, 0, 16);
-
-       codedlength = encode_data(start, 9, 256, temp, 0);
-       tempend = temp + strlen(temp);
-       decode_data(end, 16, temp, tempend);
-       assert(strcmp(out, end) == 0);
-       free(end);
-       
-       printf("OK\n");
-}
-
-int
-main()
-{
-       printf("** iodine test suite\n");
-
-       test_readputshort();
-       test_readputlong();
-       test_readname();
-       test_encode_hostname();
-       test_base32();
-
-       printf("** All went well :)\n");
-       return 0;
-}
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..c08d443
--- /dev/null
@@ -0,0 +1,26 @@
+CC = gcc
+TEST = test
+OBJS = test.o base32.o read.o dns.o encoding.o login.o user.o
+SRCOBJS = ../src/base32.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o
+
+OS = `uname | tr "a-z" "A-Z"`
+
+LDFLAGS =  -L/usr/local/lib -lcheck
+CFLAGS = -g -Wall -D$(OS) -I../src -I/usr/local/include -pedantic
+
+all: $(TEST)
+       @./$(TEST)
+
+$(TEST): $(OBJS) $(SRCOBJS)
+       @echo LD $(TEST)
+       @$(CC) -o $@ $(SRCOBJS) $(OBJS) $(LDFLAGS) 
+
+.c.o: 
+       @echo CC $<
+       @$(CC) $(CFLAGS) -c $<
+
+
+clean:
+       @echo "Cleaning..."
+       @rm -f *~ *.core $(TEST) $(OBJS)
+
diff --git a/tests/base32.c b/tests/base32.c
new file mode 100644 (file)
index 0000000..34a5da5
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "base32.h"
+#include "test.h"
+
+struct touple
+{
+       char *a;
+       char *b;
+} testpairs[] = {
+       { "abc123", "mfrggmjsgm" },
+       { NULL, NULL }  
+};
+
+START_TEST(test_base32_encode)
+{
+       size_t len;
+       char *buf;
+       int val;
+       int i;
+
+       len = 0;
+       buf = NULL;
+
+       for (i = 0; testpairs[i].a != NULL; i++) {
+               val = base32_encode(&buf, &len, testpairs[i].a, strlen(testpairs[i].a));
+
+               fail_unless(val > 0, strerror(errno));
+               fail_unless(buf != NULL, "buf == NULL");
+               fail_unless(strcmp(buf, testpairs[i].b) == 0, 
+                               va_str("'%s' != '%s'", buf, testpairs[i].b));
+       }
+
+       free(buf);
+}
+END_TEST
+
+START_TEST(test_base32_decode)
+{
+       size_t len;
+       void *buf;
+       int val;
+       int i;
+
+       len = 0;
+       buf = NULL;
+
+       for (i = 0; testpairs[i].a != NULL; i++) {
+               val = base32_decode(&buf, &len, testpairs[i].b);
+
+               fail_unless(val > 0, strerror(errno));
+               fail_unless(buf != NULL, "buf == NULL");
+               fail_unless(strcmp(buf, testpairs[i].a) == 0, 
+                               va_str("'%s' != '%s'", buf, testpairs[i].a));
+       }
+
+       free(buf);
+}
+END_TEST
+
+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);
+
+       return tc;
+}
diff --git a/tests/dns.c b/tests/dns.c
new file mode 100644 (file)
index 0000000..cbd737a
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <arpa/nameser.h>
+
+#include "common.h"
+#include "dns.h"
+#include "encoding.h"
+#include "test.h"
+
+static void dump_packet(char *, size_t);
+
+static char queryPacket[] = 
+       "\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x32\x41\x4A\x42\x43"
+       "\x55\x59\x54\x43\x50\x45\x42\x39\x47\x51\x39\x4C\x54\x45\x42\x55\x58"
+       "\x47\x49\x44\x55\x4E\x42\x53\x53\x41\x36\x44\x46\x4F\x4E\x39\x43\x41"
+       "\x5A\x44\x42\x32\x41\x41\x41\x41\x41\x36\x44\x42\x04\x6B\x72\x79\x6F"
+       "\x02\x73\x65\x00\x00\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00"
+       "\x00\x00";
+
+static char answerPacket[] = 
+       "\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"
+       "\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20"
+       "\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
+       "\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
+       
+static char *msgData = "this is the message to be delivered";
+static char *topdomain = "kryo.se";
+       
+static char *queryData = "HELLO this is the test data";
+static char *recData = "AHELLO this is the test data"; /* The A flag is added */
+
+START_TEST(test_encode_query)
+{
+       char buf[512];
+       char resolv[512];
+       struct query q;
+       char *d;
+       int len;
+       int ret;
+
+       len = sizeof(buf);
+       memset(&buf, 0, sizeof(buf));
+       memset(&resolv, 0, sizeof(resolv));
+       memset(&q, 0, sizeof(struct query));
+       q.type = T_NULL;
+       q.id = 1337;
+       d = resolv;
+
+       *d++ = 'A';
+       encode_data(queryData, strlen(queryData), 100, d);
+       d = resolv + strlen(resolv);
+       if (*d != '.') {
+               *d++ = '.';
+       }
+       strcpy(d, topdomain);
+       ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
+       len = sizeof(queryPacket) - 1; /* Skip extra null character */
+
+       if (strncmp(queryPacket, buf, sizeof(queryPacket)) || ret != len) {
+               printf("\n");
+               dump_packet(queryPacket, len);
+               dump_packet(buf, ret);
+       }
+       fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
+       fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
+}
+END_TEST
+
+START_TEST(test_decode_query)
+{
+       char buf[512];
+       char *domain;
+       struct query q;
+       int len;
+       int ret;
+
+       memset(&q, 0, sizeof(struct query));
+       memset(&buf, 0, sizeof(buf));
+       q.id = 0;
+       len = sizeof(queryPacket) - 1;
+
+       dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len);
+       domain = strstr(q.name, topdomain);
+       ret = decode_data(buf, sizeof(buf), q.name, domain);
+
+       fail_unless(strncmp(buf, recData, ret) == 0, "Did not extract expected host: '%s'", buf);
+       fail_unless(strlen(buf) == strlen(recData), va_str("Bad host length: %d, expected %d", strlen(q.name), strlen(recData)));
+}
+END_TEST
+
+START_TEST(test_encode_response)
+{
+       char buf[512];
+       char *host = "silly.host.of.iodine.code.kryo.se";
+       struct query q;
+       int len;
+       int ret;
+
+       len = sizeof(buf);
+       memset(&buf, 0, sizeof(buf));
+       memset(&q, 0, sizeof(struct query));
+       strncpy(q.name, host, strlen(host));
+       q.type = T_NULL;
+       q.id = 1337;
+
+       ret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData));
+       len = sizeof(answerPacket) - 1; /* Skip extra null character */
+
+       fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
+       fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
+}
+END_TEST
+
+START_TEST(test_decode_response)
+{
+       char buf[512];
+       int len;
+       int ret;
+
+       len = sizeof(buf);
+       memset(&buf, 0, sizeof(buf));
+
+       ret = dns_decode(buf, len, NULL, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
+       fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
+       fail_unless(ret == strlen(msgData), va_str("Bad data length: %d, expected %d", ret, strlen(msgData)));
+}
+END_TEST
+
+static void
+dump_packet(char *buf, size_t len)
+{
+       int pos;
+
+       for (pos = 0; pos < len; pos++) {
+               printf("\\x%02X", (unsigned char) buf[pos]);
+       }
+       printf("\n");
+       for (pos = 0; pos < len; pos++) {
+               if (isalnum((unsigned char) buf[pos])) {
+                       printf(" %c  ", (unsigned char) buf[pos]);
+               } else {
+                       printf("    ");
+               }
+       }
+       printf("\n");
+}
+
+TCase *
+test_dns_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("Dns");
+       tcase_add_test(tc, test_encode_query);
+       tcase_add_test(tc, test_decode_query);
+       tcase_add_test(tc, test_encode_response);
+       tcase_add_test(tc, test_decode_response);
+
+       return tc;
+}
diff --git a/tests/encoding.c b/tests/encoding.c
new file mode 100644 (file)
index 0000000..dcde87b
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "encoding.h"
+#include "test.h"
+
+START_TEST(test_encoding_base32)
+{
+       char temp[256];
+       char *start = "HELLOTEST";
+       char *out = "1HELLOTEST";
+       char end[256];
+       char *tempend;
+       int codedlength;
+
+       memset(temp, 0, sizeof(temp));
+       memset(end, 0, sizeof(end));
+
+       codedlength = encode_data(start, strlen(start), sizeof(temp) - 1, temp + 1);
+       temp[0] = '1';
+       tempend = temp + strlen(temp);
+       decode_data(end, sizeof(end), temp, tempend);
+
+       fail_unless(strcmp(out, end) == 0, NULL);
+}
+END_TEST
+
+TCase *
+test_encoding_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("Encoding");
+       tcase_add_test(tc, test_encoding_base32);
+
+       return tc;
+}
diff --git a/tests/login.c b/tests/login.c
new file mode 100644 (file)
index 0000000..cad9b9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <string.h>
+
+#include "test.h"
+#include "login.h"
+
+START_TEST(test_login_hash)
+{
+       char ans[16];
+       char good[] = "\x2A\x8A\x12\xB4\xE0\x42\xEE\xAB\xD0\x19\x17\x1E\x44\xA0\x88\xCD";
+       char pass[32] = "iodine is the shit";
+       int len;
+       int seed;
+
+       len = 16;
+       seed = 15;
+
+       memset(ans, 0, sizeof(ans));
+       login_calculate(ans, len, pass, seed);
+       fail_unless(strncmp(ans, good, len) == 0, NULL);
+}
+END_TEST
+
+TCase *
+test_login_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("Login");
+       tcase_add_test(tc, test_login_hash);
+
+       return tc;
+}
diff --git a/tests/read.c b/tests/read.c
new file mode 100644 (file)
index 0000000..e0e4472
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <arpa/nameser.h>
+#ifdef DARWIN
+#include <arpa/nameser8_compat.h>
+#endif
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+
+#include "common.h"
+#include "encoding.h"
+#include "dns.h"
+#include "read.h"
+#include "test.h"
+       
+START_TEST(test_read_putshort)
+{
+       unsigned short k;
+       unsigned short l;
+       char* p;
+       int i;
+
+       for (i = 0; i < 65536; i++) {
+               p = (char*)&k;
+               putshort(&p, i);
+               fail_unless(ntohs(k) == i, 
+                               va_str("Bad value on putshort for %d: %d != %d", 
+                                       i, ntohs(k), i));
+
+               p = (char*)&k;
+               readshort(NULL, &p, (short *) &l);
+               fail_unless(l == i,
+                               va_str("Bad value on readshort for %d: %d != %d", 
+                                       i, l, i));
+       }
+}
+END_TEST
+
+START_TEST(test_read_putlong)
+{
+       uint32_t k;
+       uint32_t l;
+       char* p;
+       int i;
+       int j;
+
+       for (i = 0; i < 32; i++) {
+               p = (char*)&k;
+               j = 0xf << i;
+
+               putlong(&p, j);
+
+               fail_unless(ntohl(k) == j, 
+                               va_str("Bad value on putlong for %d: %d != %d", i, ntohl(j), j));
+               
+               p = (char*)&k;
+               readlong(NULL, &p, &l);
+
+               fail_unless(l == j,
+                               va_str("Bad value on readlong for %d: %d != %d", i, l, j));
+       }
+}
+END_TEST
+
+START_TEST(test_read_name)
+{
+       unsigned char emptyloop[] = {
+               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 
+       unsigned char infloop[] = {
+               'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 }; 
+       unsigned char longname[] = 
+               "AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
+               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
+               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
+               "\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
+               "\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);
+
+       memset(buf, 0, sizeof(buf));
+       data = (char*) onejump + sizeof(HEADER);
+       rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);
+       fail_unless(rv == 9, NULL);
+       
+       /* These two tests use malloc to cause segfault if jump is executed */
+       memset(buf, 0, sizeof(buf));
+       jumper = malloc(sizeof(badjump));
+       if (jumper) {
+               memcpy(jumper, badjump, sizeof(badjump));
+               data = (char*) jumper + sizeof(HEADER);
+               rv = readname((char*) jumper, sizeof(badjump), &data, buf, 256);
+
+               fail_unless(rv == 0, NULL);
+               fail_unless(buf[0] == 0, NULL);
+       }
+       free(jumper);
+       
+       memset(buf, 0, sizeof(buf));
+       jumper = malloc(sizeof(badjump2));
+       if (jumper) {
+               memcpy(jumper, badjump2, sizeof(badjump2));
+               data = (char*) jumper + sizeof(HEADER);
+               rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
+
+               fail_unless(rv == 4, NULL);
+               fail_unless(strcmp("BA.", buf) == 0, 
+                               va_str("buf is not BA: %s", buf));
+       }
+       free(jumper);
+}
+END_TEST
+
+START_TEST(test_putname)
+{
+       char out[] = "\x06" "BADGER\x06" "BADGER\x04" "KRYO\x02" "SE\x00";
+       char buf[256];
+       char *domain = "BADGER.BADGER.KRYO.SE";
+       char *b;
+       int len;
+       int ret;
+
+       len = 256;
+
+       memset(buf, 0, 256);
+       b = buf;
+       ret = putname(&b, 256, domain);
+
+       fail_unless(ret == strlen(domain) + 1, NULL);
+       fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
+}
+END_TEST
+       
+START_TEST(test_putname_nodot)
+{
+       char buf[256];
+       char *nodot = 
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       char *b;
+       int len;
+       int ret;
+
+       len = 256;
+
+       memset(buf, 0, 256);
+       b = buf;
+       ret = putname(&b, 256, nodot);
+
+       fail_unless(ret == -1, NULL);
+       fail_unless(b == buf, NULL);
+}
+END_TEST
+       
+START_TEST(test_putname_toolong)
+{
+       char buf[256];
+       char *toolong = 
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.";
+       char *b;
+       int len;
+       int ret;
+
+       len = 256;
+
+       memset(buf, 0, 256);
+       b = buf;
+       ret = putname(&b, 256, toolong);
+
+       fail_unless(ret == -1, NULL);
+       fail_unless(b == buf, NULL);
+}
+END_TEST
+
+
+TCase *
+test_read_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("Read");
+       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_putname);
+       tcase_add_test(tc, test_putname_nodot);
+       tcase_add_test(tc, test_putname_toolong);
+
+       return tc;
+}
diff --git a/tests/test.c b/tests/test.c
new file mode 100644 (file)
index 0000000..850d1f7
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test.h"
+
+char *
+va_str(const char *fmt, ...)
+{
+       static char buf[512];
+       va_list ap;
+
+       memset(buf, 0, sizeof(buf));
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);   
+       va_end(ap);
+
+       return buf;
+}
+
+int
+main()
+{
+       SRunner *runner;
+       Suite *iodine;
+       TCase *test;
+       int failed;
+
+       iodine = suite_create("iodine");
+
+       test = test_base32_create_tests();
+       suite_add_tcase(iodine, test);
+
+       test = test_dns_create_tests();
+       suite_add_tcase(iodine, test);
+
+       test = test_encoding_create_tests();
+       suite_add_tcase(iodine, test);
+
+       test = test_read_create_tests();
+       suite_add_tcase(iodine, test);
+
+       test = test_login_create_tests();
+       suite_add_tcase(iodine, test);
+
+       test = test_user_create_tests();
+       suite_add_tcase(iodine, test);
+
+       runner = srunner_create(iodine);
+       srunner_run_all(runner, CK_VERBOSE);
+       failed = srunner_ntests_failed(runner);
+
+       srunner_free(runner);
+
+       return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/test.h b/tests/test.h
new file mode 100644 (file)
index 0000000..492cd9b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __TEST_H__
+#define __TEST_H__
+
+TCase *test_base32_create_tests();
+TCase *test_dns_create_tests();
+TCase *test_encoding_create_tests();
+TCase *test_read_create_tests();
+TCase *test_login_create_tests();
+TCase *test_user_create_tests();
+
+char *va_str(const char *, ...);
+       
+#if (CHECK_MAJOR_VERSION == 0 && \
+       ((CHECK_MINOR_VERSION == 9 && CHECK_MICRO_VERSION < 2) || \
+        (CHECK_MINOR_VERSION < 9)))
+#define tcase_set_timeout(...) 
+#endif
+
+#endif
diff --git a/tests/user.c b/tests/user.c
new file mode 100644 (file)
index 0000000..8f3ee84
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <check.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "common.h"
+#include "user.h"
+#include "test.h"
+
+START_TEST(test_init_users)
+{
+       in_addr_t ip;
+       char givenip[16];
+       int i;
+
+       ip = inet_addr("127.0.0.1");
+       init_users(ip);
+       for (i = 0; i < USERS; i++) {
+               fail_unless(users[i].id == i);
+               fail_unless(users[i].q.id == 0);
+               fail_unless(users[i].inpacket.len == 0);
+               fail_unless(users[i].outpacket.len == 0);
+               snprintf(givenip, sizeof(givenip), "127.0.0.%d", i + 2);
+               fail_unless(users[i].tun_ip == inet_addr(givenip));
+       }
+}
+END_TEST
+
+START_TEST(test_users_waiting)
+{
+       in_addr_t ip;
+
+       ip = inet_addr("127.0.0.1");
+       init_users(ip);
+
+       fail_unless(users_waiting_on_reply() == 0);
+
+       users[3].active = 1;
+
+       fail_unless(users_waiting_on_reply() == 0);
+
+       users[3].last_pkt = time(NULL);
+       
+       fail_unless(users_waiting_on_reply() == 0);
+       
+       users[3].q.id = 1;
+       
+       fail_unless(users_waiting_on_reply() == 1);
+}
+END_TEST
+
+START_TEST(test_find_user_by_ip)
+{
+       in_addr_t ip;
+       unsigned int testip;
+
+       ip = inet_addr("127.0.0.1");
+       init_users(ip);
+
+       testip = (unsigned int) inet_addr("10.0.0.1");
+       fail_unless(find_user_by_ip(testip) == -1);
+       
+       testip = (unsigned int) inet_addr("127.0.0.2");
+       fail_unless(find_user_by_ip(testip) == -1);
+       
+       users[0].active = 1;
+       
+       testip = (unsigned int) inet_addr("127.0.0.2");
+       fail_unless(find_user_by_ip(testip) == -1);
+       
+       users[0].last_pkt = time(NULL);
+       
+       testip = (unsigned int) inet_addr("127.0.0.2");
+       fail_unless(find_user_by_ip(testip) == 0);
+}
+END_TEST
+
+START_TEST(test_all_users_waiting_to_send)
+{
+       in_addr_t ip;
+
+       ip = inet_addr("127.0.0.1");
+       init_users(ip);
+
+       fail_unless(all_users_waiting_to_send() == 1);
+       
+       users[0].active = 1;
+       
+       fail_unless(all_users_waiting_to_send() == 1);
+       
+       users[0].last_pkt = time(NULL);
+       
+       fail_unless(all_users_waiting_to_send() == 0);
+
+       users[0].outpacket.len = 44;
+       
+       fail_unless(all_users_waiting_to_send() == 1);
+}
+END_TEST
+
+START_TEST(test_find_available_user)
+{
+       in_addr_t ip;
+       int i;
+
+       ip = inet_addr("127.0.0.1");
+       init_users(ip);
+
+       for (i = 0; i < USERS; i++) {
+               fail_unless(find_available_user() == i);
+       }
+
+       for (i = 0; i < USERS; i++) {
+               fail_unless(find_available_user() == -1);
+       }
+
+       users[3].active = 0;
+
+       fail_unless(find_available_user() == 3);
+       fail_unless(find_available_user() == -1);
+
+       users[3].last_pkt = 55;
+       
+       fail_unless(find_available_user() == 3);
+       fail_unless(find_available_user() == -1);
+}
+END_TEST
+
+TCase *
+test_user_create_tests()
+{
+       TCase *tc;
+
+       tc = tcase_create("User");
+       tcase_add_test(tc, test_init_users);
+       tcase_add_test(tc, test_users_waiting);
+       tcase_add_test(tc, test_find_user_by_ip);
+       tcase_add_test(tc, test_all_users_waiting_to_send);
+       tcase_add_test(tc, test_find_available_user);
+
+       return tc;
+}
diff --git a/tun.c b/tun.c
deleted file mode 100644 (file)
index 0f5cef0..0000000
--- a/tun.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <err.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include "tun.h"
-
-#define TUN_MAX_TRY 50
-
-char if_name[50];
-
-#ifdef LINUX
-
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <linux/if_tun.h>
-
-int 
-open_tun(const char *tun_device) 
-{
-       int i;
-       int tun_fd;
-       struct ifreq ifreq;
-       char *tunnel = "/dev/net/tun";
-
-       if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
-               warn("open_tun: %s: %s", tunnel, strerror(errno));
-               return -1;
-       }
-
-       memset(&ifreq, 0, sizeof(ifreq));
-
-       ifreq.ifr_flags = IFF_TUN; 
-
-       if (tun_device != NULL) {
-               strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
-               strncpy(if_name, tun_device, sizeof(if_name));
-
-               if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
-                       printf("Opened %s\n", ifreq.ifr_name);
-                       return tun_fd;
-               }
-
-               if (errno != EBUSY) {
-                       warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
-                       return -1;
-               }
-       } else {
-               for (i = 0; i < TUN_MAX_TRY; i++) {
-                       snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
-
-                       if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
-                               printf("Opened %s\n", ifreq.ifr_name);
-                               snprintf(if_name, sizeof(if_name), "dns%d", i);
-                               return tun_fd;
-                       }
-
-                       if (errno != EBUSY) {
-                               warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
-                               return -1;
-                       }
-               }
-
-               warn("open_tun: Couldn't set interface name");
-       }
-       return -1;
-}
-
-#else /* BSD */
-
-int 
-open_tun(const char *tun_device) 
-{
-       int i;
-       int tun_fd;
-       char tun_name[50];
-
-       if (tun_device != NULL) {
-               snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
-               strncpy(if_name, tun_device, sizeof(if_name));
-
-               if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
-                       warn("open_tun: %s: %s", tun_name, strerror(errno));
-                       return -1;
-               }
-
-               printf("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);
-                               snprintf(if_name, sizeof(if_name), "tun%d", i);
-                               return tun_fd;
-                       }
-
-                       if (errno == ENOENT)
-                               break;
-               }
-
-               warn("open_tun: Failed to open tunneling device");
-       }
-
-       return -1;
-}
-
-#endif /* !LINUX */
-
-void 
-close_tun(int tun_fd) 
-{
-       if (tun_fd >= 0)
-               close(tun_fd);
-}
-
-int 
-write_tun(int tun_fd, char *data, int len) 
-{
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
-       data += 4;
-       len -= 4;
-#else /* !FREEBSD/DARWIN */
-#ifdef LINUX
-       data[0] = 0x00;
-       data[1] = 0x00;
-       data[2] = 0x08;
-       data[3] = 0x00;
-#else /* OPENBSD */
-       data[0] = 0x00;
-       data[1] = 0x00;
-       data[2] = 0x00;
-       data[3] = 0x02;
-#endif /* !LINUX */
-#endif /* FREEBSD */
-
-       if (write(tun_fd, data, len) != len) {
-               warn("write_tun");
-               return 1;
-       }
-       return 0;
-}
-
-int 
-read_tun(int tun_fd, char *buf, int len) 
-{
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
-       // FreeBSD has no header
-       return read(tun_fd, buf + 4, len - 4) + 4;
-#else /* !FREEBSD */
-       return read(tun_fd, buf, len);
-#endif /* !FREEBSD */
-}
-
-int
-tun_setip(const char *ip)
-{
-       char cmdline[512];
-
-       if (inet_addr(ip) != INADDR_NONE) {
-               snprintf(cmdline, sizeof(cmdline), 
-                               "/sbin/ifconfig %s %s %s netmask 255.255.255.0",
-                               if_name,
-                               ip,
-                               ip);
-               
-               printf("Setting IP of %s to %s\n", if_name, ip);
-#ifndef LINUX
-               int r;
-
-               r = system(cmdline);
-               if(r != 0) {
-                       return r;
-               } else {
-                       snprintf(cmdline, sizeof(cmdline),
-                                       "/sbin/route add %s/24 %s",
-                                       ip, ip);
-               }
-               printf("Adding route %s/24 to %s\n", ip, ip);
-#endif
-               return system(cmdline);
-       } else {
-               printf("Invalid IP: %s!\n", ip);
-       }
-
-       return 1;
-}
-
-int 
-tun_setmtu(const int mtu)
-{
-       char cmdline[512];
-
-       if (mtu > 200 && mtu < 1500) {
-               snprintf(cmdline, sizeof(cmdline), 
-                               "/sbin/ifconfig %s mtu %d",
-                               if_name,
-                               mtu);
-               
-               printf("Setting MTU of %s to %d\n", if_name, mtu);
-               return system(cmdline);
-       } else {
-               warn("MTU out of range: %d\n", mtu);
-       }
-
-       return 1;
-}
-
diff --git a/tun.h b/tun.h
deleted file mode 100644 (file)
index 0a32dcd..0000000
--- a/tun.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2006 
- * Bjorn Andersson <flex@kryo.se>,
- * Erik Ekman <yarrick@kryo.se>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _TUN_H_
-#define _TUN_H_
-
-int open_tun(const char *);
-void close_tun(int);
-int write_tun(int, char *, int);
-int read_tun(int, char *, int);
-int tun_setip(const char *);
-int tun_setmtu(const int);
-
-#endif /* _TUN_H_ */