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