mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-25 06:26:05 +03:00
Release 0.5.1
This commit is contained in:
parent
f41c4bb9f3
commit
6536fc7c5d
15
CHANGELOG
15
CHANGELOG
@ -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,
|
||||
|
23
Makefile
23
Makefile
@ -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
62
README-win32.txt
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
46
src/base32.c
46
src/base32.c
@ -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;
|
||||
|
19
src/base64.c
19
src/base64.c
@ -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
|
||||
|
150
src/common.c
150
src/common.c
@ -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
|
||||
|
||||
|
33
src/common.h
33
src/common.h
@ -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
|
||||
|
20
src/dns.c
20
src/dns.c
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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__*/
|
||||
|
||||
|
346
src/iodine.c
346
src/iodine.c
@ -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);
|
||||
|
||||
@ -489,20 +497,15 @@ send_codec_switch(int fd, int userid, int bits)
|
||||
}
|
||||
|
||||
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 */
|
||||
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;
|
||||
|
||||
perform_login:
|
||||
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,33 +712,45 @@ 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) {
|
||||
}
|
||||
|
||||
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;
|
||||
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)) {
|
||||
int max_fragsize = 0;
|
||||
|
||||
max_fragsize = 0;
|
||||
fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n");
|
||||
while (running && range > 0 && (range >= 8 || !max_fragsize)) {
|
||||
for (i=0; running && i<3 ;i++) {
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
@ -721,40 +768,64 @@ autodetect_max_fragsize:
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, ".");
|
||||
fflush(stderr);
|
||||
}
|
||||
range >>= 1;
|
||||
if (max_fragsize == proposed_fragsize) {
|
||||
/* Try bigger */
|
||||
proposed_fragsize += range;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%d not ok.. ", proposed_fragsize);
|
||||
fflush(stdout);
|
||||
range >>= 1;
|
||||
} else {
|
||||
/* Try smaller */
|
||||
fprintf(stderr, "%d not ok.. ", proposed_fragsize);
|
||||
fflush(stderr);
|
||||
proposed_fragsize -= range;
|
||||
}
|
||||
}
|
||||
if (!running) {
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
warnx("stopped while autodetecting fragment size (Try probing manually with -m)");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (range == 0) {
|
||||
/* Tried all the way down to 2 and found no good size */
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
warnx("found no accepted fragment size. (Try probing manually with -m)");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
printf("will use %d\n", max_downstream_frag_size);
|
||||
}
|
||||
printf("Setting downstream fragment size to max %d...\n", max_downstream_frag_size);
|
||||
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;
|
||||
@ -894,6 +1024,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], '/');
|
||||
if (__progname == NULL)
|
||||
@ -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;
|
||||
|
176
src/iodined.c
176
src/iodined.c
@ -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;
|
||||
@ -927,6 +978,10 @@ main(int argc, char **argv)
|
||||
|
||||
b32 = get_base32_encoder();
|
||||
|
||||
#ifdef WINDOWS32
|
||||
WSAStartup(req_version, &wsa_data);
|
||||
#endif
|
||||
|
||||
#if !defined(BSD) && !defined(__GLIBC__)
|
||||
__progname = strrchr(argv[0], '/');
|
||||
if (__progname == NULL)
|
||||
@ -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:
|
||||
|
@ -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"
|
||||
|
||||
/*
|
||||
|
@ -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';
|
||||
;;
|
||||
|
271
src/tun.c
271
src/tun.c
@ -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,7 +395,11 @@ tun_setip(const char *ip, int netbits)
|
||||
netmask <<= (32 - netbits);
|
||||
net.s_addr = htonl(netmask);
|
||||
|
||||
if (inet_addr(ip) != INADDR_NONE) {
|
||||
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,
|
||||
@ -206,7 +407,7 @@ tun_setip(const char *ip, int netbits)
|
||||
ip,
|
||||
inet_ntoa(net));
|
||||
|
||||
printf("Setting IP of %s to %s\n", if_name, ip);
|
||||
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
|
||||
#ifndef LINUX
|
||||
r = system(cmdline);
|
||||
if(r != 0) {
|
||||
@ -216,33 +417,67 @@ tun_setip(const char *ip, int netbits)
|
||||
"/sbin/route add %s/%d %s",
|
||||
ip, netbits, ip);
|
||||
}
|
||||
printf("Adding route %s/%d to %s\n", ip, netbits, ip);
|
||||
fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip);
|
||||
#endif
|
||||
return system(cmdline);
|
||||
} else {
|
||||
printf("Invalid IP: %s!\n", ip);
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
|
11
src/user.c
11
src/user.c
@ -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
85
src/windows.h
Normal 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
|
@ -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"`
|
||||
|
||||
|
@ -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));
|
||||
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));
|
||||
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(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;
|
||||
}
|
||||
|
@ -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));
|
||||
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));
|
||||
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(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;
|
||||
}
|
||||
|
62
tests/dns.c
62
tests/dns.c
@ -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
88
tests/fw_query.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
135
tests/read.c
135
tests/read.c
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 *, ...);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user