Tagged iodine 0.4.2

This commit is contained in:
Erik Ekman 2008-08-06 20:26:36 +00:00
parent d27bd67997
commit e45bdece8e
18 changed files with 362 additions and 161 deletions

View File

@ -5,6 +5,23 @@ iodine - http://code.kryo.se/iodine
CHANGES:
2008-08-06: 0.4.2 "Opened Zone"
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann
- Applied a patch for not creating and configuring the tun interface,
Debian bug #477692 by Vincent Bernat, controlled by -s switch
- Applied a security patch from Andrew Griffiths, use setgroups() to
limit the groups of the user
- Applied a patch to make iodine build on (Open)Solaris, from Albert Lee
Needs TUN/TAP driver: http://www.whiteboard.ne.jp/~admin2/tuntap/
Still needs some more code in tun.c for opening/closing the device
- Added option in server (-c) to disable IP/port checking on each packet,
will hopefully help when server is behind NAT
- Fixed bug #21, now only IP address part of each packet is checked.
Should remove the need for the -c option and also work with
bugfixed DNS servers worldwide.
- Added -D option on server to enable debugging. Debug level 1 now prints
info about each RX/TX datagram.
2007-11-30: 0.4.1 "Tea Online"
- Introduced encoding API
- Switched to new Base32 implementation

View File

@ -35,7 +35,7 @@ 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) all)
clean:
@echo "Cleaning..."

View File

@ -1,5 +1,5 @@
.\" groff -man -Tascii iodine.8
.TH IODINE 8 "JUN 2007" "User Manuals"
.TH IODINE 8 "JUL 2008" "User Manuals"
.SH NAME
iodine, iodined \- tunnel IPv4 over DNS
.SH SYNOPSIS
@ -25,7 +25,7 @@ iodine, iodined \- tunnel IPv4 over DNS
.B iodined [-h]
.B iodined [-f] [-u
.B iodined [-c] [-s] [-f] [-D] [-u
.I user
.B ] [-P
.I password
@ -78,6 +78,16 @@ Use the TUN device 'device' instead of the normal one, which is dnsX on Linux
and otherwise tunX.
.SS Server Options:
.TP
.B -c
Disable checks on client IP on all incoming requests.
.TP
.B -s
Don't try to configure IP address or MTU. This should only be used if
you have already configured the device that will be used.
.TP
.B -D
Increase debug level. Level 1 prints info about each RX/TX packet.
.TP
.B -m mtu
Set 'mtu' as mtu size for the tunnel device. This will be sent to the client
on connect, and the client will use the same mtu.
@ -124,13 +134,13 @@ the same on both the client and the server.
.TP
Try it out within your own LAN! Follow these simple steps:
.TP
- On your server, run: ./iodined -f 10.0.0.1 test.asdf
- On your server, run: ./iodined \-f 10.0.0.1 test.asdf
(If you already use the 10.0.0.0 network, use another internal net like
172.16.0.0)
.TP
- Enter a password
.TP
- On the client, run: ./iodine -f 192.168.0.1 test.asdf
- On the client, run: ./iodine \-f 192.168.0.1 test.asdf
(Replace 192.168.0.1 with the server's ip address)
.TP
- Enter the same password
@ -160,10 +170,10 @@ tunnel1 IN NS tunnel1host.mytunnel.com.
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
to your server. Start iodined on the server. The first argument is the tunnel
IP address (like 192.168.99.1) and the second is the assigned domain (in this
case tunnel1.mytunnel.com). The -f argument will keep iodined running in the
case tunnel1.mytunnel.com). The \-f argument will keep iodined running in the
foreground, which helps when testing. iodined will start a virtual interface,
and also start listening for DNS queries on UDP port 53. Either enter a
password on the commandline (-P pass) or after the server has started. Now
password on the commandline (\-P pass) or after the server has started. Now
everything is ready for the client.
.TP
.B Client side:

View File

@ -8,10 +8,10 @@ SERVER = ../bin/iodined
OS = `uname | tr "a-z" "A-Z"`
ARCH = `uname -m`
LDFLAGS = -lz
LDFLAGS = -lz `sh osflags link`
CFLAGS = -c -g -Wall -D$(OS) -pedantic
all: stateos $(CLIENT) $(SERVER) $(TESTSUITE)
all: stateos $(CLIENT) $(SERVER)
stateos:
@echo OS is $(OS), arch is $(ARCH)

View File

@ -1,4 +1,5 @@
/* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -21,6 +22,8 @@
#endif
#include <time.h>
#include <err.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
@ -29,10 +32,48 @@
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <termios.h>
#include "common.h"
/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
#if !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
static int daemon(int nochdir, int noclose)
{
int fd, i;
switch (fork()) {
case 0:
break;
case -1:
return -1;
default:
_exit(0);
}
if (!nochdir) {
chdir("/");
}
if (setsid() < 0) {
return -1;
}
if (!noclose) {
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
for (i = 0; i < 3; i++) {
dup2(fd, i);
}
if (fd > 2) {
close(fd);
}
}
}
return 0;
}
#endif
int
open_dns(int localport, in_addr_t listen_ip)
{
@ -111,3 +152,20 @@ read_password(char *buf, size_t len)
strncpy(buf, pwd, len);
buf[len-1] = '\0';
}
int
check_topdomain(char *str)
{
int i;
if(str[0] == '.') /* special case */
return 1;
for( i = 0; i < strlen(str); i++) {
if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
continue;
else
return 1;
}
return 0;
}

View File

@ -54,4 +54,6 @@ void do_detach();
void read_password(char*, size_t);
int check_topdomain(char *);
#endif

View File

@ -150,14 +150,13 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
warnx("Got NXDOMAIN as reply");
break;
case SERVFAIL:
warnx("Got SERVFAIL as reply");
break;
case NOERROR:
default:
warnx("no query or answer in answer");
warnx("no query or answer in reply packet");
break;
}
return -1;
@ -178,7 +177,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
rv = MIN(rlen, sizeof(rdata));
rv = readdata(packet, &data, rdata, rv);
if(type == T_NULL && rv > 2) {
if(type == T_NULL && rv > 2 && buf) {
rv = MIN(rv, buflen);
memcpy(buf, rdata, rv);
}
@ -194,11 +193,6 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
readshort(packet, &data, &type);
readshort(packet, &data, &class);
if(type != T_NULL) {
rv = 0;
break;
}
strncpy(q->name, name, sizeof(q->name));
q->name[sizeof(q->name) - 1] = '\0';
q->type = type;

View File

@ -23,10 +23,12 @@
#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>
@ -76,6 +78,10 @@ static struct encoder *dataenc;
/* result of case preservation check done after login */
static int case_preserved;
#if !defined(BSD) && !defined(__GLIBC__)
static char *__progname;
#endif
static void
sighandler(int sig)
{
@ -396,8 +402,11 @@ handshake(int dns_fd)
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if(read < 0) {
warn("handshake read");
if(read <= 0) {
if (read == 0) {
warn("handshake read");
}
/* if read < 0 then warning has been printed already */
continue;
}
@ -602,7 +611,7 @@ static void
version() {
printf("iodine IP over DNS tunneling client\n");
printf("version: 0.4.1 from 2007-11-30\n");
printf("version: 0.4.2 from 2008-08-06\n");
exit(0);
}
@ -630,6 +639,14 @@ main(int argc, char **argv)
b32 = get_base32_encoder();
dataenc = get_base32_encoder();
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
#endif
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
switch(choice) {
case 'v':
@ -687,8 +704,13 @@ main(int argc, char **argv)
set_nameserver(nameserv_addr);
if (strlen(topdomain) > 128 || topdomain[0] == '.') {
warnx("Use a topdomain max 128 chars long. Do not start it with a dot.\n");
if(strlen(topdomain) <= 128) {
if(check_topdomain(topdomain)) {
warnx("Topdomain contains invalid characters.\n");
usage();
}
} else {
warnx("Use a topdomain max 128 chars long.\n");
usage();
}
@ -722,7 +744,9 @@ main(int argc, char **argv)
do_chroot(newroot);
if (username != NULL) {
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
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();
}

View File

@ -21,10 +21,12 @@
#include <signal.h>
#include <unistd.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 <time.h>
#include <pwd.h>
#include <arpa/inet.h>
@ -32,6 +34,10 @@
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <zlib.h>
#include <arpa/nameser.h>
#ifdef DARWIN
#include <arpa/nameser8_compat.h>
#endif
#include "common.h"
#include "dns.h"
@ -47,10 +53,17 @@ static char *topdomain;
static char password[33];
static struct encoder *b32;
static int check_ip;
static int my_mtu;
static in_addr_t my_ip;
static int read_dns(int, struct query *, char *, int);
static int debug;
#if !defined(BSD) && !defined(__GLIBC__)
static char *__progname;
#endif
static int read_dns(int, struct query *);
static void write_dns(int, struct query *, char *, int);
static void
@ -59,6 +72,15 @@ sigint(int sig)
running = 0;
}
static int
ip_cmp(int userid, struct query *q)
{
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
}
static int
tunnel_tun(int tun_fd, int dns_fd)
{
@ -118,34 +140,44 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *
out[5] = ((payload >> 16) & 0xff);
out[6] = ((payload >> 8) & 0xff);
out[7] = ((payload) & 0xff);
out[8] = u->id;
if (u) {
out[8] = u->id;
} else {
out[8] = 0;
}
write_dns(fd, &u->q, out, sizeof(out));
}
static int
tunnel_dns(int tun_fd, int dns_fd)
static void
handle_null_request(int tun_fd, int dns_fd, struct query *q)
{
struct in_addr tempip;
struct user dummy;
struct ip *hdr;
unsigned long outlen;
char in[64*1024];
char logindata[16];
char out[64*1024];
char in[64*1024];
char unpacked[64*1024];
char *tmp[2];
char *domain;
int userid;
int touser;
int version;
int read;
int code;
int read;
userid = -1;
if ((read = read_dns(dns_fd, &(dummy.q), in, sizeof(in))) <= 0)
return 0;
domain = strstr(q->name, topdomain);
if (!domain) {
/* Not for us, discard */
return;
}
read = (int) (domain - q->name);
memcpy(in, q->name, MIN(read, sizeof(in)));
if(in[0] == 'V' || in[0] == 'v') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Version greeting, compare and send ack/nak */
@ -160,34 +192,37 @@ tunnel_dns(int tun_fd, int dns_fd)
if (version == VERSION) {
userid = find_available_user();
if (userid >= 0) {
struct sockaddr_in *tempin;
users[userid].seed = rand();
memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
users[userid].addrlen = dummy.q.fromlen;
/* Store remote IP number */
tempin = (struct sockaddr_in *) &(q->from);
memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].encoder = get_base32_encoder();
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
users[userid].q.id = 0;
} else {
/* No space for another user */
send_version_response(dns_fd, VERSION_FULL, USERS, &dummy);
send_version_response(dns_fd, VERSION_FULL, USERS, NULL);
}
} else {
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
send_version_response(dns_fd, VERSION_NACK, VERSION, NULL);
}
} else if(in[0] == 'L' || in[0] == 'l') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Login phase, handle auth */
userid = unpacked[0];
if (userid < 0 || userid >= USERS) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
return 0; /* illegal id */
write_dns(dns_fd, q, "BADIP", 5);
return; /* illegal id */
}
users[userid].last_pkt = time(NULL);
login_calculate(logindata, 16, password, users[userid].seed);
if (dummy.q.fromlen != users[userid].addrlen ||
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
if (check_ip && ip_cmp(userid, q) != 0) {
write_dns(dns_fd, q, "BADIP", 5);
} else {
if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
/* Login ok, send ip/mtu info */
@ -200,31 +235,31 @@ tunnel_dns(int tun_fd, int dns_fd)
read = snprintf(out, sizeof(out), "%s-%s-%d",
tmp[0], tmp[1], my_mtu);
write_dns(dns_fd, &(dummy.q), out, read);
dummy.q.id = 0;
write_dns(dns_fd, q, out, read);
q->id = 0;
free(tmp[1]);
free(tmp[0]);
} else {
write_dns(dns_fd, &(dummy.q), "LNAK", 4);
write_dns(dns_fd, q, "LNAK", 4);
}
}
} else if(in[0] == 'P' || in[0] == 'p') {
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
/* Ping packet, store userid */
userid = unpacked[0];
if (userid < 0 || userid >= USERS) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
return 0; /* illegal id */
if (userid < 0 || userid >= USERS || ip_cmp(userid, q) != 0) {
write_dns(dns_fd, q, "BADIP", 5);
return; /* illegal id */
}
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].last_pkt = time(NULL);
} else if(in[0] == 'Z' || in[0] == 'z') {
/* Case conservation check */
/* Reply with received hostname as data */
write_dns(dns_fd, &(dummy.q), in, read);
return 0;
write_dns(dns_fd, q, in, read);
return;
} else if((in[0] >= '0' && in[0] <= '9')
|| (in[0] >= 'a' && in[0] <= 'f')
|| (in[0] >= 'A' && in[0] <= 'F')) {
@ -237,22 +272,20 @@ tunnel_dns(int tun_fd, int dns_fd)
userid = code >> 1;
if (userid < 0 || userid >= USERS) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
return 0; /* illegal id */
write_dns(dns_fd, q, "BADIP", 5);
return; /* illegal id */
}
/* Check sending ip number */
if (dummy.q.fromlen != users[userid].addrlen ||
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
if (check_ip && ip_cmp(userid, q) != 0) {
write_dns(dns_fd, q, "BADIP", 5);
} else {
/* decode with this users encoding */
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1,
users[userid].encoder);
users[userid].last_pkt = time(NULL);
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
users[userid].addrlen = dummy.q.fromlen;
memcpy(&(users[userid].q), q, sizeof(struct query));
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
users[userid].inpacket.len += read;
users[userid].inpacket.offset += read;
@ -281,14 +314,35 @@ tunnel_dns(int tun_fd, int dns_fd)
}
}
/* userid must be set for a reply to be sent */
if (userid >= 0 && userid < USERS && dummy.q.fromlen == users[userid].addrlen &&
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) == 0 &&
users[userid].outpacket.len > 0) {
write_dns(dns_fd, &(dummy.q), users[userid].outpacket.data, users[userid].outpacket.len);
if (userid >= 0 && userid < USERS && ip_cmp(userid, q) == 0 && users[userid].outpacket.len > 0) {
write_dns(dns_fd, q, users[userid].outpacket.data, users[userid].outpacket.len);
users[userid].outpacket.len = 0;
users[userid].q.id = 0;
}
}
static int
tunnel_dns(int tun_fd, int dns_fd)
{
struct query q;
int read;
if ((read = read_dns(dns_fd, &q)) <= 0)
return 0;
if (debug >= 1) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q.from);
printf("RX: client %s, type %d, name %s\n", inet_ntoa(tempin->sin_addr), q.type, q.name);
}
switch (q.type) {
case T_NULL:
handle_null_request(tun_fd, dns_fd, &q);
break;
default:
break;
}
return 0;
}
@ -349,36 +403,28 @@ tunnel(int tun_fd, int dns_fd)
}
static int
read_dns(int fd, struct query *q, char *buf, int buflen)
read_dns(int fd, struct query *q)
{
struct sockaddr_in from;
char packet[64*1024];
char *domain;
socklen_t addrlen;
int rv;
int r;
addrlen = sizeof(struct sockaddr);
r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
if (r > 0) {
dns_decode(buf, buflen, q, QR_QUERY, packet, r);
domain = strstr(q->name, topdomain);
if (domain) {
rv = (int) (domain - q->name);
memcpy(buf, q->name, MIN(rv, buflen));
q->fromlen = addrlen;
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
} else {
rv = 0;
}
dns_decode(NULL, 0, q, QR_QUERY, packet, r);
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
q->fromlen = addrlen;
return strlen(q->name);
} else if (r < 0) {
/* Error */
warn("read dns");
rv = 0;
}
return rv;
return 0;
}
static void
@ -389,6 +435,13 @@ write_dns(int fd, struct query *q, char *data, int datalen)
len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
if (debug >= 1) {
struct sockaddr_in *tempin;
tempin = (struct sockaddr_in *) &(q->from);
printf("TX: client %s, type %d, name %s, %d bytes data\n",
inet_ntoa(tempin->sin_addr), q->type, q->name, datalen);
}
sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
}
@ -396,7 +449,7 @@ static void
usage() {
extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] [-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-P password]"
" tunnel_ip topdomain\n", __progname);
exit(2);
@ -407,12 +460,15 @@ help() {
extern char *__progname;
printf("iodine IP over DNS tunneling server\n");
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] [-t chrootdir] [-d device] [-m mtu] "
"[-l ip address to listen on] [-p port] [-P password]"
" tunnel_ip topdomain\n", __progname);
printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n");
printf(" -c to disable check of client IP/port on each request\n");
printf(" -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");
@ -428,7 +484,7 @@ help() {
static void
version() {
printf("iodine IP over DNS tunneling server\n");
printf("version: 0.4.1 from 2007-11-30\n");
printf("version: 0.4.2 from 2008-08-06\n");
exit(0);
}
@ -446,6 +502,7 @@ main(int argc, char **argv)
int choice;
int port;
int mtu;
int skipipconfig;
username = NULL;
newroot = NULL;
@ -454,23 +511,43 @@ main(int argc, char **argv)
mtu = 1024;
listen_ip = INADDR_ANY;
port = 53;
check_ip = 1;
skipipconfig = 0;
debug = 0;
b32 = get_base32_encoder();
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
#endif
memset(password, 0, sizeof(password));
srand(time(NULL));
while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:P:")) != -1) {
switch(choice) {
case 'v':
version();
break;
case 'c':
check_ip = 0;
break;
case 's':
skipipconfig = 1;
break;
case 'f':
foreground = 1;
break;
case 'h':
help();
break;
case 'D':
debug++;
break;
case 'u':
username = optarg;
break;
@ -488,10 +565,6 @@ main(int argc, char **argv)
break;
case 'p':
port = atoi(optarg);
if (port) {
printf("ALERT! Other dns servers expect you to run on port 53.\n");
printf("You must manually forward port 53 to port %d for things to work.\n", port);
}
break;
case 'P':
strncpy(password, optarg, sizeof(password));
@ -518,8 +591,13 @@ main(int argc, char **argv)
usage();
topdomain = strdup(argv[1]);
if (strlen(topdomain) > 128 || topdomain[0] == '.') {
warnx("Use a topdomain max 128 chars long. Do not start it with a dot.\n");
if(strlen(topdomain) <= 128) {
if(check_topdomain(topdomain)) {
warnx("Topdomain contains invalid characters.\n");
usage();
}
} else {
warnx("Use a topdomain max 128 chars long.\n");
usage();
}
@ -530,10 +608,26 @@ main(int argc, char **argv)
}
}
if (mtu == 0) {
if (mtu <= 0) {
warnx("Bad MTU given.\n");
usage();
}
if(port < 1 || port > 65535) {
warnx("Bad port number given.\n");
usage();
}
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);
}
if (debug) {
printf("Debug level %d enabled, will stay in foreground.\n", debug);
printf("Add more -D switches to set higher debug level.\n");
foreground = 1;
}
if (listen_ip == INADDR_NONE) {
warnx("Bad IP address to listen on.\n");
@ -545,8 +639,9 @@ main(int argc, char **argv)
if ((tun_fd = open_tun(device)) == -1)
goto cleanup0;
if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
goto cleanup1;
if (!skipipconfig)
if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
goto cleanup1;
if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
goto cleanup2;
@ -564,7 +659,9 @@ main(int argc, char **argv)
signal(SIGINT, sigint);
if (username != NULL) {
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
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();
}

14
src/osflags Normal file
View File

@ -0,0 +1,14 @@
#!/bin/sh
case $1 in
link)
case `uname` in
SunOS | solaris)
echo '-lsocket -lnsl';
;;
esac
;;
*)
;;
esac

View File

@ -25,8 +25,7 @@ struct user {
time_t last_pkt;
int seed;
in_addr_t tun_ip;
struct sockaddr host;
int addrlen;
struct in_addr host;
struct query q;
struct packet inpacket;
struct packet outpacket;

View File

@ -21,6 +21,6 @@ $(TEST): $(OBJS) $(SRCOBJS)
clean:
@echo "Cleaning..."
@echo "Cleaning tests/"
@rm -f *~ *.core $(TEST) $(OBJS)

View File

@ -31,7 +31,7 @@ static struct tuple
} testpairs[] = {
{ "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
{ "abc123", "mfrggmjsgm" },
{ NULL, NULL }
{ NULL, NULL }
};
START_TEST(test_base32_encode)
@ -46,8 +46,8 @@ START_TEST(test_base32_encode)
val = base32_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].b));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
}
END_TEST
@ -65,8 +65,8 @@ START_TEST(test_base32_decode)
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a));
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
}
END_TEST

View File

@ -31,7 +31,7 @@ static struct tuple
} testpairs[] = {
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
{ "abc123", "ywjJmtiZ" },
{
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
@ -45,7 +45,7 @@ static struct tuple
"776543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9abba87654"
"3210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfe999dcba"
},
{
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
@ -59,7 +59,7 @@ static struct tuple
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcbaML87654321"
"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
},
{ NULL, NULL }
{ NULL, NULL }
};
START_TEST(test_base64_encode)
@ -74,8 +74,8 @@ START_TEST(test_base64_encode)
val = base64_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].b));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
}
END_TEST
@ -93,8 +93,8 @@ START_TEST(test_base64_decode)
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a));
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
}
END_TEST

View File

@ -33,24 +33,24 @@
static void dump_packet(char *, size_t);
static char queryPacket[] =
static char queryPacket[] =
"\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 answerPacket[] =
"\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
"\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20"
"\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
"\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
static char *msgData = "this is the message to be delivered";
static char *topdomain = "kryo.se";
static char *innerData = "HELLO this is the test data";
START_TEST(test_encode_query)
@ -88,7 +88,7 @@ START_TEST(test_encode_query)
dump_packet(buf, ret);
}
fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
@ -112,7 +112,7 @@ START_TEST(test_decode_query)
unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);
fail_unless(strncmp(buf, innerData, strlen(innerData)) == 0, "Did not extract expected host: '%s'", buf);
fail_unless(strlen(buf) == strlen(innerData), va_str("Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf));
fail_unless(strlen(buf) == strlen(innerData), "Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf);
}
END_TEST
@ -135,7 +135,7 @@ START_TEST(test_encode_response)
len = sizeof(answerPacket) - 1; /* Skip extra null character */
fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
@ -150,7 +150,7 @@ START_TEST(test_decode_response)
ret = dns_decode(buf, len, NULL, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), va_str("Bad data length: %d, expected %d", ret, strlen(msgData)));
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
}
END_TEST

View File

@ -27,9 +27,9 @@ struct tuple
char *a;
char *b;
} dottests[] = {
{ "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
{ "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a"},
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
{ "abc123", "abc123" },
{ NULL, NULL }
@ -49,7 +49,7 @@ START_TEST(test_inline_dotify)
inline_dotify(b, sizeof(temp));
fail_unless(strcmp(dottests[i].b, temp) == 0,
va_str("'%s' != '%s'", temp, dottests[i].b));
"'%s' != '%s'", temp, dottests[i].b);
i++;
}
}
@ -69,7 +69,7 @@ START_TEST(test_inline_undotify)
inline_undotify(b, sizeof(temp));
fail_unless(strcmp(dottests[i].a, temp) == 0,
va_str("'%s' != '%s'", temp, dottests[i].a));
"'%s' != '%s'", temp, dottests[i].a);
i++;
}
}

View File

@ -33,7 +33,7 @@
#include "dns.h"
#include "read.h"
#include "test.h"
START_TEST(test_read_putshort)
{
unsigned short k;
@ -44,15 +44,15 @@ START_TEST(test_read_putshort)
for (i = 0; i < 65536; i++) {
p = (char*)&k;
putshort(&p, i);
fail_unless(ntohs(k) == i,
va_str("Bad value on putshort for %d: %d != %d",
i, ntohs(k), i));
fail_unless(ntohs(k) == i,
"Bad value on putshort for %d: %d != %d",
i, ntohs(k), i);
p = (char*)&k;
readshort(NULL, &p, (short *) &l);
fail_unless(l == i,
va_str("Bad value on readshort for %d: %d != %d",
i, l, i));
"Bad value on readshort for %d: %d != %d",
i, l, i);
}
}
END_TEST
@ -71,14 +71,14 @@ START_TEST(test_read_putlong)
putlong(&p, j);
fail_unless(ntohl(k) == j,
va_str("Bad value on putlong for %d: %d != %d", i, ntohl(j), j));
fail_unless(ntohl(k) == j,
"Bad value on putlong for %d: %d != %d", i, ntohl(j), j);
p = (char*)&k;
readlong(NULL, &p, &l);
fail_unless(l == j,
va_str("Bad value on readlong for %d: %d != %d", i, l, j));
"Bad value on readlong for %d: %d != %d", i, l, j);
}
}
END_TEST
@ -87,11 +87,11 @@ START_TEST(test_read_name)
{
unsigned char emptyloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char infloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char longname[] =
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char longname[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
@ -100,15 +100,15 @@ START_TEST(test_read_name)
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x00\x00\x01\x00\x01";
unsigned char onejump[] =
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 };
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 };
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
unsigned char *jumper;
char buf[1024];
char *data;
@ -119,13 +119,13 @@ START_TEST(test_read_name)
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';
@ -136,7 +136,7 @@ START_TEST(test_read_name)
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));
@ -149,7 +149,7 @@ START_TEST(test_read_name)
fail_unless(buf[0] == 0, NULL);
}
free(jumper);
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump2));
if (jumper) {
@ -158,8 +158,8 @@ START_TEST(test_read_name)
rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
fail_unless(rv == 4, NULL);
fail_unless(strcmp("BA.", buf) == 0,
va_str("buf is not BA: %s", buf));
fail_unless(strcmp("BA.", buf) == 0,
"buf is not BA: %s", buf);
}
free(jumper);
}
@ -184,11 +184,11 @@ START_TEST(test_putname)
fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
}
END_TEST
START_TEST(test_putname_nodot)
{
char buf[256];
char *nodot =
char *nodot =
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *b;
@ -205,11 +205,11 @@ START_TEST(test_putname_nodot)
fail_unless(b == buf, NULL);
}
END_TEST
START_TEST(test_putname_toolong)
{
char buf[256];
char *toolong =
char *toolong =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."

View File

@ -22,20 +22,6 @@
#include "test.h"
char *
va_str(const char *fmt, ...)
{
static char buf[512];
va_list ap;
memset(buf, 0, sizeof(buf));
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
int
main()
{
@ -68,7 +54,7 @@ main()
suite_add_tcase(iodine, test);
runner = srunner_create(iodine);
srunner_run_all(runner, CK_VERBOSE);
srunner_run_all(runner, CK_MINIMAL);
failed = srunner_ntests_failed(runner);
srunner_free(runner);