Release 0.5.1

This commit is contained in:
Erik Ekman 2009-03-21 13:07:49 +00:00
parent f41c4bb9f3
commit 6536fc7c5d
28 changed files with 1444 additions and 401 deletions

View File

@ -5,6 +5,21 @@ iodine - http://code.kryo.se/iodine
CHANGES:
2009-03-21: 0.5.1 "Boringo"
- Added initial Windows support, fixes #43.
- Added length check of autoprobe responses
- Refactored and added unit tests
- Added syslog logging for iodined on version and login packets
- Fixed segfault when encoding just one block, fixes #51.
The normal code was never affected by this.
- Added win32 code to read DNS server from system, fixes #45.
- Disabled password echo on win32, fixes #44.
- Fix encoding error making all autoprobing > 1024 bytes fail, #52.
- Increase default interface MTU to 1200.
- Fix autoprobing error making every third probe fail, set IP flag
Dont-Fragment where supported. Fixes #54.
- Added TAP32 version 0901 as accepted (#53).
2009-01-23: 0.5.0 "iPassed"
- Fixed segfault in server when sending version reject.
- Applied patch to make iodine build on BeOS R5-BONE and Haiku,

View File

@ -14,8 +14,25 @@ MKDIR_FLAGS=-p
RM=rm
RM_FLAGS=-f
TARGETOS = `uname`
all:
@(cd src; $(MAKE) all)
@(cd src; $(MAKE) TARGETOS=$(TARGETOS) all)
cross-mingw:
@(cd src; $(MAKE) TARGETOS=windows32 CC=i686-mingw32-gcc all)
cross-mingw-dist: cross-mingw
@rm -rf iodine-latest-win32*
@mkdir -p iodine-latest-win32/bin
@for i in `ls bin`; do cp bin/$$i iodine-latest-win32/bin/$$i.exe; done
@cp /usr/i686-mingw32/usr/bin/zlib1.dll iodine-latest-win32/bin
@cp README* CH* TO* iodine-latest-win32
@echo "Create date: " > iodine-latest-win32/VERSION
@date >> iodine-latest-win32/VERSION
@echo "SVN version: " >> iodine-latest-win32/VERSION
@svnversion >> iodine-latest-win32/VERSION
@zip -r iodine-latest-win32.zip iodine-latest-win32
install: all
$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
@ -35,11 +52,11 @@ uninstall:
test: all
@echo "!! The check library is required for compiling and running the tests"
@echo "!! Get it at http://check.sf.net"
@(cd tests; $(MAKE) all)
@(cd tests; $(MAKE) TARGETOS=$(TARGETOS) all)
clean:
@echo "Cleaning..."
@(cd src; $(MAKE) clean)
@(cd tests; $(MAKE) clean)
@rm -rf bin
@rm -rf bin iodine-latest-win32*

62
README-win32.txt Normal file
View File

@ -0,0 +1,62 @@
iodine - http://code.kryo.se/iodine
***********************************
Extra README file for Win32 related stuff
== Running iodine on Windows:
1. Install the TAP32 driver
http://openvpn.net/index.php/downloads.html
choose OpenVPN 2.0.9 Windows Installer, when installing you can
select to install only the TAP driver.
2. Have one TAP32 interface installed
3. Name the interface "dns"
4. Make sure the interface does not have a default gateway set
5. Run iodine/iodined as normal.
6. Enjoy!
== Building on Windows:
You need:
MinGW, MSYS, GCC, zlib
Then just run make
== Cross-compiling for MinGW:
You need:
MinGW crosscompiler, crosscompiled zlib
Then run "make cross-mingw"
Note that the binaries will not get a .exe suffix
== Zlib download
You can get zlib for MinGW here (both for native and crosscompile):
http://code.kryo.se/iodine/deps/zlib.zip
Unzip it in your MinGW directory on Windows or in $ROOT/usr for
cross-compile.
== Results of crappy Win32 API:
The following fixable limitations apply:
- Exactly one TAP32 interface must be installed
- The TAP32 interface must be named "dns" and be version 0801 or 0901
- Server cannot read packet destination address
The following (probably) un-fixable limitations apply:
- A password entered as -P argument can be shown in process list
- Priviligies cannot be dropped
- chroot() cannot be used
- Detaching from terminal not possible
- Server on windows must be run with /30 netmask
- Client can only talk to server, not other clients

View File

@ -5,11 +5,12 @@ CLIENT = ../bin/iodine
SERVEROBJS = iodined.o user.o fw_query.o
SERVER = ../bin/iodined
OS = `uname | tr "a-z" "A-Z"`
OS = `echo $(TARGETOS) | tr "a-z" "A-Z"`
ARCH = `uname -m`
LDFLAGS = -lz `sh osflags link`
CFLAGS = -c -g -Wall -D$(OS) -pedantic `sh osflags cflags`
LIBPATH = -L.
LDFLAGS = -lz `sh osflags $(TARGETOS) link` $(LIBPATH)
CFLAGS = -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags`
all: stateos $(CLIENT) $(SERVER)
@ -32,5 +33,5 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
clean:
@echo "Cleaning src/"
@rm -f $(CLIENT) $(SERVER) *~ *.o *.core
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core

View File

@ -27,7 +27,6 @@
static const char cb32[] =
"abcdefghijklmnopqrstuvwxyz012345";
static unsigned char rev32[128];
static int reverse_init = 0;
static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_encode(char *, size_t *, const void *, size_t);
@ -70,6 +69,22 @@ base32_blksize_enc()
return BLKSIZE_ENC;
}
static void
base32_reverse_init()
{
int i;
unsigned char c;
static int reverse_init = 0;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
}
int
b32_5to8(int in)
{
@ -79,15 +94,7 @@ b32_5to8(int in)
int
b32_8to5(int in)
{
int i;
int c;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
base32_reverse_init();
return rev32[in];
}
@ -103,9 +110,12 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
memset(buf, 0, *buflen);
/* how many chars can we encode within the buf */
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
/* how big will the encoded data be */
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
if (size % BLKSIZE_RAW) {
newsize += BLKSIZE_ENC;
}
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
@ -132,7 +142,7 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf) - 1;
return strlen(buf);
}
#define DECODE_ERROR 0xffffffff
@ -183,17 +193,9 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
size_t newsize;
size_t maxsize;
const char *p;
unsigned char c;
int len;
int i;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
base32_reverse_init();
/* chars needed to decode slen */
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;

View File

@ -78,7 +78,6 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
{
size_t newsize;
size_t maxsize;
unsigned char c;
unsigned char *s;
unsigned char *p;
unsigned char *q;
@ -86,18 +85,14 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
memset(buf, 0, *buflen);
if (!reverse_init) {
for (i = 0; i < 64; i++) {
c = cb64[i];
rev64[(int) c] = i;
}
reverse_init = 1;
/* how many chars can we encode within the buf */
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
/* how big will the encoded data be */
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
if (size % BLKSIZE_RAW) {
newsize += BLKSIZE_ENC;
}
/* how many chars can we encode within the buf */
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
/* how big will the encoded data be */
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
@ -120,7 +115,7 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf) - 1;
return strlen(buf);
}
#define DECODE_ERROR 0xffffffff

View File

@ -14,14 +14,7 @@
* 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>
@ -33,12 +26,25 @@
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef WINDOWS32
#include <winsock2.h>
#include <conio.h>
#else
#include <arpa/nameser.h>
#ifdef DARWIN
#include <arpa/nameser8_compat.h>
#endif
#include <termios.h>
#include <err.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include "common.h"
/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
#if !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
#if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
static int daemon(int nochdir, int noclose)
{
int fd, i;
@ -82,11 +88,24 @@ int setgroups(int count, int *groups)
}
#endif
void
check_superuser(void (*usage_fn)(void))
{
#ifndef WINDOWS32
if (geteuid() != 0) {
warnx("Run as root and you'll be happy.\n");
usage_fn();
/* NOTREACHED */
}
#endif
}
int
open_dns(int localport, in_addr_t listen_ip)
{
struct sockaddr_in addr;
int flag;
int flag = 1;
int fd;
memset(&addr, 0, sizeof(addr));
@ -95,22 +114,32 @@ open_dns(int localport, in_addr_t listen_ip)
/* listen_ip already in network byte order from inet_addr, or 0 */
addr.sin_addr.s_addr = listen_ip;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
fprintf(stderr, "got fd %d\n", fd);
err(1, "socket");
}
flag = 1;
#ifdef SO_REUSEPORT
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));
#endif
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
#ifndef WINDOWS32
/* To get destination address from each UDP datagram, see iodined.c:read_dns() */
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, &flag, sizeof(flag));
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
#endif
#ifdef IP_OPT_DONT_FRAG
/* Set dont-fragment ip header flag */
flag = DONT_FRAG_VALUE;
setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
#endif
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
err(1, "bind");
printf("Opened UDP socket\n");
fprintf(stderr, "Opened UDP socket\n");
return fd;
}
@ -124,7 +153,7 @@ close_dns(int fd)
void
do_chroot(char *newroot)
{
#if !defined(__BEOS__) || defined(__HAIKU__)
#if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))
if (chroot(newroot) != 0 || chdir("/") != 0)
err(1, "%s", newroot);
@ -138,31 +167,54 @@ do_chroot(char *newroot)
void
do_detach()
{
printf("Detaching from terminal...\n");
#ifndef WINDOWS32
fprintf(stderr, "Detaching from terminal...\n");
daemon(0, 0);
umask(0);
alarm(0);
#else
fprintf(stderr, "Windows version does not support detaching\n");
#endif
}
void
read_password(char *buf, size_t len)
{
char pwd[80];
#ifndef WINDOWS32
struct termios old;
struct termios tp;
char pwd[80];
tcgetattr(0, &tp);
old = tp;
tp.c_lflag &= (~ECHO);
tcsetattr(0, TCSANOW, &tp);
#else
int i;
#endif
printf("Enter password: ");
fflush(stdout);
fprintf(stderr, "Enter password: ");
fflush(stderr);
#ifndef WINDOWS32
scanf("%79s", pwd);
printf("\n");
#else
for (i = 0; i < sizeof(pwd); i++) {
pwd[i] = getch();
if (pwd[i] == '\r' || pwd[i] == '\n') {
pwd[i] = 0;
break;
} else if (pwd[i] == '\b') {
i--; /* Remove the \b char */
if (i >=0) i--; /* If not first char, remove one more */
}
}
#endif
fprintf(stderr, "\n");
#ifndef WINDOWS32
tcsetattr(0, TCSANOW, &old);
#endif
strncpy(buf, pwd, len);
buf[len-1] = '\0';
@ -184,3 +236,61 @@ check_topdomain(char *str)
}
return 0;
}
#ifdef WINDOWS32
int
inet_aton(const char *cp, struct in_addr *inp)
{
inp->s_addr = inet_addr(cp);
return inp->s_addr != INADDR_ANY;
}
void
warn(const char *fmt, ...)
{
va_list list;
va_start(list, fmt);
if (fmt) fprintf(stderr, fmt, list);
if (errno == 0) {
fprintf(stderr, ": WSA error %d\n", WSAGetLastError());
} else {
fprintf(stderr, ": %s\n", strerror(errno));
}
va_end(list);
}
void
warnx(const char *fmt, ...)
{
va_list list;
va_start(list, fmt);
if (fmt) fprintf(stderr, fmt, list);
fprintf(stderr, "\n");
va_end(list);
}
void
err(int eval, const char *fmt, ...)
{
va_list list;
va_start(list, fmt);
warn(fmt, list);
va_end(list);
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list list;
va_start(list, fmt);
warnx(fmt, list);
va_end(list);
exit(eval);
}
#endif

View File

@ -17,10 +17,15 @@
#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))
@ -39,6 +44,20 @@
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
#endif
#if defined IP_MTU_DISCOVER
/* Linux */
# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER
# define DONT_FRAG_VALUE IP_PMTUDISC_DO
#elif defined IP_DONTFRAG
/* FreeBSD */
# define IP_OPT_DONT_FRAG IP_DONTFRAG
# define DONT_FRAG_VALUE 1
#elif defined IP_DONTFRAGMENT
/* Winsock2 */
# define IP_OPT_DONT_FRAG IP_DONTFRAGMENT
# define DONT_FRAG_VALUE 1
#endif
struct packet
{
int len; /* Total packet length */
@ -58,6 +77,7 @@ struct query {
int fromlen;
};
void check_superuser(void (*usage_fn)(void));
int open_dns(int, in_addr_t);
void close_dns(int);
@ -68,4 +88,13 @@ void read_password(char*, size_t);
int check_topdomain(char *);
#ifdef WINDOWS32
int inet_aton(const char *cp, struct in_addr *inp);
void err(int eval, const char *fmt, ...);
void warn(const char *fmt, ...);
void errx(int eval, const char *fmt, ...);
void warnx(const char *fmt, ...);
#endif
#endif

View File

@ -14,13 +14,7 @@
* 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>
@ -28,6 +22,18 @@
#include <string.h>
#include <ctype.h>
#ifdef WINDOWS32
#include "windows.h"
#else
#include <arpa/nameser.h>
#ifdef DARWIN
#include <arpa/nameser8_compat.h>
#endif
#include <arpa/inet.h>
#include <err.h>
#endif
#include "dns.h"
#include "encoding.h"
#include "read.h"
@ -177,7 +183,7 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
return len;
}
short
unsigned short
dns_get_id(char *packet, size_t packetlen)
{
HEADER *header;

View File

@ -26,7 +26,7 @@ typedef enum {
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain);
short dns_get_id(char *packet, size_t packetlen);
unsigned short dns_get_id(char *packet, size_t packetlen);
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
#endif /* _DNS_H_ */

View File

@ -35,7 +35,7 @@ void fw_query_put(struct fw_query *fw_query)
fwq_ix = 0;
}
void fw_query_get(short query_id, struct fw_query **fw_query)
void fw_query_get(unsigned short query_id, struct fw_query **fw_query)
{
int i;

View File

@ -18,19 +18,24 @@
#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__*/

View File

@ -20,22 +20,28 @@
#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"
@ -46,6 +52,11 @@
#include "tun.h"
#include "version.h"
#ifdef WINDOWS32
WORD req_version = MAKEWORD(2, 2);
WSADATA wsa_data;
#endif
static void send_ping(int fd);
static void send_chunk(int fd);
static int build_hostname(char *buf, size_t buflen,
@ -64,9 +75,6 @@ static int downstream_fragment;
static int down_ack_seqno;
static int down_ack_fragment;
static int max_downstream_frag_size;
static int autodetect_frag_size;
/* Current up/downstream IP packet */
static struct packet outpkt;
static struct packet inpkt;
@ -132,7 +140,7 @@ build_hostname(char *buf, size_t buflen,
size_t space;
char *b;
space = MIN(0xFF, buflen) - strlen(topdomain) - 5;
space = MIN(0xFF, buflen) - strlen(topdomain) - 7;
if (!encoder->places_dots())
space -= (space / 57); /* space for dots */
@ -424,7 +432,7 @@ send_fragsize_probe(int fd, int fragsize)
fragsize &= 2047;
buf[0] = 'r'; /* Probe downstream fragsize packet */
buf[1] = b32_5to8((userid << 1) | (fragsize & 1024));
buf[1] = b32_5to8((userid << 1) | ((fragsize >> 10) & 1));
buf[2] = b32_5to8((fragsize >> 5) & 31);
buf[3] = b32_5to8(fragsize & 31);
@ -487,22 +495,17 @@ send_codec_switch(int fd, int userid, int bits)
strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf);
}
static int
handshake(int dns_fd)
handshake_version(int dns_fd, int *seed)
{
struct timeval tv;
uint32_t payload;
char server[65];
char client[65];
char login[16];
char in[4096];
fd_set fds;
int read;
int mtu;
int seed;
uint32_t payload;
int i;
int r;
int read;
for (i = 0; running && i < 5; i++) {
tv.tv_sec = i + 1;
@ -533,11 +536,11 @@ handshake(int dns_fd)
((in[7] & 0xff)));
if (strncmp("VACK", in, 4) == 0) {
seed = payload;
*seed = payload;
userid = in[8];
printf("Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid);
goto perform_login;
fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid);
return 0;
} else if (strncmp("VNAK", in, 4) == 0) {
warnx("You use protocol v 0x%08x, server uses v 0x%08x. Giving up",
VERSION, payload);
@ -550,12 +553,26 @@ handshake(int dns_fd)
warnx("did not receive proper login challenge");
}
printf("Retrying version check...\n");
fprintf(stderr, "Retrying version check...\n");
}
errx(1, "couldn't connect to server");
/* NOTREACHED */
perform_login:
warnx("couldn't connect to server");
return 1;
}
static int
handshake_login(int dns_fd, int seed)
{
struct timeval tv;
char in[4096];
char login[16];
char server[65];
char client[65];
int mtu;
fd_set fds;
int i;
int r;
int read;
login_calculate(login, 16, password, seed);
for (i=0; running && i<5 ;i++) {
@ -580,7 +597,7 @@ perform_login:
if (read > 0) {
int netmask;
if (strncmp("LNAK", in, 4) == 0) {
printf("Bad password\n");
fprintf(stderr, "Bad password\n");
return 1;
} else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d",
server, client, &mtu, &netmask) == 4) {
@ -589,22 +606,32 @@ perform_login:
client[64] = 0;
if (tun_setip(client, netmask) == 0 &&
tun_setmtu(mtu) == 0) {
goto perform_case_check;
return 0;
} else {
warnx("Received handshake with bad data");
}
} else {
printf("Received bad handshake\n");
fprintf(stderr, "Received bad handshake\n");
}
}
}
printf("Retrying login...\n");
fprintf(stderr, "Retrying login...\n");
}
warnx("couldn't login to server");
return 1;
}
static void
handshake_case_check(int dns_fd)
{
struct timeval tv;
char in[4096];
fd_set fds;
int i;
int r;
int read;
perform_case_check:
case_preserved = 0;
for (i=0; running && i<5 ;i++) {
tv.tv_sec = i + 1;
@ -623,8 +650,8 @@ perform_case_check:
if (read > 0) {
if (in[0] == 'z' || in[0] == 'Z') {
if (read < (27 * 2)) {
printf("Received short case check reply. Will use base32 encoder\n");
goto switch_codec;
fprintf(stderr, "Received short case check reply. Will use base32 encoder\n");
return;
} else {
int k;
@ -636,27 +663,35 @@ perform_case_check:
case_preserved = 0;
}
}
goto switch_codec;
return;
}
} else {
printf("Received bad case check reply\n");
fprintf(stderr, "Received bad case check reply\n");
}
} else {
printf("Got error on case check, will use base32\n");
goto switch_codec;
fprintf(stderr, "Got error on case check, will use base32\n");
return;
}
}
printf("Retrying case check...\n");
fprintf(stderr, "Retrying case check...\n");
}
printf("No reply on case check, continuing\n");
switch_codec:
if (!case_preserved)
goto autodetect_max_fragsize;
fprintf(stderr, "No reply on case check, continuing\n");
}
static void
handshake_switch_codec(int dns_fd)
{
struct timeval tv;
char in[4096];
fd_set fds;
int i;
int r;
int read;
dataenc = get_base64_encoder();
printf("Switching to %s codec\n", dataenc->name);
fprintf(stderr, "Switching to %s codec\n", dataenc->name);
/* Send to server that this user will use base64 from now on */
for (i=0; running && i<5 ;i++) {
int bits;
@ -677,84 +712,120 @@ switch_codec:
if (read > 0) {
if (strncmp("BADLEN", in, 6) == 0) {
printf("Server got bad message length. ");
fprintf(stderr, "Server got bad message length. ");
goto codec_revert;
} else if (strncmp("BADIP", in, 5) == 0) {
printf("Server rejected sender IP address. ");
fprintf(stderr, "Server rejected sender IP address. ");
goto codec_revert;
} else if (strncmp("BADCODEC", in, 8) == 0) {
printf("Server rejected the selected codec. ");
fprintf(stderr, "Server rejected the selected codec. ");
goto codec_revert;
}
in[read] = 0; /* zero terminate */
printf("Server switched to codec %s\n", in);
goto autodetect_max_fragsize;
fprintf(stderr, "Server switched to codec %s\n", in);
return;
}
}
printf("Retrying codec switch...\n");
fprintf(stderr, "Retrying codec switch...\n");
}
printf("No reply from server on codec switch. ");
fprintf(stderr, "No reply from server on codec switch. ");
codec_revert:
printf("Falling back to base32\n");
fprintf(stderr, "Falling back to base32\n");
dataenc = get_base32_encoder();
autodetect_max_fragsize:
if (autodetect_frag_size) {
int proposed_fragsize = 768;
int range = 768;
max_downstream_frag_size = 0;
printf("Autoprobing max downstream fragment size... (skip with -m fragsize)\n");
while (running && range > 0 && (range >= 8 || !max_downstream_frag_size)) {
for (i=0; running && i<3 ;i++) {
tv.tv_sec = 1;
tv.tv_usec = 0;
send_fragsize_probe(dns_fd, proposed_fragsize);
}
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
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;
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
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);
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;
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;
fprintf(stderr, ".");
fflush(stderr);
}
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;
}
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;
}
printf("will use %d\n", max_downstream_frag_size);
}
printf("Setting downstream fragment size to max %d...\n", max_downstream_frag_size);
if (!running) {
fprintf(stderr, "\n");
warnx("stopped while autodetecting fragment size (Try probing manually with -m)");
return 0;
}
if (range == 0) {
/* Tried all the way down to 2 and found no good size */
fprintf(stderr, "\n");
warnx("found no accepted fragment size. (Try probing manually with -m)");
return 0;
}
fprintf(stderr, "will use %d\n", max_fragsize);
return max_fragsize;
}
static void
handshake_set_fragsize(int dns_fd, int fragsize)
{
struct timeval tv;
char in[4096];
fd_set fds;
int i;
int r;
int read;
fprintf(stderr, "Setting downstream fragment size to max %d...\n", fragsize);
for (i=0; running && i<5 ;i++) {
tv.tv_sec = i + 1;
tv.tv_usec = 0;
send_set_downstream_fragsize(dns_fd, max_downstream_frag_size);
send_set_downstream_fragsize(dns_fd, fragsize);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
@ -768,21 +839,53 @@ autodetect_max_fragsize:
int accepted_fragsize;
if (strncmp("BADFRAG", in, 7) == 0) {
printf("Server rejected fragsize. Keeping default.");
goto done;
fprintf(stderr, "Server rejected fragsize. Keeping default.");
return;
} else if (strncmp("BADIP", in, 5) == 0) {
printf("Server rejected sender IP address.\n");
goto done;
fprintf(stderr, "Server rejected sender IP address.\n");
return;
}
accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
goto done;
return;
}
}
printf("Retrying set fragsize...\n");
fprintf(stderr, "Retrying set fragsize...\n");
}
printf("No reply from server when setting fragsize. Keeping default.\n");
done:
fprintf(stderr, "No reply from server when setting fragsize. Keeping default.\n");
}
static int
handshake(int dns_fd, int autodetect_frag_size, int fragsize)
{
int seed;
int r;
r = handshake_version(dns_fd, &seed);
if (r) {
return r;
}
r = handshake_login(dns_fd, seed);
if (r) {
return r;
}
handshake_case_check(dns_fd);
if (case_preserved) {
handshake_switch_codec(dns_fd);
}
if (autodetect_frag_size) {
fragsize = handshake_autoprobe_fragsize(dns_fd);
if (!fragsize) {
return 1;
}
}
handshake_set_fragsize(dns_fd, fragsize);
return 0;
}
@ -790,8 +893,9 @@ static char *
get_resolvconf_addr()
{
static char addr[16];
char buf[80];
char *rv;
#ifndef WINDOWS32
char buf[80];
FILE *fp;
rv = NULL;
@ -809,7 +913,29 @@ get_resolvconf_addr()
}
fclose(fp);
#else /* !WINDOWS32 */
FIXED_INFO *fixed_info;
ULONG buflen;
DWORD ret;
rv = NULL;
fixed_info = malloc(sizeof(FIXED_INFO));
buflen = sizeof(FIXED_INFO);
if (GetNetworkParams(fixed_info, &buflen) == ERROR_BUFFER_OVERFLOW) {
/* official ugly api workaround */
free(fixed_info);
fixed_info = malloc(buflen);
}
ret = GetNetworkParams(fixed_info, &buflen);
if (ret == NO_ERROR) {
strncpy(addr, fixed_info->DnsServerList.IpAddress.String, sizeof(addr));
addr[15] = 0;
rv = addr;
}
free(fixed_info);
#endif
return rv;
}
@ -831,7 +957,7 @@ static void
usage() {
extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"[-P password] [-m maxfragsize] [nameserver] topdomain\n", __progname);
exit(2);
}
@ -840,19 +966,19 @@ static void
help() {
extern char *__progname;
printf("iodine IP over DNS tunneling client\n");
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
fprintf(stderr, "iodine IP over DNS tunneling client\n");
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"[-P password] [-m maxfragsize] [nameserver] topdomain\n", __progname);
printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n");
printf(" -f to keep running in foreground\n");
printf(" -u name to drop privileges and run as user 'name'\n");
printf(" -t dir to chroot to directory dir\n");
printf(" -d device to set tunnel device name\n");
printf(" -P password used for authentication (max 32 chars will be used)\n");
printf(" -m maxfragsize, to limit size of downstream packets\n");
printf("nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
fprintf(stderr, " -v to print version info and exit\n");
fprintf(stderr, " -h to print this help and exit\n");
fprintf(stderr, " -f to keep running in foreground\n");
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
fprintf(stderr, " -t dir to chroot to directory dir\n");
fprintf(stderr, " -d device to set tunnel device name\n");
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
fprintf(stderr, " -m maxfragsize, to limit size of downstream packets\n");
fprintf(stderr, "nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
exit(0);
}
@ -860,7 +986,7 @@ help() {
static void
version() {
printf("iodine IP over DNS tunneling client\n");
printf("version: 0.5.0 from 2009-01-23\n");
printf("version: 0.5.1 from 2009-03-21\n");
exit(0);
}
@ -869,7 +995,9 @@ int
main(int argc, char **argv)
{
char *nameserv_addr;
#ifndef WINDOWS32
struct passwd *pw;
#endif
char *username;
int foreground;
char *newroot;
@ -877,6 +1005,8 @@ main(int argc, char **argv)
int choice;
int tun_fd;
int dns_fd;
int max_downstream_frag_size;
int autodetect_frag_size;
memset(password, 0, 33);
username = NULL;
@ -893,6 +1023,10 @@ main(int argc, char **argv)
b32 = get_base32_encoder();
dataenc = get_base32_encoder();
#ifdef WINDOWS32
WSAStartup(req_version, &wsa_data);
#endif
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
@ -941,11 +1075,7 @@ main(int argc, char **argv)
}
}
if (geteuid() != 0) {
warnx("Run as root and you'll be happy.\n");
usage();
/* NOTREACHED */
}
check_superuser(usage);
argc -= optind;
argv += optind;
@ -985,11 +1115,13 @@ main(int argc, char **argv)
}
if (username != NULL) {
#ifndef WINDOWS32
if ((pw = getpwnam(username)) == NULL) {
warnx("User %s does not exist!\n", username);
usage();
/* NOTREACHED */
}
#endif
}
if (strlen(password) == 0)
@ -1003,10 +1135,10 @@ main(int argc, char **argv)
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
if(handshake(dns_fd))
if(handshake(dns_fd, autodetect_frag_size, max_downstream_frag_size))
goto cleanup2;
printf("Sending queries for %s to %s\n", topdomain, nameserv_addr);
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
if (foreground == 0)
do_detach();
@ -1015,6 +1147,7 @@ main(int argc, char **argv)
do_chroot(newroot);
if (username != NULL) {
#ifndef WINDOWS32
gid_t gids[1];
gids[0] = pw->pw_gid;
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
@ -1022,6 +1155,7 @@ main(int argc, char **argv)
usage();
/* NOTREACHED */
}
#endif
}
downstream_seqno = 0;

View File

@ -23,22 +23,30 @@
#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"
@ -52,6 +60,11 @@
#include "fw_query.h"
#include "version.h"
#ifdef WINDOWS32
WORD req_version = MAKEWORD(2, 2);
WSADATA wsa_data;
#endif
static int running = 1;
static char *topdomain;
static char password[33];
@ -81,6 +94,23 @@ sigint(int sig)
running = 0;
}
#ifdef WINDOWS32
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERR 3
#define LOG_WARNING 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
static void
syslog(int a, const char *str, ...)
{
/* TODO: implement (add to event log), move to common.c */
;
}
#endif
static int
check_user_and_ip(int userid, struct query *q)
{
@ -208,7 +238,7 @@ send_chunk(int dns_fd, int userid) {
((users[userid].outpacket.fragment & 15) << 1) | (last & 1);
if (debug >= 1) {
printf("OUT pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n",
fprintf(stderr, "OUT pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n",
users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15,
last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid);
}
@ -306,13 +336,19 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].encoder = get_base32_encoder();
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q);
syslog(LOG_INFO, "accepted version for user #%d from %s",
userid, inet_ntoa(tempin->sin_addr));
users[userid].q.id = 0;
} else {
/* No space for another user */
send_version_response(dns_fd, VERSION_FULL, created_users, 0, q);
syslog(LOG_INFO, "dropped user from %s, server full",
inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
}
} else {
send_version_response(dns_fd, VERSION_NACK, VERSION, 0, q);
syslog(LOG_INFO, "dropped user from %s, sent bad version %08X",
inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr), version);
}
return;
} else if(in[0] == 'L' || in[0] == 'l') {
@ -322,6 +358,8 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
if (check_user_and_ip(userid, q) != 0) {
write_dns(dns_fd, q, "BADIP", 5);
syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s",
userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
return;
} else {
users[userid].last_pkt = time(NULL);
@ -340,11 +378,14 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
write_dns(dns_fd, q, out, read);
q->id = 0;
syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]);
free(tmp[1]);
free(tmp[0]);
} else {
write_dns(dns_fd, q, "LNAK", 4);
syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password",
userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
}
}
return;
@ -441,7 +482,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
}
if (debug >= 1) {
printf("PING pkt from user %d\n", userid);
fprintf(stderr, "PING pkt from user %d\n", userid);
}
if (users[userid].q.id != 0) {
@ -491,7 +532,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
up_frag <= users[userid].inpacket.fragment) {
/* Got repeated old packet, skip it */
if (debug >= 1) {
printf("IN pkt seq# %d, frag %d, dropped duplicate\n",
fprintf(stderr, "IN pkt seq# %d, frag %d, dropped duplicate\n",
up_seq, up_frag);
}
/* Update seqno and maybe send immediate response packet */
@ -516,7 +557,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
users[userid].inpacket.offset += read;
if (debug >= 1) {
printf("IN pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n",
fprintf(stderr, "IN pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n",
up_seq, up_frag, lastfrag, read, users[userid].inpacket.len, userid);
}
@ -542,7 +583,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
}
}
} else {
printf("Discarded data, uncompress() result: %d\n", ret);
fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
}
users[userid].inpacket.len = users[userid].inpacket.offset = 0;
}
@ -567,7 +608,7 @@ handle_ns_request(int dns_fd, struct query *q)
if (debug >= 2) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
printf("TX: client %s, type %d, name %s, %d bytes NS reply\n",
fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n",
inet_ntoa(tempin->sin_addr), q->type, q->name, len);
}
if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
@ -598,7 +639,7 @@ forward_query(int bind_fd, struct query *q)
myaddr->sin_port = htons(bind_port);
if (debug >= 2) {
printf("TX: NS reply \n");
fprintf(stderr, "TX: NS reply \n");
}
if (sendto(bind_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
@ -613,7 +654,7 @@ tunnel_bind(int bind_fd, int dns_fd)
struct sockaddr_in from;
socklen_t fromlen;
struct fw_query *query;
short id;
unsigned short id;
int r;
fromlen = sizeof(struct sockaddr);
@ -626,20 +667,20 @@ tunnel_bind(int bind_fd, int dns_fd)
id = dns_get_id(packet, r);
if (debug >= 2) {
printf("RX: Got response on query %u from DNS\n", (id & 0xFFFF));
fprintf(stderr, "RX: Got response on query %u from DNS\n", (id & 0xFFFF));
}
/* Get sockaddr from id */
fw_query_get(id, &query);
if (!query && debug >= 2) {
printf("Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
fprintf(stderr, "Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
return 0;
}
if (debug >= 2) {
struct sockaddr_in *in;
in = (struct sockaddr_in *) &(query->addr);
printf("TX: client %s id %u, %d bytes\n",
fprintf(stderr, "TX: client %s id %u, %d bytes\n",
inet_ntoa(in->sin_addr), (id & 0xffff), r);
}
@ -666,7 +707,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
if (debug >= 2) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q.from);
printf("RX: client %s, type %d, name %s\n",
fprintf(stderr, "RX: client %s, type %d, name %s\n",
inet_ntoa(tempin->sin_addr), q.type, q.name);
}
@ -774,11 +815,12 @@ read_dns(int fd, struct query *q)
struct sockaddr_in from;
socklen_t addrlen;
char packet[64*1024];
int r;
#ifndef WINDOWS32
char address[96];
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
int r;
addrlen = sizeof(struct sockaddr);
iov.iov_base = packet;
@ -793,12 +835,17 @@ read_dns(int fd, struct query *q)
msg.msg_flags = 0;
r = recvmsg(fd, &msg, 0);
#else
addrlen = sizeof(struct sockaddr);
r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
#endif /* !WINDOWS32 */
if (r > 0) {
dns_decode(NULL, 0, q, QR_QUERY, packet, r);
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
q->fromlen = addrlen;
#ifndef WINDOWS32
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@ -809,6 +856,7 @@ read_dns(int fd, struct query *q)
break;
}
}
#endif
return strlen(q->name);
} else if (r < 0) {
@ -830,7 +878,7 @@ write_dns(int fd, struct query *q, char *data, int datalen)
if (debug >= 2) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
printf("TX: client %s, type %d, name %s, %d bytes data\n",
fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n",
inet_ntoa(tempin->sin_addr), q->type, q->name, datalen);
}
@ -841,7 +889,7 @@ static void
usage() {
extern char *__progname;
printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
"[-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]"
" tunnel_ip[/netmask] topdomain\n", __progname);
@ -852,46 +900,49 @@ static void
help() {
extern char *__progname;
printf("iodine IP over DNS tunneling server\n");
printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
fprintf(stderr, "iodine IP over DNS tunneling server\n");
fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
"[-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]"
" tunnel_ip[/netmask] topdomain\n", __progname);
printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n");
printf(" -c to disable check of client IP/port on each request\n");
printf(" -s to skip creating and configuring the tun device, "
fprintf(stderr, " -v to print version info and exit\n");
fprintf(stderr, " -h to print this help and exit\n");
fprintf(stderr, " -c to disable check of client IP/port on each request\n");
fprintf(stderr, " -s to skip creating and configuring the tun device, "
"which then has to be created manually\n");
printf(" -f to keep running in foreground\n");
printf(" -D to increase debug level\n");
printf(" -u name to drop privileges and run as user 'name'\n");
printf(" -t dir to chroot to directory dir\n");
printf(" -d device to set tunnel device name\n");
printf(" -m mtu to set tunnel device mtu\n");
printf(" -l ip address to listen on for incoming dns traffic "
fprintf(stderr, " -f to keep running in foreground\n");
fprintf(stderr, " -D to increase debug level\n");
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
fprintf(stderr, " -t dir to chroot to directory dir\n");
fprintf(stderr, " -d device to set tunnel device name\n");
fprintf(stderr, " -m mtu to set tunnel device mtu\n");
fprintf(stderr, " -l ip address to listen on for incoming dns traffic "
"(default 0.0.0.0)\n");
printf(" -p port to listen on for incoming dns traffic (default 53)\n");
printf(" -n ip to respond with to NS queries\n");
printf(" -b port to forward normal DNS queries to (on localhost)\n");
printf(" -P password used for authentication (max 32 chars will be used)\n");
printf("tunnel_ip is the IP number of the local tunnel interface.\n");
printf(" /netmask sets the size of the tunnel network.\n");
printf("topdomain is the FQDN that is delegated to this server.\n");
fprintf(stderr, " -p port to listen on for incoming dns traffic (default 53)\n");
fprintf(stderr, " -n ip to respond with to NS queries\n");
fprintf(stderr, " -b port to forward normal DNS queries to (on localhost)\n");
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
fprintf(stderr, "tunnel_ip is the IP number of the local tunnel interface.\n");
fprintf(stderr, " /netmask sets the size of the tunnel network.\n");
fprintf(stderr, "topdomain is the FQDN that is delegated to this server.\n");
exit(0);
}
static void
version() {
printf("iodine IP over DNS tunneling server\n");
printf("version: 0.5.0 from 2009-01-23\n");
printf("version: 0.5.1 from 2009-03-21\n");
exit(0);
}
int
main(int argc, char **argv)
{
extern char *__progname;
in_addr_t listen_ip;
#ifndef WINDOWS32
struct passwd *pw;
#endif
int foreground;
char *username;
char *newroot;
@ -916,7 +967,7 @@ main(int argc, char **argv)
foreground = 0;
bind_enable = 0;
bind_fd = 0;
mtu = 1024;
mtu = 1200;
listen_ip = INADDR_ANY;
port = 53;
ns_ip = INADDR_ANY;
@ -926,6 +977,10 @@ main(int argc, char **argv)
netmask = 27;
b32 = get_base32_encoder();
#ifdef WINDOWS32
WSAStartup(req_version, &wsa_data);
#endif
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
@ -1000,10 +1055,7 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
if (geteuid() != 0) {
warnx("Run as root and you'll be happy.\n");
usage();
}
check_superuser(usage);
if (argc != 2)
usage();
@ -1034,10 +1086,12 @@ main(int argc, char **argv)
}
if (username != NULL) {
#ifndef WINDOWS32
if ((pw = getpwnam(username)) == NULL) {
warnx("User %s does not exist!\n", username);
usage();
}
#endif
}
if (mtu <= 0) {
@ -1056,18 +1110,18 @@ main(int argc, char **argv)
usage();
/* NOTREACHED */
}
printf("Requests for domains outside of %s will be forwarded to port %d\n",
fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n",
topdomain, bind_port);
}
if (port != 53) {
printf("ALERT! Other dns servers expect you to run on port 53.\n");
printf("You must manually forward port 53 to port %d for things to work.\n", port);
fprintf(stderr, "ALERT! Other dns servers expect you to run on port 53.\n");
fprintf(stderr, "You must manually forward port 53 to port %d for things to work.\n", port);
}
if (debug) {
printf("Debug level %d enabled, will stay in foreground.\n", debug);
printf("Add more -D switches to set higher debug level.\n");
fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug);
fprintf(stderr, "Add more -D switches to set higher debug level.\n");
foreground = 1;
}
@ -1104,10 +1158,10 @@ main(int argc, char **argv)
created_users = init_users(my_ip, netmask);
if (created_users < USERS) {
printf("Limiting to %d simultaneous users because of netmask /%d\n",
fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n",
created_users, netmask);
}
printf("Listening to dns for domain %s\n", topdomain);
fprintf(stderr, "Listening to dns for domain %s\n", topdomain);
if (foreground == 0)
do_detach();
@ -1117,16 +1171,24 @@ main(int argc, char **argv)
signal(SIGINT, sigint);
if (username != NULL) {
#ifndef WINDOWS32
gid_t gids[1];
gids[0] = pw->pw_gid;
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
warnx("Could not switch to user %s!\n", username);
usage();
}
#endif
}
#ifndef WINDOWS32
openlog(__progname, LOG_NOWAIT, LOG_DAEMON);
#endif
syslog(LOG_INFO, "started, listening on port %d", port);
tunnel(tun_fd, dnsd_fd, bind_fd);
syslog(LOG_INFO, "stopping");
cleanup3:
close_dns(bind_fd);
cleanup2:

View File

@ -15,9 +15,14 @@
*/
#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"
/*

View File

@ -1,9 +1,9 @@
#!/bin/sh
case $1 in
case $2 in
link)
case `uname` in
case $1 in
SunOS | solaris)
echo '-lsocket -lnsl';
;;
@ -13,10 +13,13 @@ link)
Haiku)
echo '-lnetwork';
;;
windows32)
echo '-lws2_32 -liphlpapi';
;;
esac
;;
cflags)
case `uname` in
case $1 in
BeOS)
echo '-Dsocklen_t=int';
;;

303
src/tun.c
View File

@ -23,16 +23,39 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef WINDOWS32
#include <winsock2.h>
#include <winioctl.h>
#include "windows.h"
HANDLE dev_handle;
struct tun_data data;
#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED)
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
#define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define TAP_DEVICE_SPACE "\\\\.\\Global\\"
#define TAP_VERSION_ID_0801 "tap0801"
#define TAP_VERSION_ID_0901 "tap0901"
#define KEY_COMPONENT_ID "ComponentId"
#define NET_CFG_INST_ID "NetCfgInstanceId"
#else
#include <err.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "tun.h"
#define TUN_MAX_TRY 50
#endif
#include "tun.h"
#include "common.h"
char if_name[50];
#ifndef WINDOWS32
#ifdef LINUX
#include <sys/ioctl.h>
@ -63,7 +86,7 @@ open_tun(const char *tun_device)
if_name[sizeof(if_name)-1] = '\0';
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
printf("Opened %s\n", ifreq.ifr_name);
fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
return tun_fd;
}
@ -76,7 +99,7 @@ open_tun(const char *tun_device)
snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
printf("Opened %s\n", ifreq.ifr_name);
fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
snprintf(if_name, sizeof(if_name), "dns%d", i);
return tun_fd;
}
@ -111,14 +134,14 @@ open_tun(const char *tun_device)
return -1;
}
printf("Opened %s\n", tun_name);
fprintf(stderr, "Opened %s\n", tun_name);
return tun_fd;
} else {
for (i = 0; i < TUN_MAX_TRY; i++) {
snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
printf("Opened %s\n", tun_name);
fprintf(stderr, "Opened %s\n", tun_name);
snprintf(if_name, sizeof(if_name), "tun%d", i);
return tun_fd;
}
@ -134,6 +157,148 @@ open_tun(const char *tun_device)
}
#endif /* !LINUX */
#else /* WINDOWS32 */
static void
get_device(char *device, int device_len)
{
LONG status;
HKEY adapter_key;
int index;
index = 0;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
if (status != ERROR_SUCCESS) {
warnx("Error opening registry key " TAP_ADAPTER_KEY );
return;
}
while (TRUE) {
char name[256];
char unit[256];
char component[256];
char cid_string[256] = KEY_COMPONENT_ID;
HKEY device_key;
DWORD datatype;
DWORD len;
/* Iterate through all adapter of this kind */
len = sizeof(name);
status = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);
if (status == ERROR_NO_MORE_ITEMS) {
break;
} else if (status != ERROR_SUCCESS) {
warnx("Error enumerating subkeys of registry key " TAP_ADAPTER_KEY );
break;
}
snprintf(unit, sizeof(unit), TAP_ADAPTER_KEY "\\%s", name);
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);
if (status != ERROR_SUCCESS) {
warnx("Error opening registry key %s", unit);
goto next;
}
/* Check component id */
len = sizeof(component);
status = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);
if (status != ERROR_SUCCESS || datatype != REG_SZ) {
goto next;
}
if (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||
strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) {
/* We found a TAP32 device, get its NetCfgInstanceId */
char iid_string[256] = NET_CFG_INST_ID;
status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);
if (status != ERROR_SUCCESS || datatype != REG_SZ) {
warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string);
} else {
/* Done getting name of TAP device */
RegCloseKey(device_key);
return;
}
}
next:
RegCloseKey(device_key);
index++;
}
RegCloseKey(adapter_key);
}
DWORD WINAPI tun_reader(LPVOID arg)
{
struct tun_data *tun = arg;
char buf[64*1024];
int len;
int res;
OVERLAPPED olpd;
int sock;
sock = open_dns(0, INADDR_ANY);
olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
while(TRUE) {
olpd.Offset = 0;
olpd.OffsetHigh = 0;
res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
if (!res) {
WaitForSingleObject(olpd.hEvent, INFINITE);
res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),
sizeof(struct sockaddr_in));
}
}
return 0;
}
int
open_tun(const char *tun_device)
{
char adapter[256];
char tapfile[512];
int tunfd;
in_addr_t local;
memset(adapter, 0, sizeof(adapter));
get_device(adapter, sizeof(adapter));
if (strlen(adapter) == 0) {
warnx("No TAP adapters found. See README-win32.txt for help.\n");
return -1;
}
snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
fprintf(stderr, "Opening device %s\n", tapfile);
dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
if (dev_handle == INVALID_HANDLE_VALUE) {
return -1;
}
/* TODO get name of interface */
strncpy(if_name, "dns", MIN(4, sizeof(if_name)));
/* Use a UDP connection to forward packets from tun,
* so we can still use select() in main code.
* A thread does blocking reads on tun device and
* sends data as udp to this socket */
local = htonl(0x7f000001); /* 127.0.0.1 */
tunfd = open_dns(55353, local);
data.tun = dev_handle;
memset(&(data.addr), 0, sizeof(data.addr));
data.addr.sin_family = AF_INET;
data.addr.sin_port = htons(55353);
data.addr.sin_addr.s_addr = local;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
return tunfd;
}
#endif
void
close_tun(int tun_fd)
@ -145,7 +310,7 @@ close_tun(int tun_fd)
int
write_tun(int tun_fd, char *data, size_t len)
{
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
data += 4;
len -= 4;
#else /* !FREEBSD/DARWIN */
@ -162,19 +327,45 @@ write_tun(int tun_fd, char *data, size_t len)
#endif /* !LINUX */
#endif /* FREEBSD */
#ifndef WINDOWS32
if (write(tun_fd, data, len) != len) {
warn("write_tun");
return 1;
}
#else /* WINDOWS32 */
{
DWORD written;
DWORD res;
OVERLAPPED olpd;
olpd.Offset = 0;
olpd.OffsetHigh = 0;
olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
res = WriteFile(dev_handle, data, len, &written, &olpd);
if (!res && GetLastError() == ERROR_IO_PENDING) {
WaitForSingleObject(olpd.hEvent, INFINITE);
res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);
if (written != len) {
return -1;
}
}
}
#endif
return 0;
}
ssize_t
read_tun(int tun_fd, char *buf, size_t len)
{
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
/* FreeBSD/Darwin/NetBSD has no header */
return read(tun_fd, buf + 4, len - 4) + 4;
int bytes;
bytes = recv(tun_fd, buf + 4, len, 0);
if (bytes < 0) {
return bytes;
} else {
return bytes + 4;
}
#else /* !FREEBSD */
return read(tun_fd, buf, len);
#endif /* !FREEBSD */
@ -187,10 +378,16 @@ tun_setip(const char *ip, int netbits)
int netmask;
struct in_addr net;
int i;
#ifndef LINUX
int r;
#endif
#ifdef WINDOWS32
DWORD status;
DWORD ipdata[3];
struct in_addr addr;
DWORD len;
#endif
netmask = 0;
for (i = 0; i < netbits; i++) {
netmask = (netmask << 1) | 1;
@ -198,51 +395,89 @@ tun_setip(const char *ip, int netbits)
netmask <<= (32 - netbits);
net.s_addr = htonl(netmask);
if (inet_addr(ip) != INADDR_NONE) {
snprintf(cmdline, sizeof(cmdline),
"/sbin/ifconfig %s %s %s netmask %s",
if_name,
ip,
ip,
inet_ntoa(net));
printf("Setting IP of %s to %s\n", if_name, ip);
if (inet_addr(ip) == INADDR_NONE) {
fprintf(stderr, "Invalid IP: %s!\n", ip);
return 1;
}
#ifndef WINDOWS32
snprintf(cmdline, sizeof(cmdline),
"/sbin/ifconfig %s %s %s netmask %s",
if_name,
ip,
ip,
inet_ntoa(net));
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
#ifndef LINUX
r = system(cmdline);
if(r != 0) {
return r;
} else {
snprintf(cmdline, sizeof(cmdline),
"/sbin/route add %s/%d %s",
ip, netbits, ip);
}
printf("Adding route %s/%d to %s\n", ip, netbits, ip);
#endif
return system(cmdline);
r = system(cmdline);
if(r != 0) {
return r;
} else {
printf("Invalid IP: %s!\n", ip);
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);
#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 {
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
}

View File

@ -21,13 +21,18 @@
#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"

85
src/windows.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2006-2009 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 __FIX_WINDOWS_H__
#define __FIX_WINDOWS_H__
typedef unsigned int in_addr_t;
#include <windows.h>
#include <windns.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#define T_A DNS_TYPE_A
#define T_NS DNS_TYPE_NS
#define T_NULL DNS_TYPE_NULL
#define C_IN 1
#define SERVFAIL 2
#define NXDOMAIN 3
#define NOTIMP 4
#define REFUSED 5
typedef struct {
unsigned id :16; /* query identification number */
/* fields in third byte */
unsigned rd :1; /* recursion desired */
unsigned tc :1; /* truncated message */
unsigned aa :1; /* authoritive answer */
unsigned opcode :4; /* purpose of message */
unsigned qr :1; /* response flag */
/* fields in fourth byte */
unsigned rcode :4; /* response code */
unsigned cd: 1; /* checking disabled by resolver */
unsigned ad: 1; /* authentic data from named */
unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
unsigned ra :1; /* recursion available */
/* remaining bytes */
unsigned qdcount :16; /* number of question entries */
unsigned ancount :16; /* number of answer entries */
unsigned nscount :16; /* number of authority entries */
unsigned arcount :16; /* number of resource entries */
} HEADER;
struct ip
{
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
DWORD WINAPI tun_reader(LPVOID arg);
struct tun_data {
HANDLE tun;
int sock;
struct sockaddr_in addr;
};
#endif

View File

@ -1,7 +1,7 @@
CC = gcc
TEST = test
OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o user.o
SRCOBJS = ../src/base32.o ../src/base64.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o
OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o user.o fw_query.o
SRCOBJS = ../src/base32.o ../src/base64.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o ../src/fw_query.o
OS = `uname | tr "a-z" "A-Z"`

View File

@ -24,14 +24,18 @@
#include "base32.h"
#include "test.h"
#define TUPLES 5
static struct tuple
{
char *a;
char *b;
} testpairs[] = {
} testpairs[TUPLES] = {
{ "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
{ "abc123", "mfrggmjsgm" },
{ NULL, NULL }
{ "test", "orsxg3a" },
{ "tst", "orzxi" },
{ "", "" },
};
START_TEST(test_base32_encode)
@ -40,18 +44,14 @@ START_TEST(test_base32_encode)
char buf[4096];
struct encoder *b32;
int val;
int i;
b32 = get_base32_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = b32->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
len = sizeof(buf);
val = b32->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
fail_unless(strcmp(buf, testpairs[_i].b) == 0,
"'%s' != '%s'", buf, testpairs[_i].b);
}
END_TEST
@ -61,19 +61,15 @@ START_TEST(test_base32_decode)
char buf[4096];
struct encoder *b32;
int val;
int i;
b32 = get_base32_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = b32->decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
len = sizeof(buf);
val = b32->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[_i].a) == 0,
"'%s' != '%s'", buf, testpairs[_i].a);
}
END_TEST
@ -89,15 +85,58 @@ START_TEST(test_base32_5to8_8to5)
}
END_TEST
START_TEST(test_base32_blksize)
{
size_t rawlen;
size_t enclen;
char *rawbuf;
char *encbuf;
struct encoder *b32;
int i;
int val;
b32 = get_base32_encoder();
rawlen = b32->blocksize_raw();
enclen = b32->blocksize_encoded();
rawbuf = malloc(rawlen + 16);
encbuf = malloc(enclen + 16);
for (i = 0; i < rawlen; i++) {
rawbuf[i] = 'A';
}
rawbuf[i] = 0;
val = b32->encode(encbuf, &enclen, rawbuf, rawlen);
fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
fail_unless(enclen == 5, "encoded %d bytes, not 5", enclen);
fail_unless(val == 8, "encoded string %s was length %d", encbuf, val);
memset(rawbuf, 0, rawlen + 16);
enclen = val;
val = b32->decode(rawbuf, &rawlen, encbuf, enclen);
fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
fail_unless(val == 5, "val was not 5 but %d", val);
for (i = 0; i < rawlen; i++) {
fail_unless(rawbuf[i] == 'A');
}
}
END_TEST
TCase *
test_base32_create_tests()
{
TCase *tc;
tc = tcase_create("Base32");
tcase_add_test(tc, test_base32_encode);
tcase_add_test(tc, test_base32_decode);
tcase_add_loop_test(tc, test_base32_encode, 0, TUPLES);
tcase_add_loop_test(tc, test_base32_decode, 0, TUPLES);
tcase_add_test(tc, test_base32_5to8_8to5);
tcase_add_test(tc, test_base32_blksize);
return tc;
}

View File

@ -24,11 +24,13 @@
#include "base64.h"
#include "test.h"
#define TUPLES 5
static struct tuple
{
char *a;
char *b;
} testpairs[] = {
} testpairs[TUPLES] = {
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
{ "abc1231", "ywjJmtiZmq" },
{
@ -59,7 +61,7 @@ static struct tuple
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654321"
"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
},
{ NULL, NULL }
{ "", "" }
};
START_TEST(test_base64_encode)
@ -68,18 +70,14 @@ START_TEST(test_base64_encode)
char buf[4096];
struct encoder *b64;
int val;
int i;
b64 = get_base64_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = b64->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
len = sizeof(buf);
val = b64->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
fail_unless(strcmp(buf, testpairs[_i].b) == 0,
"'%s' != '%s'", buf, testpairs[_i].b);
}
END_TEST
@ -89,18 +87,56 @@ START_TEST(test_base64_decode)
char buf[4096];
struct encoder *b64;
int val;
int i;
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));
len = sizeof(buf);
val = b64->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
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();
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(rawlen == 3, "raw length was %d not 3", rawlen);
fail_unless(val == 3);
for (i = 0; i < rawlen; i++) {
fail_unless(rawbuf[i] == 'A');
}
}
END_TEST
@ -111,8 +147,9 @@ test_base64_create_tests()
TCase *tc;
tc = tcase_create("Base64");
tcase_add_test(tc, test_base64_encode);
tcase_add_test(tc, test_base64_decode);
tcase_add_loop_test(tc, test_base64_encode, 0, TUPLES);
tcase_add_loop_test(tc, test_base64_decode, 0, TUPLES);
tcase_add_test(tc, test_base64_blksize);
return tc;
}

View File

@ -33,14 +33,14 @@
static void dump_packet(char *, size_t);
static char queryPacket[] =
static char query_packet[] =
"\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x2D\x41\x6A\x62\x63"
"\x75\x79\x74\x63\x70\x65\x62\x30\x67\x71\x30\x6C\x74\x65\x62\x75\x78"
"\x67\x69\x64\x75\x6E\x62\x73\x73\x61\x33\x64\x66\x6F\x6E\x30\x63\x61"
"\x7A\x64\x62\x6F\x72\x71\x71\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00"
"\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00";
static char answerPacket[] =
static char answer_packet[] =
"\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
@ -48,7 +48,7 @@ static char answerPacket[] =
"\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
"\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
static char answerPacketHighTransId[] =
static char answer_packet_high_trans_id[] =
"\x85\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
@ -87,14 +87,14 @@ START_TEST(test_encode_query)
}
strcpy(d, topdomain);
ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
len = sizeof(queryPacket) - 1; /* Skip extra null character */
len = sizeof(query_packet) - 1; /* Skip extra null character */
if (strncmp(queryPacket, buf, sizeof(queryPacket)) || ret != len) {
if (strncmp(query_packet, buf, sizeof(query_packet)) || ret != len) {
printf("\n");
dump_packet(queryPacket, len);
dump_packet(query_packet, len);
dump_packet(buf, ret);
}
fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
fail_unless(strncmp(query_packet, buf, sizeof(query_packet)) == 0, "Did not compile expected packet");
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
@ -110,10 +110,10 @@ START_TEST(test_decode_query)
memset(&q, 0, sizeof(struct query));
memset(&buf, 0, sizeof(buf));
q.id = 0;
len = sizeof(queryPacket) - 1;
len = sizeof(query_packet) - 1;
enc = get_base32_encoder();
dns_decode(buf, sizeof(buf), &q, QR_QUERY, queryPacket, len);
dns_decode(buf, sizeof(buf), &q, QR_QUERY, query_packet, len);
domain = strstr(q.name, topdomain);
len = sizeof(buf);
unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);
@ -139,9 +139,9 @@ START_TEST(test_encode_response)
q.id = 1337;
ret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData));
len = sizeof(answerPacket) - 1; /* Skip extra null character */
len = sizeof(answer_packet) - 1; /* Skip extra null character */
fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
fail_unless(strncmp(answer_packet, buf, sizeof(answer_packet)) == 0, "Did not compile expected packet");
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
@ -156,7 +156,7 @@ START_TEST(test_decode_response)
len = sizeof(buf);
memset(&buf, 0, sizeof(buf));
ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet, sizeof(answer_packet)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
fail_unless(q.id == 0x0539);
@ -173,12 +173,45 @@ START_TEST(test_decode_response_with_high_trans_id)
len = sizeof(buf);
memset(&buf, 0, sizeof(buf));
ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacketHighTransId, sizeof(answerPacketHighTransId)-1);
ret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539);
}
END_TEST
START_TEST(test_get_id_short_packet)
{
char buf[5];
int len;
unsigned short id;
len = sizeof(buf);
memset(&buf, 5, sizeof(buf));
id = dns_get_id(buf, len);
fail_unless(id == 0);
}
END_TEST
START_TEST(test_get_id_low)
{
unsigned short id;
id = dns_get_id(answer_packet, sizeof(answer_packet));
fail_unless(id == 1337);
}
END_TEST
START_TEST(test_get_id_high)
{
unsigned short id;
id = dns_get_id(answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id));
fail_unless(id == 0x8539);
}
END_TEST
static void
dump_packet(char *buf, size_t len)
{
@ -209,6 +242,9 @@ test_dns_create_tests()
tcase_add_test(tc, test_encode_response);
tcase_add_test(tc, test_decode_response);
tcase_add_test(tc, test_decode_response_with_high_trans_id);
tcase_add_test(tc, test_get_id_short_packet);
tcase_add_test(tc, test_get_id_low);
tcase_add_test(tc, test_get_id_high);
return tc;
}

88
tests/fw_query.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2006-2009 Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <check.h>
#include "fw_query.h"
#include "test.h"
START_TEST(test_fw_query_simple)
{
struct fw_query q;
struct fw_query *qp;
q.addrlen = 33;
q.id = 0x848A;
fw_query_init();
/* Test empty cache */
fw_query_get(0x848A, &qp);
fail_unless(qp == NULL);
fw_query_put(&q);
/* Test cache with one entry */
fw_query_get(0x848A, &qp);
fail_unless(qp->addrlen == q.addrlen);
fail_unless(qp->id == q.id);
}
END_TEST
START_TEST(test_fw_query_edge)
{
struct fw_query q;
struct fw_query *qp;
int i;
fw_query_init();
q.addrlen = 33;
q.id = 0x848A;
fw_query_put(&q);
for (i = 1; i < FW_QUERY_CACHE_SIZE; i++) {
q.addrlen++;
q.id++;
fw_query_put(&q);
}
/* The query should still be cached */
fw_query_get(0x848A, &qp);
fail_unless(qp->addrlen == 33);
fail_unless(qp->id == 0x848A);
q.addrlen++;
q.id++;
fw_query_put(&q);
/* but now it is overwritten */
fw_query_get(0x848A, &qp);
fail_unless(qp == NULL);
}
END_TEST
TCase *
test_fw_query_create_tests()
{
TCase *tc;
tc = tcase_create("Forwarded query");
tcase_add_test(tc, test_fw_query_simple);
tcase_add_test(tc, test_fw_query_edge);
return tc;
}

View File

@ -28,7 +28,7 @@ START_TEST(test_login_hash)
int len;
int seed;
len = 16;
len = sizeof(ans);
seed = 15;
memset(ans, 0, sizeof(ans));
@ -37,6 +37,26 @@ START_TEST(test_login_hash)
}
END_TEST
START_TEST(test_login_hash_short)
{
char ans[8];
char check[sizeof(ans)];
char pass[32] = "iodine is the shit";
int len;
int seed;
len = sizeof(ans);
seed = 15;
memset(ans, 0, sizeof(ans));
memset(check, 0, sizeof(check));
/* If len < 16, it should do nothing */
login_calculate(ans, len, pass, seed);
fail_if(memcmp(ans, check, sizeof(ans)));
}
END_TEST
TCase *
test_login_create_tests()
{
@ -44,6 +64,7 @@ test_login_create_tests()
tc = tcase_create("Login");
tcase_add_test(tc, test_login_hash);
tcase_add_test(tc, test_login_hash_short);
return tc;
}

View File

@ -83,14 +83,42 @@ START_TEST(test_read_putlong)
}
END_TEST
START_TEST(test_read_name)
START_TEST(test_read_name_empty_loop)
{
unsigned char emptyloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
char buf[1024];
char *data;
int rv;
memset(buf, 0, sizeof(buf));
data = (char*) emptyloop + sizeof(HEADER);
buf[1023] = 'A';
rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
fail_unless(buf[1023] == 'A');
}
END_TEST
START_TEST(test_read_name_inf_loop)
{
unsigned char infloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
char buf[1024];
char *data;
int rv;
memset(buf, 0, sizeof(buf));
data = (char*) infloop + sizeof(HEADER);
buf[4] = '\a';
rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
fail_unless(buf[4] == '\a');
}
END_TEST
START_TEST(test_read_name_longname)
{
unsigned char longname[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
@ -100,12 +128,61 @@ START_TEST(test_read_name)
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x00\x00\x01\x00\x01";
char buf[1024];
char *data;
int rv;
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');
}
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);
}
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;
/* This test uses 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);
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 };
@ -114,42 +191,7 @@ START_TEST(test_read_name)
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);
/* This test uses malloc to cause segfault if jump is executed */
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump2));
if (jumper) {
@ -157,7 +199,7 @@ START_TEST(test_read_name)
data = (char*) jumper + sizeof(HEADER);
rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
fail_unless(rv == 4, NULL);
fail_unless(rv == 4);
fail_unless(strcmp("BA.", buf) == 0,
"buf is not BA: %s", buf);
}
@ -180,7 +222,7 @@ START_TEST(test_putname)
b = buf;
ret = putname(&b, 256, domain);
fail_unless(ret == strlen(domain) + 1, NULL);
fail_unless(ret == strlen(domain) + 1);
fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
}
END_TEST
@ -201,8 +243,8 @@ START_TEST(test_putname_nodot)
b = buf;
ret = putname(&b, 256, nodot);
fail_unless(ret == -1, NULL);
fail_unless(b == buf, NULL);
fail_unless(ret == -1);
fail_unless(b == buf);
}
END_TEST
@ -226,8 +268,8 @@ START_TEST(test_putname_toolong)
b = buf;
ret = putname(&b, 256, toolong);
fail_unless(ret == -1, NULL);
fail_unless(b == buf, NULL);
fail_unless(ret == -1);
fail_unless(b == buf);
}
END_TEST
@ -241,7 +283,12 @@ test_read_create_tests()
tcase_set_timeout(tc, 60);
tcase_add_test(tc, test_read_putshort);
tcase_add_test(tc, test_read_putlong);
tcase_add_test(tc, test_read_name);
tcase_add_test(tc, test_read_name_empty_loop);
tcase_add_test(tc, test_read_name_inf_loop);
tcase_add_test(tc, test_read_name_longname);
tcase_add_test(tc, test_read_name_onejump);
tcase_add_test(tc, test_read_name_badjump_start);
tcase_add_test(tc, test_read_name_badjump_second);
tcase_add_test(tc, test_putname);
tcase_add_test(tc, test_putname_nodot);
tcase_add_test(tc, test_putname_toolong);

View File

@ -53,6 +53,9 @@ main()
test = test_user_create_tests();
suite_add_tcase(iodine, test);
test = test_fw_query_create_tests();
suite_add_tcase(iodine, test);
runner = srunner_create(iodine);
srunner_run_all(runner, CK_NORMAL);
failed = srunner_ntests_failed(runner);

View File

@ -24,6 +24,7 @@ TCase *test_encoding_create_tests();
TCase *test_read_create_tests();
TCase *test_login_create_tests();
TCase *test_user_create_tests();
TCase *test_fw_query_create_tests();
char *va_str(const char *, ...);