mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-24 22:16:11 +03:00
Tagged iodine 0.4.2
This commit is contained in:
parent
d27bd67997
commit
e45bdece8e
17
CHANGELOG
17
CHANGELOG
@ -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
|
||||
|
2
Makefile
2
Makefile
@ -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..."
|
||||
|
22
man/iodine.8
22
man/iodine.8
@ -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:
|
||||
|
@ -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)
|
||||
|
58
src/common.c
58
src/common.c
@ -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;
|
||||
}
|
||||
|
@ -54,4 +54,6 @@ void do_detach();
|
||||
|
||||
void read_password(char*, size_t);
|
||||
|
||||
int check_topdomain(char *);
|
||||
|
||||
#endif
|
||||
|
10
src/dns.c
10
src/dns.c
@ -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;
|
||||
|
34
src/iodine.c
34
src/iodine.c
@ -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) {
|
||||
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();
|
||||
}
|
||||
|
227
src/iodined.c
227
src/iodined.c
@ -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,33 +140,43 @@ 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);
|
||||
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);
|
||||
@ -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;
|
||||
dns_decode(NULL, 0, q, QR_QUERY, packet, r);
|
||||
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
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,11 +608,27 @@ 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");
|
||||
usage();
|
||||
@ -545,6 +639,7 @@ main(int argc, char **argv)
|
||||
|
||||
if ((tun_fd = open_tun(device)) == -1)
|
||||
goto cleanup0;
|
||||
if (!skipipconfig)
|
||||
if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
|
||||
goto cleanup1;
|
||||
if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
|
||||
@ -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
14
src/osflags
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
case $1 in
|
||||
link)
|
||||
|
||||
case `uname` in
|
||||
SunOS | solaris)
|
||||
echo '-lsocket -lnsl';
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
@ -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;
|
||||
|
@ -21,6 +21,6 @@ $(TEST): $(OBJS) $(SRCOBJS)
|
||||
|
||||
|
||||
clean:
|
||||
@echo "Cleaning..."
|
||||
@echo "Cleaning tests/"
|
||||
@rm -f *~ *.core $(TEST) $(OBJS)
|
||||
|
||||
|
@ -47,7 +47,7 @@ START_TEST(test_base32_encode)
|
||||
|
||||
fail_unless(val > 0, strerror(errno));
|
||||
fail_unless(strcmp(buf, testpairs[i].b) == 0,
|
||||
va_str("'%s' != '%s'", buf, testpairs[i].b));
|
||||
"'%s' != '%s'", buf, testpairs[i].b);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
@ -66,7 +66,7 @@ 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));
|
||||
"'%s' != '%s'", buf, testpairs[i].a);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
@ -75,7 +75,7 @@ START_TEST(test_base64_encode)
|
||||
|
||||
fail_unless(val > 0, strerror(errno));
|
||||
fail_unless(strcmp(buf, testpairs[i].b) == 0,
|
||||
va_str("'%s' != '%s'", buf, testpairs[i].b));
|
||||
"'%s' != '%s'", buf, testpairs[i].b);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
@ -94,7 +94,7 @@ 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));
|
||||
"'%s' != '%s'", buf, testpairs[i].a);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
@ -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
|
||||
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
14
tests/read.c
14
tests/read.c
@ -45,14 +45,14 @@ START_TEST(test_read_putshort)
|
||||
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));
|
||||
"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
|
||||
@ -72,13 +72,13 @@ 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));
|
||||
"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
|
||||
@ -159,7 +159,7 @@ START_TEST(test_read_name)
|
||||
|
||||
fail_unless(rv == 4, NULL);
|
||||
fail_unless(strcmp("BA.", buf) == 0,
|
||||
va_str("buf is not BA: %s", buf));
|
||||
"buf is not BA: %s", buf);
|
||||
}
|
||||
free(jumper);
|
||||
}
|
||||
|
16
tests/test.c
16
tests/test.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user