Imported Upstream version 0.7.0
authorgregor herrmann <gregoa@debian.org>
Sun, 5 Oct 2014 12:00:51 +0000 (14:00 +0200)
committergregor herrmann <gregoa@debian.org>
Sun, 5 Oct 2014 12:47:50 +0000 (14:47 +0200)
55 files changed:
CHANGELOG
Makefile
README
README-android.txt [new file with mode: 0644]
README-win32.txt
doc/iodine-server.service [new file with mode: 0644]
doc/iodine-server.socket [new file with mode: 0644]
doc/proto_00000502.txt
man/iodine.8
src/Android.mk [new file with mode: 0644]
src/Makefile
src/android_dns.h [new file with mode: 0644]
src/base128.c
src/base32.c
src/base32.h
src/base64.c
src/base64.h
src/client.c
src/client.h
src/common.c
src/common.h
src/dns.c
src/dns.h
src/encoding.c
src/encoding.h
src/fw_query.c
src/fw_query.h
src/iodine.c
src/iodined.c
src/login.c
src/login.h
src/md5.h
src/osflags [changed mode: 0644->0755]
src/read.c
src/read.h
src/tun.c
src/tun.h
src/user.c
src/user.h
src/util.c
src/util.h
src/version.h
src/windows.h
tests/Makefile
tests/base32.c
tests/base64.c
tests/common.c [new file with mode: 0644]
tests/dns.c
tests/encoding.c
tests/fw_query.c
tests/login.c
tests/read.c
tests/test.c
tests/test.h
tests/user.c

index 888beacff9d9dfcee4596c4fecc776e4c63d9506..93430d977d50be70755032a6669ad8e8a9c1fc3e 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,7 +5,30 @@ iodine - http://code.kryo.se/iodine
 
 CHANGES:
 
-2010-02-13: 0.6.0-rc1 "Hotspotify"
+2014-06-16: 0.7.0 "Kryoptonite"
+       - Partial IPv6 support (#107)
+          Client can connect to iodined through an relaying IPv6
+          nameserver. Server only supports IPv4 for now.
+          Traffic inside tunnel is IPv4.
+       - Add socket activation for systemd, by Michael Scherer.
+       - Add automated lookup of external ip (via -n auto).
+       - Bugfix for OS X (Can't assign requested address)
+       - Fix DNS tunneling bug caused by uninitialized variable, #94
+       - Handle spaces when entering password interactively, fixes #93.
+               Patch by Hagar.
+       - Add -R option to set OpenBSD routing domain for the DNS socket.
+               Patch by laurent at gouloum fr, fixes #95.
+       - Add android patches and makefile, from Marcel Bokhorst, fixes #105.
+       - Added missing break in iodine.c, by Pavel Pergamenshchik, #108.
+       - A number of minor patches from Frank Denis, Gregor Herrmann and
+               Barak A. Pearlmutter.
+       - Testcase compilation fixes for OS X and FreeBSD
+       - Do not let sockets be inherited by sub-processes, fixes #99.
+       - Add unspecified RR type (called PRIVATE; id 65399, in private use
+               range). For servers with RFC3597 support. Fixes #97.
+       - Fix authentication bypass vulnerability; found by Oscar Reparaz.
+
+2010-02-06: 0.6.0-rc1 "Hotspotify"
        - Fixed tunnel not working on Windows.
        - Any device name is now supported on Windows, fixes #47.
        - Multiple installed TAP32 interfaces are now supported, fixes #46.
@@ -30,6 +53,7 @@ CHANGES:
        - Merged low-latency patch from Anne Bezemer, fixes #76.
        - Resolve client nameserver argument if given as hostname, fixes #82.
        - Open log before chroot, fixes #86: logging on FreeBSD.
+       - Merged big bugfix patch from Anne Bezemer, #88.
 
 2009-06-01: 0.5.2 "WifiFree"
        - Fixed client segfault on OS X, #57
index 01c232521ca8a19beb4003b24395bacab2a3b361..a75eaa8ec991e3a3a258070967f6ddf0db6383fa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-prefix=/usr/local
+prefix?=/usr/local
 sbindir=$(prefix)/sbin
 datadir=$(prefix)/share
 mandir=$(datadir)/man
@@ -16,24 +16,9 @@ RM_FLAGS=-f
 
 TARGETOS = `uname`
 
-all: 
+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)
        $(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine
@@ -48,7 +33,7 @@ uninstall:
        $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodine
        $(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined
        $(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8
-       
+
 test: all
        @echo "!! The check library is required for compiling and running the tests"
        @echo "!! Get it at http://check.sf.net"
@@ -58,5 +43,62 @@ clean:
        @echo "Cleaning..."
        @(cd src; $(MAKE) clean)
        @(cd tests; $(MAKE) clean)
-       @rm -rf bin iodine-latest-win32*
+       @rm -rf bin iodine-latest*
+
+#Helper target for windows/android zipfiles
+iodine-latest:
+       @rm -rf iodine-latest*
+       @mkdir -p iodine-latest
+       @echo "Create date: " > iodine-latest/VERSION.txt
+       @date >> iodine-latest/VERSION.txt
+       @echo "Git version: " >> iodine-latest/VERSION.txt
+       @git rev-parse HEAD >> iodine-latest/VERSION.txt
+       @for i in README CHANGELOG TODO; do cp $$i iodine-latest/$$i.txt; done
+       @unix2dos iodine-latest/*
+
+cross-android:
+       @(cd src; $(MAKE) base64u.c base64u.h)
+       @(cd src; ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk)
+
+iodine-latest-android.zip: iodine-latest
+       @mv iodine-latest iodine-latest-android
+       @mkdir -p iodine-latest-android/armeabi iodine-latest-android/x86
+       @$(MAKE) cross-android TARGET_ARCH_ABI=armeabi
+       @cp src/libs/armeabi/* iodine-latest-android/armeabi
+       @$(MAKE) cross-android TARGET_ARCH_ABI=x86
+       @cp src/libs/x86/* iodine-latest-android/x86
+       @cp README-android.txt iodine-latest-android
+       @zip -r iodine-latest-android.zip iodine-latest-android
+
+cross-mingw32:
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=i686-w64-mingw32-gcc all)
+
+cross-mingw64:
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=x86_64-w64-mingw32-gcc all)
+
+iodine-latest-windows.zip: iodine-latest
+       @mv iodine-latest iodine-latest-windows
+       @mkdir -p iodine-latest-windows/64bit iodine-latest-windows/32bit
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=i686-w64-mingw32-gcc clean all)
+       @i686-w64-mingw32-strip bin/iodine*
+       @for i in `ls bin`; do cp bin/$$i iodine-latest-windows/32bit/$$i.exe; done
+       @cp /usr/i686-w64-mingw32/bin/zlib1.dll iodine-latest-windows/32bit
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=x86_64-w64-mingw32-gcc clean all)
+       @x86_64-w64-mingw32-strip bin/iodine*
+       @for i in `ls bin`; do cp bin/$$i iodine-latest-windows/64bit/$$i.exe; done
+       @cp /usr/x86_64-w64-mingw32/bin/zlib1.dll iodine-latest-windows/64bit
+       @cp README-win32.txt iodine-latest-windows
+       @zip -r iodine-latest-windows.zip iodine-latest-windows
+
+cross-mingw:
+       @(cd src; $(MAKE) TARGETOS=windows32 CC=i686-mingw32-gcc all)
+
+iodine-latest-win32.zip: cross-mingw iodine-latest
+       @mv iodine-latest iodine-latest-win32
+       @mkdir -p iodine-latest-win32/bin
+       @i686-mingw32-strip bin/iodine*
+       @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-win32.txt iodine-latest-win32
+       @zip -r iodine-latest-win32.zip iodine-latest-win32
 
diff --git a/README b/README
index d9e3c291db216e0f367e649f4c647c47a279ae5e..cfc8ede69c549eb99607604aeac0394f8e6363a3 100644 (file)
--- a/README
+++ b/README
@@ -8,6 +8,17 @@ server. This can be usable in different situations where internet access is
 firewalled, but DNS queries are allowed.
 
 
+COMPILING:
+
+Iodine has no configure script. There are two optional features for Linux
+(SELinux and systemd support) that will be enabled automatically if the
+relevant header files are found in /usr/include. (See script at ./src/osflags)
+
+Run 'make' to compile the server and client binaries.
+Run 'make install' to copy binaries and manpage to the destination directory.
+Run 'make test' to compile and run the unit tests. (Requires the check library)
+
+
 QUICKSTART:
 
 Try it out within your own LAN! Follow these simple steps:
@@ -103,6 +114,16 @@ end of the tunnel. In this case, ping 192.168.99.1 from the iodine client, and
 
 MISC. INFO:
 
+IPv6:
+At the moment the iodined server only supports IPv4. The data inside the tunnel
+is IPv4 only.
+
+The client can use IPv4 or IPv6 nameservers to connect to iodined. The relay
+nameservers will translate between protocols automatically if needed. Use
+options -4 or -6 to force the client to use a specific IP version for its DNS
+queries. The client has to force IPv4 if it has dual-stack connectivity and
+the hostname handling the tunnel domain has both A and AAAA records.
+
 Routing:
 It is possible to route all traffic through the DNS tunnel. To do this, first
 add a host route to the nameserver used by iodine over the wired/wireless
@@ -156,12 +177,13 @@ packet, and one query can be max 256 chars. Each domain name part can be max
 63 chars. So your domain name and subdomain should be as short as possible to
 allow maximum upstream throughput.
 
-Several DNS request types are supported, with the NULL type expected to provide
-the largest downstream bandwidth. Other available types are TXT, SRV, MX,
-CNAME and A (returning CNAME), in decreasing bandwidth order. Normally the
+Several DNS request types are supported, with the NULL and PRIVATE types
+expected to provide the largest downstream bandwidth. The PRIVATE type uses
+value 65399 in the private-use range. Other available types are TXT, SRV, MX,
+CNAME and A (returning CNAME), in decreasing bandwidth order.  Normally the
 "best" request type is autodetected and used. However, DNS relays may impose
 limits on for example NULL and TXT, making SRV or MX actually the best choice.
-This is not autodetected, but can be forced using the -T option. It is
+This is not autodetected, but can be forced using the -T option.  It is
 advisable to try various alternatives especially when the autodetected request
 type provides a downstream fragment size of less than 200 bytes.
 
@@ -169,14 +191,14 @@ Note that SRV, MX and A (returning CNAME) queries may/will cause additional
 lookups by "smart" caching nameservers to get an actual IP address, which may
 either slow down or fail completely.
 
-DNS responses for non-NULL queries can be encoded with the same set of codecs
-as upstream data. This is normally also autodetected, but no fully exhaustive
-tests are done, so some problems may not be noticed when selecting more
-advanced codecs. In that case, you'll see failures/corruption in the fragment
-size autoprobe. In particular, several DNS relays have been found that change
-replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when that
-hostname exceeds ca. 180 characters. In these and similar cases, use the -O
-option to try other downstream codecs; Base32 should always work.
+DNS responses for non-NULL/PRIVATE queries can be encoded with the same set of
+codecs as upstream data. This is normally also autodetected, but no fully
+exhaustive tests are done, so some problems may not be noticed when selecting
+more advanced codecs. In that case, you'll see failures/corruption in the
+fragment size autoprobe. In particular, several DNS relays have been found that
+change replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when
+that hostname exceeds ca. 180 characters. In these and similar cases, use the
+-O option to try other downstream codecs; Base32 should always work.
 
 Normal operation now is for the server to _not_ answer a DNS request until
 the next DNS request has come in, a.k.a. being "lazy". This way, the server
@@ -337,8 +359,8 @@ THANKS:
 
 AUTHORS & LICENSE:
 
-Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
-Also major contributions by Anne Bezemer.
+Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>, 2006-2009 Bjorn
+Andersson <flex@kryo.se>. Also major contributions by Anne Bezemer.
 
 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
diff --git a/README-android.txt b/README-android.txt
new file mode 100644 (file)
index 0000000..f08c6cf
--- /dev/null
@@ -0,0 +1,45 @@
+\r
+\r
+iodine - http://code.kryo.se/iodine\r
+\r
+***********************************\r
+\r
+Extra README file for Android\r
+\r
+\r
+== Running iodine on Android:\r
+1. Get root access on your android device\r
+\r
+2. Find/build a compatible tun.ko for your specific Android kernel\r
+\r
+3. Copy tun.ko and the iodine binary to your device:\r
+   (Almost all devices need the armeabi binary. Only Intel powered \r
+   ones need the x86 build.)\r
+\r
+               adb push tun.ko /data/local/tmp\r
+               adb push iodine /data/local/tmp\r
+               adb shell\r
+               su\r
+               cd /data/local/tmp\r
+               chmod 777 iodine\r
+\r
+4. Run iodine (see the man page for parameters)\r
+\r
+               ./iodine ...\r
+\r
+For more information: http://blog.bokhorst.biz/5123\r
+\r
+== Building iodine for Android:\r
+1. Download and install the Android SDK and NDK\r
+\r
+2. Download and unpack the iodine sources\r
+\r
+3. Build:\r
+               cd src\r
+               make base64u.h base64u.c\r
+               ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk\r
+\r
+   or run "make cross-android" in the iodine root directory.\r
+   To build for other archs, specify TARGET_ARCH_ABI: \r
+               "make cross-android TARGET_ARCH_ABI=x86"\r
+\r
index eec675e7eb2922937b563120722a88ba97ea992e..de9124ba727ddb538b3d4948a2b9d0d14013b894 100644 (file)
@@ -8,6 +8,9 @@ Extra README file for Win32 related stuff
 \r
 \r
 == Running iodine on Windows:\r
+\r
+0. After iodine 0.6, you need Windows XP or newer to run.\r
+\r
 1. Install the TAP32 driver \r
    http://openvpn.net/index.php/open-source/downloads.html\r
    Choose OpenVPN 2.0.9 Windows Installer, when installing you can\r
diff --git a/doc/iodine-server.service b/doc/iodine-server.service
new file mode 100644 (file)
index 0000000..64d2ecc
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=Iodine Server
+After=local-fs.target network.target
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/iodine-server
+ExecStart=/usr/local/bin/iodined -i 30 -f $OPTIONS
+StandardOutput=syslog
+
+[Install]
+WantedBy=multi-user.target
diff --git a/doc/iodine-server.socket b/doc/iodine-server.socket
new file mode 100644 (file)
index 0000000..d6c57b8
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Iodine socket
+
+[Socket]
+ListenDatagram=53
+
+[Install]
+WantedBy=sockets.target
index 46cf2defcc09584df210b7a0bcf86d7c6f10b33a..831824d63f78eeddceb8a7a64668e60bd55ea4a9 100644 (file)
@@ -122,7 +122,8 @@ Server sends:
        s or S: Downstream encoding Base64, for TXT/CNAME/A/MX
        u or U: Downstream encoding Base64u, for TXT/CNAME/A/MX
        v or V: Downstream encoding Base128, for TXT/CNAME/A/MX
-       r or R: Downstream encoding Raw, for TXT/NULL (default for NULL)
+       r or R: Downstream encoding Raw, for PRIVATE/TXT/NULL (default for
+               PRIVATE and NULL)
        If codec unsupported for request type, server will use Base32; note
        that server will answer any mix of request types that a client sends.
        Server may disregard this option; client must always use the downstream
@@ -188,8 +189,8 @@ encoded with the chosen upstream codec.
 Downstream data starts with 2 byte header. Then payload data, which may be
 compressed.
 
-In NULL responses, downstream data is always raw. In all other response types,
-downstream data is encoded (see Options above).
+In NULL and PRIVATE responses, downstream data is always raw. In all other
+response types, downstream data is encoded (see Options above).
 Encoding type is indicated by 1 prefix char:
 TXT:
        End result is always DNS-chopped (series of len-prefixed strings
index 6eee603127d5c53d554e4aef84120ff05ce5d9c5..1d1e3332747a737e85853016d6318302915a6eef 100644 (file)
@@ -1,5 +1,5 @@
 .\" groff -man -Tascii iodine.8
-.TH IODINE 8 "DEC 2009" "User Manuals"
+.TH IODINE 8 "JUN 2014" "User Manuals"
 .SH NAME
 iodine, iodined \- tunnel IPv4 over DNS
 .SH SYNOPSIS
@@ -7,7 +7,7 @@ iodine, iodined \- tunnel IPv4 over DNS
 
 .B iodine [-h]
 
-.B iodine [-f] [-r] [-u
+.B iodine [-4] [-6] [-f] [-r] [-u
 .I user
 .B ] [-P
 .I password
@@ -17,6 +17,8 @@ iodine, iodined \- tunnel IPv4 over DNS
 .I chrootdir
 .B ] [-d
 .I device
+.B ] [-R
+.I rdomain
 .B ] [-m
 .I fragsize
 .B ] [-M
@@ -56,7 +58,11 @@ iodine, iodined \- tunnel IPv4 over DNS
 .B ] [-p
 .I port
 .B ] [-n
+(
+.B auto
+|
 .I external_ip
+)
 .B ] [-b
 .I dnsport
 .B ] [-P
@@ -65,6 +71,8 @@ iodine, iodined \- tunnel IPv4 over DNS
 .I context
 .B ] [-F
 .I pidfile
+.B ] [-i
+.I max_idle_time
 .B ]
 .I tunnel_ip
 .B [
@@ -124,11 +132,20 @@ Apply SELinux 'context' after initialization.
 Create 'pidfile' and write process id in it.
 .SS Client Options:
 .TP
+.B -4
+Force IPv4 DNS queries
+.TP
+.B -6
+Force IPv6 DNS queries
+.TP
 .B -r
 Skip raw UDP mode. If not used, iodine will try getting the public IP address
 of the iodined host and test if it is reachable directly. If it is, traffic
 will be sent to the server instead of the DNS relay.
 .TP
+.B -R rdomain
+Use OpenBSD routing domain 'rdomain' for the DNS connection.
+.TP
 .B -m fragsize
 Force maximum downstream fragment size. Not setting this will cause the
 client to automatically probe the maximum accepted downstream fragment size.
@@ -139,7 +156,7 @@ Usable range ca. 100 to 255.
 Use this option to scale back upstream bandwidth in favor of downstream
 bandwidth.
 Also useful for DNS servers that perform unreliably when using full-length
-hostnames, noticable when fragment size autoprobe returns very
+hostnames, noticeable when fragment size autoprobe returns very
 different results each time.
 .TP
 .B -T dnstype
@@ -152,6 +169,7 @@ more bandwidth.
 In that case, use this option to override the autodetection.
 In (expected) decreasing bandwidth order, the supported DNS request types are:
 .IR NULL ,
+.IR PRIVATE ,
 .IR TXT ,
 .IR SRV ,
 .IR MX ,
@@ -166,7 +184,10 @@ and
 .I A
 may/will cause additional lookups by "smart" caching
 nameservers to get an actual IP address, which may either slow down or fail
-completely.
+completely. The
+.IR PRIVATE
+type uses value 65399 (in the 'private use' range) and requires servers
+implementing RFC 3597.
 .TP
 .B -O downenc
 Force downstream encoding type for all query type responses except NULL.
@@ -218,7 +239,7 @@ connection after 60 seconds of inactivity.
 .TP
 .B -c
 Disable checking the client IP address on all incoming requests.
-By default, requests originating from non-matching IP adresses will be
+By default, requests originating from non-matching IP addresses will be
 rejected, however this will cause problems when requests are routed
 via a cluster of DNS servers.
 .TP
@@ -232,10 +253,10 @@ Increase debug level. Level 1 prints info about each RX/TX packet.
 Implies the
 .B -f
 option.
-On level 2 (-DD) or higher, DNS queries will be printed literally.
+On level 2 (\-DD) or higher, DNS queries will be printed literally.
 When using Base128 upstream encoding, this is best viewed as
 ISO Latin-1 text instead of (illegal) UTF-8.
-This is easily done with : "LC_ALL=C luit iodined -DD ..."
+This is easily done with : "LC_ALL=C luit iodined \-DD ..."
 (see luit(1)).
 .TP
 .B -m mtu
@@ -250,26 +271,36 @@ By default, incoming requests are accepted from all interfaces.
 .TP
 .B -p port
 Make the server listen on 'port' instead of 53 for traffic. 
+If 'listen_ip' does not include localhost, this 'port' can be the same
+as 'dnsport'.
 .B Note:
 You must make sure the dns requests are forwarded to this port yourself.
 .TP
-.B -n external_ip
+.B -n auto|external_ip
 The IP address to return in NS responses. Default is to return the address used
 as destination in the query.
+If external_ip is 'auto', iodined will use externalip.net web service to
+retrieve the external IP of the host and use that for NS responses.
 .TP
 .B -b dnsport
 If this port is specified, all incoming requests not inside the tunnel domain
 will be forwarded to this port on localhost, to be handled by a real dns.
+If 'listen_ip' does not include localhost, this 'dnsport' can be the
+same as 'port'.
 .B Note:
 The forwarding is not fully transparent, and not advised for use
 in production environments.
+.TP
+.B -i max_idle_time
+Make the server stop itself after max_idle_time seconds if no traffic have been received.
+This should be combined with systemd or upstart on demand activation for being effective.
 .SS Client Arguments:
 .TP
 .B nameserver
 The nameserver to use to relay the dns traffic. This can be any relaying
 nameserver or the server running iodined if reachable. This field can be
-given as an IP address, or as a hostname. This argument is optional, and 
-if not specified a nameserver will be read from the
+given as an IPv4/IPv6 address or as a hostname. This argument is optional,
+and if not specified a nameserver will be read from the
 .I /etc/resolv.conf
 file.
 .TP
@@ -285,7 +316,7 @@ must be the same on both the client and the server.
 .B tunnel_ip[/netmask]
 This is the server's ip address on the tun interface. The client will be
 given the next ip number in the range. It is recommended to use the 
-10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden
+10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overridden
 by specifying it here. Using a smaller network will limit the number of
 concurrent users.
 .TP
@@ -327,7 +358,6 @@ is set, iodined will use the value it is set to as password instead of asking
 for one. The
 .B -P
 option still has precedence.
-.El
 .SH SEE ALSO
 The README file in the source distribution contains some more elaborate
 information.
diff --git a/src/Android.mk b/src/Android.mk
new file mode 100644 (file)
index 0000000..8f7c729
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# iodine for Android
+#
+# by Marcel Bokhorst
+# http://blog.bokhorst.biz/5123/computers-en-internet/iodine-for-android/
+#
+# cd iodine-0.6.0-rc1/src
+# make base64u.h base64u.c
+# .../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := iodine
+LOCAL_SRC_FILES := tun.c dns.c read.c encoding.c login.c base32.c base64.c base64u.c base128.c md5.c common.c iodine.c client.c util.c
+LOCAL_CFLAGS    := -c -DANDROID -DLINUX -DIFCONFIGPATH=\"/system/bin/\" -Wall
+LOCAL_LDLIBS    := -lz
+
+include $(BUILD_EXECUTABLE)
+
index a5b9838290cfeeb57284ec4fdd1281c485091476..80bd345d26152fbccd5893bff487c7ca81e8a1e9 100644 (file)
@@ -9,7 +9,7 @@ ARCH = `uname -m`
 
 LIBPATH = -L.
 LDFLAGS +=  -lz `sh osflags $(TARGETOS) link` $(LIBPATH)
-CFLAGS += -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags`
+CFLAGS += -std=c99 -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags`
 
 all: stateos $(CLIENT) $(SERVER)
 
@@ -26,7 +26,7 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
        @mkdir -p ../bin
        @$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
 
-.c.o: 
+.c.o:
        @echo CC $<
        @$(CC) $(CFLAGS) $< -o $@
 
@@ -43,4 +43,5 @@ base64u.h: base64.h
 clean:
        @echo "Cleaning src/"
        @rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.*
+       @rm -rf obj libs #android stuff
 
diff --git a/src/android_dns.h b/src/android_dns.h
new file mode 100644 (file)
index 0000000..dafd8ec
--- /dev/null
@@ -0,0 +1,39 @@
+
+#ifndef __FIX_ANDROID_H__
+#define __FIX_ANDROID_H__
+
+typedef struct {
+       unsigned id :16;
+       unsigned rd :1;
+       unsigned tc :1;
+       unsigned aa :1;
+       unsigned opcode :4;
+       unsigned qr :1;
+       unsigned rcode :4;
+       unsigned cd: 1;
+       unsigned ad: 1;
+       unsigned unused :1;
+       unsigned ra :1;
+       unsigned qdcount :16;
+       unsigned ancount :16;
+       unsigned nscount :16;
+       unsigned arcount :16;
+} HEADER;
+
+#define NOERROR                0
+#define FORMERR                1
+#define SERVFAIL       2
+#define NXDOMAIN       3
+#define NOTIMP         4
+#define REFUSED                5
+
+#define C_IN           1
+
+#define T_A                    1
+#define T_CNAME                5
+#define T_NULL         10
+#define T_MX           15
+#define T_TXT          16
+#define T_SRV          33
+
+#endif
index 32a29f8b06c006ad2f570ee3ccb3778f8dade6ca..7ddc38c0b012e135d2a94d0fc84f1d8849829c79 100644 (file)
@@ -42,7 +42,7 @@
  * accent chars since they might readily be entered in normal use,
  * don't use 254-255 because of possible function overloading in DNS systems.
  */
-static const unsigned char cb128[] = 
+static const unsigned char cb128[] =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        "\274\275\276\277"
        "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
@@ -75,19 +75,19 @@ struct encoder
        return &base128_encoder;
 }
 
-static int 
+static int
 base128_handles_dots()
 {
        return 0;
 }
 
-static int 
+static int
 base128_blksize_raw()
 {
        return BLKSIZE_RAW;
 }
 
-static int 
+static int
 base128_blksize_enc()
 {
        return BLKSIZE_ENC;
@@ -109,7 +109,7 @@ base128_reverse_init()
        }
 }
 
-static int 
+static int
 base128_encode(char *buf, size_t *buflen, const void *data, size_t size)
 /*
  * Fills *buf with max. *buflen characters, encoding size bytes of *data.
@@ -231,7 +231,7 @@ base128_decode(void *buf, size_t *buflen, const char *str, size_t slen)
                if (iout >= *buflen || iin + 1 >= slen ||
                    str[iin] == '\0' || str[iin + 1] == '\0')
                        break;
-               ubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) | 
+               ubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) |
                             ((REV128(ustr[iin + 1]) & 0x40) >> 6);
                iin++;                  /* 0 used up, iin=1 */
                iout++;
index 8731a9252416804a61b9c55a664e00081020f6d5..d971ce25b01f400a5f34ed88c08533ec966ee91e 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
  * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -25,9 +26,9 @@
 #define BLKSIZE_RAW 5
 #define BLKSIZE_ENC 8
 
-static const char cb32[] = 
+static const char cb32[] =
        "abcdefghijklmnopqrstuvwxyz012345";
-static const char cb32_ucase[] = 
+static const char cb32_ucase[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
 static unsigned char rev32[256];
 static int reverse_init = 0;
@@ -55,19 +56,19 @@ struct encoder
        return &base32_encoder;
 }
 
-static int 
+static int
 base32_handles_dots()
 {
        return 0;
 }
 
-static int 
+static int
 base32_blksize_raw()
 {
        return BLKSIZE_RAW;
 }
 
-static int 
+static int
 base32_blksize_enc()
 {
        return BLKSIZE_ENC;
@@ -104,7 +105,7 @@ b32_8to5(int in)
        return rev32[in];
 }
 
-static int 
+static int
 base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
 /*
  * Fills *buf with max. *buflen characters, encoding size bytes of *data.
@@ -222,7 +223,7 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
                if (iout >= *buflen || iin + 1 >= slen ||
                    str[iin] == '\0' || str[iin + 1] == '\0')
                        break;
-               ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) | 
+               ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
                             ((REV32(str[iin + 1]) & 0x1c) >> 2);
                iin++;                  /* 0 used up, iin=1 */
                iout++;
@@ -231,8 +232,8 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
                    str[iin] == '\0' || str[iin + 1] == '\0' ||
                    str[iin + 2] == '\0')
                        break;
-               ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) | 
-                            ((REV32(str[iin + 1]) & 0x1f) << 1) | 
+               ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
+                            ((REV32(str[iin + 1]) & 0x1f) << 1) |
                             ((REV32(str[iin + 2]) & 0x10) >> 4);
                iin += 2;               /* 1,2 used up, iin=3 */
                iout++;
index 497ca33e1a47b1956523995de3c742ba1a9ca50f..53975c5c71edd585961c9b141ce12b924cf90318 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 5218c091414286228e3dcf527cf48a0a32a1e6a6..71bbcf130e896fee92c3c29eb17a290dab59995b 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
  * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -27,7 +28,7 @@
 
 /* Note: the "unofficial" char is last here, which means that the \377 pattern
    in DOWNCODECCHECK1 ('Y' request) will properly test it. */
-static const char cb64[] = 
+static const char cb64[] =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
 static unsigned char rev64[256];
 static int reverse_init = 0;
@@ -55,19 +56,19 @@ struct encoder
        return &base64_encoder;
 }
 
-static int 
+static int
 base64_handles_dots()
 {
        return 0;
 }
 
-static int 
+static int
 base64_blksize_raw()
 {
        return BLKSIZE_RAW;
 }
 
-static int 
+static int
 base64_blksize_enc()
 {
        return BLKSIZE_ENC;
@@ -89,7 +90,7 @@ base64_reverse_init()
        }
 }
 
-static int 
+static int
 base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
 /*
  * Fills *buf with max. *buflen characters, encoding size bytes of *data.
@@ -177,7 +178,7 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
                if (iout >= *buflen || iin + 1 >= slen ||
                    str[iin] == '\0' || str[iin + 1] == '\0')
                        break;
-               ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) | 
+               ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |
                             ((REV64(str[iin + 1]) & 0x30) >> 4);
                iin++;                  /* 0 used up, iin=1 */
                iout++;
@@ -185,7 +186,7 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
                if (iout >= *buflen || iin + 1 >= slen ||
                    str[iin] == '\0' || str[iin + 1] == '\0')
                        break;
-               ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) | 
+               ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |
                             ((REV64(str[iin + 1]) & 0x3c) >> 2);
                iin++;                  /* 1 used up, iin=2 */
                iout++;
index d550cf3de5fbb3774367ae089aea8371d9eb4bc8..662175edd07d9627c5ab03d0bff7127beeb1f392 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 0036b0ed093431a7b8fbb325ab10d3190f5b2355..0f951accbf05cb209aa128921f84af262cb05f37 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -19,6 +20,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/param.h>
 
 #ifdef WINDOWS32
 #include "windows.h"
-#include <winsock2.h>
 #else
+#ifdef ANDROID
+#include "android_dns.h"
+#endif
 #include <arpa/nameser.h>
 #ifdef DARWIN
 #define BIND_8_COMPAT
@@ -58,7 +62,8 @@ static void handshake_lazyoff(int dns_fd);
 static int running;
 static const char *password;
 
-static struct sockaddr_in nameserv;
+static struct sockaddr_storage nameserv;
+static int nameserv_len;
 static struct sockaddr_in raw_serv;
 static const char *topdomain;
 
@@ -89,10 +94,10 @@ static struct encoder *b128;
 /* The encoder used for data packets
  * Defaults to Base32, can be changed after handshake */
 static struct encoder *dataenc;
-  
+
 /* The encoder to use for downstream data */
 static char downenc = ' ';
+
 /* set query type to send */
 static unsigned short do_qtype = T_UNSET;
 
@@ -146,49 +151,10 @@ client_get_conn()
 }
 
 void
-client_set_nameserver(const char *cp, int port) 
+client_set_nameserver(struct sockaddr_storage *addr, int addrlen)
 {
-       struct in_addr addr;
-
-       if (inet_aton(cp, &addr) != 1) {
-               /* try resolving if a domain is given */
-               struct hostent *host;
-               const char *err;
-               host = gethostbyname(cp);
-               if (host != NULL && h_errno > 0) {
-                       int i = 0;
-                       while (host->h_addr_list[i] != 0) {
-                               addr = *(struct in_addr *) host->h_addr_list[i++];
-                               fprintf(stderr, "Resolved %s to %s\n", cp, inet_ntoa(addr));
-                               goto setaddr;
-                       }
-               }
-#ifndef WINDOWS32
-               err = hstrerror(h_errno);
-#else
-               {
-                       DWORD wserr = WSAGetLastError();
-                       switch (wserr) {
-                       case WSAHOST_NOT_FOUND:
-                               err = "Host not found";
-                               break;
-                       case WSANO_DATA:
-                               err = "No data record found";
-                               break;
-                       default:
-                               err = "Unknown error";
-                               break;
-                       }
-               }
-#endif /* !WINDOWS32 */
-               errx(1, "error resolving nameserver '%s': %s", cp, err);
-       }
-
-setaddr:
-       memset(&nameserv, 0, sizeof(nameserv));
-       nameserv.sin_family = AF_INET;
-       nameserv.sin_port = htons(port);
-       nameserv.sin_addr = addr;
+       memcpy(&nameserv, addr, addrlen);
+       nameserv_len = addrlen;
 }
 
 void
@@ -203,11 +169,13 @@ client_set_password(const char *cp)
        password = cp;
 }
 
-void
-set_qtype(char *qtype)
+int
+client_set_qtype(char *qtype)
 {
        if (!strcasecmp(qtype, "NULL"))
                do_qtype = T_NULL;
+       else if (!strcasecmp(qtype, "PRIVATE"))
+               do_qtype = T_PRIVATE;
        else if (!strcasecmp(qtype, "CNAME"))
                do_qtype = T_CNAME;
        else if (!strcasecmp(qtype, "A"))
@@ -218,14 +186,16 @@ set_qtype(char *qtype)
                do_qtype = T_SRV;
        else if (!strcasecmp(qtype, "TXT"))
                do_qtype = T_TXT;
+       return (do_qtype == T_UNSET);
 }
 
 char *
-get_qtype()
+client_get_qtype()
 {
        char *c = "UNDEFINED";
 
        if (do_qtype == T_NULL)         c = "NULL";
+       else if (do_qtype == T_PRIVATE) c = "PRIVATE";
        else if (do_qtype == T_CNAME)   c = "CNAME";
        else if (do_qtype == T_A)       c = "A";
        else if (do_qtype == T_MX)      c = "MX";
@@ -236,7 +206,7 @@ get_qtype()
 }
 
 void
-set_downenc(char *encoding)
+client_set_downenc(char *encoding)
 {
        if (!strcasecmp(encoding, "base32"))
                downenc = 'T';
@@ -250,7 +220,7 @@ set_downenc(char *encoding)
                downenc = 'R';
 }
 
-void 
+void
 client_set_selecttimeout(int select_timeout)
 {
        selecttimeout = select_timeout;
@@ -302,7 +272,7 @@ send_query(int fd, char *hostname)
        fprintf(stderr, "  Sendquery: id %5d name[0] '%c'\n", q.id, hostname[0]);
 #endif
 
-       sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv));
+       sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, nameserv_len);
 
        /* There are DNS relays that time out quickly but don't send anything
           back on timeout.
@@ -369,7 +339,7 @@ send_packet(int fd, char cmd, const char *data, const size_t datalen)
        char buf[4096];
 
        buf[0] = cmd;
-       
+
        build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain,
                       b32, hostname_maxlen);
        send_query(fd, buf);
@@ -402,7 +372,7 @@ send_chunk(int fd)
        /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */
 
        buf[0] = userid_char;           /* First byte is hex userid */
-  
+
        code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2);
        buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */
 
@@ -416,7 +386,7 @@ send_chunk(int fd)
        datacmc++;
        if (datacmc >= 36)
                datacmc = 0;
-  
+
 #if 0
        fprintf(stderr, "  Send: down %d/%d up %d/%d, %d bytes\n",
                inpkt.seqno, inpkt.fragment, outpkt.seqno, outpkt.fragment,
@@ -431,12 +401,12 @@ send_ping(int fd)
 {
        if (conn == CONN_DNS_NULL) {
                char data[4];
-               
+
                data[0] = userid;
                data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15);
                data[2] = (rand_seed >> 8) & 0xff;
                data[3] = (rand_seed >> 0) & 0xff;
-               
+
                rand_seed++;
 
 #if 0
@@ -596,13 +566,13 @@ read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q)
    Returns >0 on correct replies; value is #valid bytes in *buf.
 */
 {
-       struct sockaddr_in from;
+       struct sockaddr_storage from;
        char data[64*1024];
        socklen_t addrlen;
        int r;
 
-       addrlen = sizeof(struct sockaddr);
-       if ((r = recvfrom(dns_fd, data, sizeof(data), 0, 
+       addrlen = sizeof(from);
+       if ((r = recvfrom(dns_fd, data, sizeof(data), 0,
                          (struct sockaddr*)&from, &addrlen)) < 0) {
                warn("recvfrom");
                return -1;
@@ -624,9 +594,9 @@ read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q)
                        /*
                         * buf is a hostname or txt stream that we still need to
                         * decode to binary
-                        * 
+                        *
                         * also update rv with the number of valid bytes
-                        * 
+                        *
                         * data is unused here, and will certainly hold the smaller binary
                         */
 
@@ -1167,11 +1137,11 @@ client_tunnel(int tun_fd, int dns_fd)
                        warnx("No downstream data received in 60 seconds, shutting down.");
                        running = 0;
                }
-               
+
                if (running == 0)
                        break;
 
-               if (i < 0) 
+               if (i < 0)
                        err(1, "select");
 
                if (i == 0) {
@@ -1214,7 +1184,7 @@ client_tunnel(int tun_fd, int dns_fd)
                        if (FD_ISSET(dns_fd, &fds)) {
                                if (tunnel_dns(tun_fd, dns_fd) <= 0)
                                        continue;
-                       } 
+                       }
                }
        }
 
@@ -1232,7 +1202,7 @@ send_login(int fd, char *login, int len)
 
        data[17] = (rand_seed >> 8) & 0xff;
        data[18] = (rand_seed >> 0) & 0xff;
-       
+
        rand_seed++;
 
        send_packet(fd, 'l', data, sizeof(data));
@@ -1271,23 +1241,23 @@ static void
 send_set_downstream_fragsize(int fd, int fragsize)
 {
        char data[5];
-       
+
        data[0] = userid;
        data[1] = (fragsize & 0xff00) >> 8;
        data[2] = (fragsize & 0x00ff);
        data[3] = (rand_seed >> 8) & 0xff;
        data[4] = (rand_seed >> 0) & 0xff;
-       
+
        rand_seed++;
 
        send_packet(fd, 'n', data, sizeof(data));
 }
 
-static void 
+static void
 send_version(int fd, uint32_t version)
 {
        char data[6];
+
        data[0] = (version >> 24) & 0xff;
        data[1] = (version >> 16) & 0xff;
        data[2] = (version >> 8) & 0xff;
@@ -1295,7 +1265,7 @@ send_version(int fd, uint32_t version)
 
        data[4] = (rand_seed >> 8) & 0xff;
        data[5] = (rand_seed >> 0) & 0xff;
-       
+
        rand_seed++;
 
        send_packet(fd, 'v', data, sizeof(data));
@@ -1306,7 +1276,7 @@ send_ip_request(int fd, int userid)
 {
        char buf[512] = "i____.";
        buf[1] = b32_5to8(userid);
-       
+
        buf[2] = b32_5to8((rand_seed >> 10) & 0x1f);
        buf[3] = b32_5to8((rand_seed >> 5) & 0x1f);
        buf[4] = b32_5to8((rand_seed ) & 0x1f);
@@ -1330,7 +1300,7 @@ send_upenctest(int fd, char *s)
 /* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */
 {
        char buf[512] = "z___";
-       
+
        buf[1] = b32_5to8((rand_seed >> 10) & 0x1f);
        buf[2] = b32_5to8((rand_seed >> 5) & 0x1f);
        buf[3] = b32_5to8((rand_seed ) & 0x1f);
@@ -1366,7 +1336,7 @@ send_codec_switch(int fd, int userid, int bits)
        char buf[512] = "s_____.";
        buf[1] = b32_5to8(userid);
        buf[2] = b32_5to8(bits);
-       
+
        buf[3] = b32_5to8((rand_seed >> 10) & 0x1f);
        buf[4] = b32_5to8((rand_seed >> 5) & 0x1f);
        buf[5] = b32_5to8((rand_seed ) & 0x1f);
@@ -1429,33 +1399,31 @@ handshake_version(int dns_fd, int *seed)
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'v', 'V', i+1);
 
-               /*XXX START adjust indent 1 tab back*/
-                       if (read >= 9) {
-                               payload =  (((in[4] & 0xff) << 24) |
-                                               ((in[5] & 0xff) << 16) |
-                                               ((in[6] & 0xff) << 8) |
-                                               ((in[7] & 0xff)));
-
-                               if (strncmp("VACK", in, 4) == 0) {
-                                       *seed = payload;
-                                       userid = in[8];
-                                       userid_char = hex[userid & 15];
-                                       userid_char2 = hex2[userid & 15];
+               if (read >= 9) {
+                       payload =  (((in[4] & 0xff) << 24) |
+                                       ((in[5] & 0xff) << 16) |
+                                       ((in[6] & 0xff) << 8) |
+                                       ((in[7] & 0xff)));
+
+                       if (strncmp("VACK", in, 4) == 0) {
+                               *seed = payload;
+                               userid = in[8];
+                               userid_char = hex[userid & 15];
+                               userid_char2 = hex2[userid & 15];
+
+                               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);
+                               return 1;
+                       } else if (strncmp("VFUL", in, 4) == 0) {
+                               warnx("Server full, all %d slots are taken. Try again later", payload);
+                               return 1;
+                       }
+               } else if (read > 0)
+                       warnx("did not receive proper login challenge");
 
-                                       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);
-                                       return 1;
-                               } else if (strncmp("VFUL", in, 4) == 0) {
-                                       warnx("Server full, all %d slots are taken. Try again later", payload);
-                                       return 1;
-                               }
-                       } else if (read > 0)
-                               warnx("did not receive proper login challenge");
-               /*XXX END adjust indent 1 tab back*/
-               
                fprintf(stderr, "Retrying version check...\n");
        }
        warnx("couldn't connect to server (maybe other -T options will work)");
@@ -1474,37 +1442,35 @@ handshake_login(int dns_fd, int seed)
        int read;
 
        login_calculate(login, 16, password, seed);
-       
+
        for (i=0; running && i<5 ;i++) {
 
                send_login(dns_fd, login, 16);
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'l', 'L', i+1);
 
-               /*XXX START adjust indent 1 tab back*/
-                       if (read > 0) {
-                               int netmask;
-                               if (strncmp("LNAK", in, 4) == 0) {
-                                       fprintf(stderr, "Bad password\n");
-                                       return 1;
-                               } else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d", 
-                                       server, client, &mtu, &netmask) == 4) {
-                                       
-                                       server[64] = 0;
-                                       client[64] = 0;
-                                       if (tun_setip(client, server, netmask) == 0 && 
-                                               tun_setmtu(mtu) == 0) {
-
-                                               fprintf(stderr, "Server tunnel IP is %s\n", server);
-                                               return 0;
-                                       } else {
-                                               errx(4, "Failed to set IP and MTU");
-                                       }
+               if (read > 0) {
+                       int netmask;
+                       if (strncmp("LNAK", in, 4) == 0) {
+                               fprintf(stderr, "Bad password\n");
+                               return 1;
+                       } else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d",
+                               server, client, &mtu, &netmask) == 4) {
+
+                               server[64] = 0;
+                               client[64] = 0;
+                               if (tun_setip(client, server, netmask) == 0 &&
+                                       tun_setmtu(mtu) == 0) {
+
+                                       fprintf(stderr, "Server tunnel IP is %s\n", server);
+                                       return 0;
                                } else {
-                                       fprintf(stderr, "Received bad handshake\n");
+                                       errx(4, "Failed to set IP and MTU");
                                }
+                       } else {
+                               fprintf(stderr, "Received bad handshake\n");
                        }
-               /*XXX END adjust indent 1 tab back*/
+               }
 
                fprintf(stderr, "Retrying login...\n");
        }
@@ -1531,20 +1497,18 @@ handshake_raw_udp(int dns_fd, int seed)
 
                len = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1);
 
-               /*XXX START adjust indent 1 tab back*/
-                       if (len == 5 && in[0] == 'I') {
-                               /* Received IP address */
-                               remoteaddr = (in[1] & 0xff);
-                               remoteaddr <<= 8;
-                               remoteaddr |= (in[2] & 0xff);
-                               remoteaddr <<= 8;
-                               remoteaddr |= (in[3] & 0xff);
-                               remoteaddr <<= 8;
-                               remoteaddr |= (in[4] & 0xff);
-                               server.s_addr = ntohl(remoteaddr);
-                               break;
-                       }
-               /*XXX END adjust indent 1 tab back*/
+               if (len == 5 && in[0] == 'I') {
+                       /* Received IP address */
+                       remoteaddr = (in[1] & 0xff);
+                       remoteaddr <<= 8;
+                       remoteaddr |= (in[2] & 0xff);
+                       remoteaddr <<= 8;
+                       remoteaddr |= (in[3] & 0xff);
+                       remoteaddr <<= 8;
+                       remoteaddr |= (in[4] & 0xff);
+                       server.s_addr = ntohl(remoteaddr);
+                       break;
+               }
 
                fprintf(stderr, ".");
                fflush(stderr);
@@ -1552,7 +1516,7 @@ handshake_raw_udp(int dns_fd, int seed)
        fprintf(stderr, "\n");
        if (!running)
                return 0;
-       
+
        if (!remoteaddr) {
                fprintf(stderr, "Failed to get raw server IP, will use DNS mode.\n");
                return 0;
@@ -1566,7 +1530,7 @@ handshake_raw_udp(int dns_fd, int seed)
        raw_serv.sin_port = htons(53);
        raw_serv.sin_addr = server;
 
-       /* do login against port 53 on remote server 
+       /* do login against port 53 on remote server
         * based on the old seed. If reply received,
         * switch to raw udp mode */
        for (i=0; running && i<4 ;i++) {
@@ -1574,7 +1538,7 @@ handshake_raw_udp(int dns_fd, int seed)
                tv.tv_usec = 0;
 
                send_raw_udp_login(dns_fd, userid, seed);
-               
+
                FD_ZERO(&fds);
                FD_SET(dns_fd, &fds);
 
@@ -1587,7 +1551,7 @@ handshake_raw_udp(int dns_fd, int seed)
                                char hash[16];
                                login_calculate(hash, 16, password, seed - 1);
                                if (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0
-                                       && RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN 
+                                       && RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN
                                        && memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0) {
 
                                        fprintf(stderr, "OK\n");
@@ -1598,7 +1562,7 @@ handshake_raw_udp(int dns_fd, int seed)
                fprintf(stderr, ".");
                fflush(stderr);
        }
-       
+
        fprintf(stderr, "failed\n");
        return 0;
 }
@@ -1827,7 +1791,7 @@ handshake_downenc_autodetect(int dns_fd)
        int base64uok = 0;
        int base128ok = 0;
 
-       if (do_qtype == T_NULL) {
+       if (do_qtype == T_NULL || do_qtype == T_PRIVATE) {
                /* no other choice than raw */
                fprintf(stderr, "No alternative downstream codec available, using default (Raw)\n");
                return ' ';
@@ -1881,13 +1845,14 @@ handshake_qtypetest(int dns_fd, int timeout)
        int trycodec;
        int k;
 
-       if (do_qtype == T_NULL)
+       if (do_qtype == T_NULL || do_qtype == T_PRIVATE)
                trycodec = 'R';
        else
                trycodec = 'T';
 
        /* We could use 'Z' bouncing here, but 'Y' also tests that 0-255
-          byte values can be returned, which is needed for NULL to work. */
+          byte values can be returned, which is needed for NULL/PRIVATE
+          to work. */
 
        send_downenctest(dns_fd, trycodec, 1, NULL, 0);
 
@@ -1912,11 +1877,12 @@ handshake_qtype_numcvt(int num)
 {
        switch (num) {
        case 0: return T_NULL;
-       case 1: return T_TXT;
-       case 2: return T_SRV;
-       case 3: return T_MX;
-       case 4: return T_CNAME;
-       case 5: return T_A;
+       case 1: return T_PRIVATE;
+       case 2: return T_TXT;
+       case 3: return T_SRV;
+       case 4: return T_MX;
+       case 5: return T_CNAME;
+       case 6: return T_A;
        }
        return T_UNSET;
 }
@@ -1959,7 +1925,7 @@ handshake_qtype_autodetect(int dns_fd)
                                highestworking = qtypenum;
 #if 0
                                fprintf(stderr, " Type %s timeout %d works\n",
-                                       get_qtype(), timeout);
+                                       client_get_qtype(), timeout);
 #endif
                                break;
                                /* try others with longer timeout */
@@ -2066,27 +2032,25 @@ handshake_switch_codec(int dns_fd, int bits)
        for (i=0; running && i<5 ;i++) {
 
                send_codec_switch(dns_fd, userid, bits);
-               
+
                read = handshake_waitdns(dns_fd, in, sizeof(in), 's', 'S', i+1);
 
-               /*XXX START adjust indent 1 tab back*/                  
-                       if (read > 0) {
-                               if (strncmp("BADLEN", in, 6) == 0) {
-                                       fprintf(stderr, "Server got bad message length. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADIP", in, 5) == 0) {
-                                       fprintf(stderr, "Server rejected sender IP address. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADCODEC", in, 8) == 0) {
-                                       fprintf(stderr, "Server rejected the selected codec. ");
-                                       goto codec_revert;
-                               }
-                               in[read] = 0; /* zero terminate */
-                               fprintf(stderr, "Server switched upstream to codec %s\n", in);
-                               dataenc = tempenc;
-                               return;
+               if (read > 0) {
+                       if (strncmp("BADLEN", in, 6) == 0) {
+                               fprintf(stderr, "Server got bad message length. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADIP", in, 5) == 0) {
+                               fprintf(stderr, "Server rejected sender IP address. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADCODEC", in, 8) == 0) {
+                               fprintf(stderr, "Server rejected the selected codec. ");
+                               goto codec_revert;
                        }
-               /*XXX END adjust indent 1 tab back*/
+                       in[read] = 0; /* zero terminate */
+                       fprintf(stderr, "Server switched upstream to codec %s\n", in);
+                       dataenc = tempenc;
+                       return;
+               }
 
                fprintf(stderr, "Retrying codec switch...\n");
        }
@@ -2095,7 +2059,7 @@ handshake_switch_codec(int dns_fd, int bits)
 
        fprintf(stderr, "No reply from server on codec switch. ");
 
-codec_revert: 
+codec_revert:
        fprintf(stderr, "Falling back to upstream codec %s\n", dataenc->name);
 }
 
@@ -2124,23 +2088,21 @@ handshake_switch_downenc(int dns_fd)
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1);
 
-               /*XXX START adjust indent 1 tab back*/
-                       if (read > 0) {
-                               if (strncmp("BADLEN", in, 6) == 0) {
-                                       fprintf(stderr, "Server got bad message length. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADIP", in, 5) == 0) {
-                                       fprintf(stderr, "Server rejected sender IP address. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADCODEC", in, 8) == 0) {
-                                       fprintf(stderr, "Server rejected the selected codec. ");
-                                       goto codec_revert;
-                               }
-                               in[read] = 0; /* zero terminate */
-                               fprintf(stderr, "Server switched downstream to codec %s\n", in);
-                               return;
+               if (read > 0) {
+                       if (strncmp("BADLEN", in, 6) == 0) {
+                               fprintf(stderr, "Server got bad message length. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADIP", in, 5) == 0) {
+                               fprintf(stderr, "Server rejected sender IP address. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADCODEC", in, 8) == 0) {
+                               fprintf(stderr, "Server rejected the selected codec. ");
+                               goto codec_revert;
                        }
-               /*XXX END adjust indent 1 tab back*/
+                       in[read] = 0; /* zero terminate */
+                       fprintf(stderr, "Server switched downstream to codec %s\n", in);
+                       return;
+               }
 
                fprintf(stderr, "Retrying codec switch...\n");
        }
@@ -2149,7 +2111,7 @@ handshake_switch_downenc(int dns_fd)
 
        fprintf(stderr, "No reply from server on codec switch. ");
 
-codec_revert: 
+codec_revert:
        fprintf(stderr, "Falling back to downstream codec Base32\n");
 }
 
@@ -2167,24 +2129,22 @@ handshake_try_lazy(int dns_fd)
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1);
 
-               /*XXX START adjust indent 1 tab back*/
-                       if (read > 0) {
-                               if (strncmp("BADLEN", in, 6) == 0) {
-                                       fprintf(stderr, "Server got bad message length. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADIP", in, 5) == 0) {
-                                       fprintf(stderr, "Server rejected sender IP address. ");
-                                       goto codec_revert;
-                               } else if (strncmp("BADCODEC", in, 8) == 0) {
-                                       fprintf(stderr, "Server rejected lazy mode. ");
-                                       goto codec_revert;
-                               } else if (strncmp("Lazy", in, 4) == 0) {
-                                       fprintf(stderr, "Server switched to lazy mode\n");
-                                       lazymode = 1;
-                                       return;
-                               }
+               if (read > 0) {
+                       if (strncmp("BADLEN", in, 6) == 0) {
+                               fprintf(stderr, "Server got bad message length. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADIP", in, 5) == 0) {
+                               fprintf(stderr, "Server rejected sender IP address. ");
+                               goto codec_revert;
+                       } else if (strncmp("BADCODEC", in, 8) == 0) {
+                               fprintf(stderr, "Server rejected lazy mode. ");
+                               goto codec_revert;
+                       } else if (strncmp("Lazy", in, 4) == 0) {
+                               fprintf(stderr, "Server switched to lazy mode\n");
+                               lazymode = 1;
+                               return;
                        }
-               /*XXX END adjust indent 1 tab back*/
+               }
 
                fprintf(stderr, "Retrying lazy mode switch...\n");
        }
@@ -2193,7 +2153,7 @@ handshake_try_lazy(int dns_fd)
 
        fprintf(stderr, "No reply from server on lazy switch. ");
 
-codec_revert: 
+codec_revert:
        fprintf(stderr, "Falling back to legacy mode\n");
        lazymode = 0;
        selecttimeout = 1;
@@ -2213,14 +2173,12 @@ handshake_lazyoff(int dns_fd)
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', 1);
 
-               /*XXX START adjust indent 2 tabs back*/
-                               if (read == 9 && strncmp("Immediate", in, 9) == 0) {
-                                       warnx("Server switched back to legacy mode.\n");
-                                       lazymode = 0;
-                                       selecttimeout = 1;
-                                       return;
-                               }
-               /*XXX END adjust indent 2 tabs back*/
+               if (read == 9 && strncmp("Immediate", in, 9) == 0) {
+                       warnx("Server switched back to legacy mode.\n");
+                       lazymode = 0;
+                       selecttimeout = 1;
+                       return;
+               }
        }
        if (!running)
                return;
@@ -2275,28 +2233,26 @@ fragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize)
        okay = 1;
        v = in[3] & 0xff;
 
-       /*XXX START adjust indent 1 tab back*/
-               for (i = 3; i < read; i++, v = (v + 107) & 0xff)
-                       if ((in[i] & 0xff) != v) {
-                               okay = 0;
-                               break;
-                       }
+       for (i = 3; i < read; i++, v = (v + 107) & 0xff)
+               if ((in[i] & 0xff) != v) {
+                       okay = 0;
+                       break;
+               }
 
-               if (okay) {
-                       fprintf(stderr, "%d ok.. ", acked_fragsize);
-                       fflush(stderr);
-                       *max_fragsize = acked_fragsize;
-                       return 1;
+       if (okay) {
+               fprintf(stderr, "%d ok.. ", acked_fragsize);
+               fflush(stderr);
+               *max_fragsize = acked_fragsize;
+               return 1;
+       } else {
+               if (downenc != ' ' && downenc != 'T') {
+                       fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i);
                } else {
-                       if (downenc != ' ' && downenc != 'T') {
-                               fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i);
-                       } else {
-                               fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i);
-                       }
-                       fflush(stderr);
-                       return 1;
+                       fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i);
                }
-       /*XXX END adjust indent 1 tab back*/
+               fflush(stderr);
+               return 1;
+       }
 
        /* notreached */
        return 1;
@@ -2314,7 +2270,7 @@ handshake_autoprobe_fragsize(int dns_fd)
        int max_fragsize;
 
        max_fragsize = 0;
-       fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); 
+       fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n");
        while (running && range > 0 && (range >= 8 || max_fragsize < 300)) {
                /* stop the slow probing early when we have enough bytes anyway */
                for (i=0; running && i<3 ;i++) {
@@ -2322,14 +2278,12 @@ handshake_autoprobe_fragsize(int dns_fd)
                        send_fragsize_probe(dns_fd, proposed_fragsize);
 
                        read = handshake_waitdns(dns_fd, in, sizeof(in), 'r', 'R', 1);
-                               
-                       /*XXX START adjust indent 1 tab back*/
-                               if (read > 0) {
-                                       /* We got a reply */
-                                       if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1)
-                                               break;
-                               }
-                       /*XXX END adjust indent 1 tab back*/
+
+                       if (read > 0) {
+                               /* We got a reply */
+                               if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1)
+                                       break;
+                       }
 
                        fprintf(stderr, ".");
                        fflush(stderr);
@@ -2370,7 +2324,7 @@ handshake_autoprobe_fragsize(int dns_fd)
                fprintf(stderr, "Note: this probably won't work well.\n");
                fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n");
        } else if (max_fragsize < 202 &&
-           (do_qtype == T_NULL || do_qtype == T_TXT ||
+           (do_qtype == T_NULL || do_qtype == T_PRIVATE || do_qtype == T_TXT ||
             do_qtype == T_SRV || do_qtype == T_MX)) {
                fprintf(stderr, "Note: this isn't very much.\n");
                fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n");
@@ -2393,22 +2347,20 @@ handshake_set_fragsize(int dns_fd, int fragsize)
 
                read = handshake_waitdns(dns_fd, in, sizeof(in), 'n', 'N', i+1);
 
-               /*XXX START adjust indent 1 tab back*/                  
-                       if (read > 0) {
-                               int accepted_fragsize;
-
-                               if (strncmp("BADFRAG", in, 7) == 0) {
-                                       fprintf(stderr, "Server rejected fragsize. Keeping default.");
-                                       return;
-                               } else if (strncmp("BADIP", in, 5) == 0) {
-                                       fprintf(stderr, "Server rejected sender IP address.\n");
-                                       return;
-                               }
+               if (read > 0) {
 
-                               accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
+                       if (strncmp("BADFRAG", in, 7) == 0) {
+                               fprintf(stderr, "Server rejected fragsize. Keeping default.");
+                               return;
+                       } else if (strncmp("BADIP", in, 5) == 0) {
+                               fprintf(stderr, "Server rejected sender IP address.\n");
                                return;
                        }
-               /*XXX END adjust indent 1 tab back*/
+
+                       /* The server returns the accepted fragsize:
+                       accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff) */
+                       return;
+               }
 
                fprintf(stderr, "Retrying set fragsize...\n");
        }
@@ -2435,7 +2387,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz
                }
        }
 
-       fprintf(stderr, "Using DNS type %s queries\n", get_qtype());
+       fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype());
 
        r = handshake_version(dns_fd, &seed);
        if (r) {
index 16ab0e47825779dca316277bea836bdd19f3953f..983b830b33c441c61636606d220adc76074ec669 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -23,12 +24,12 @@ void client_stop();
 enum connection client_get_conn();
 const char *client_get_raw_addr();
 
-void client_set_nameserver(const char *cp, int port);
+void client_set_nameserver(struct sockaddr_storage *, int);
 void client_set_topdomain(const char *cp);
 void client_set_password(const char *cp);
-void set_qtype(char *qtype);
-char *get_qtype();
-void set_downenc(char *encoding);
+int client_set_qtype(char *qtype);
+char *client_get_qtype();
+void client_set_downenc(char *encoding);
 void client_set_selecttimeout(int select_timeout);
 void client_set_lazymode(int lazy_mode);
 void client_set_hostname_maxlen(int i);
index dd2bf2d3bbc777bba6b792ca926cbd7c843d01d5..27159795efa6f4b86b2a06592144318858a9c8ff 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+/* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
  * Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
  *
  * Permission to use, copy, modify, and distribute this software for any
 #endif
 #include <termios.h>
 #include <err.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <syslog.h>
+#include <sys/socket.h>
+#include <netdb.h>
 #endif
 
 #ifdef HAVE_SETCON
 const unsigned char raw_header[RAW_HDR_LEN] = { 0x10, 0xd1, 0x9e, 0x00 };
 
 /* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
-#if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
+#if !defined(ANDROID) && !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
 static int daemon(int nochdir, int noclose)
 {
        int fd, i;
+
        switch (fork()) {
                case 0:
                        break;
@@ -67,15 +70,15 @@ static int daemon(int nochdir, int noclose)
                default:
                        _exit(0);
        }
+
        if (!nochdir) {
                chdir("/");
        }
+
        if (setsid() < 0) {
                return -1;
        }
-       
+
        if (!noclose) {
                if ((fd = open("/dev/null", O_RDWR)) >= 0) {
                        for (i = 0; i < 3; i++) {
@@ -111,21 +114,69 @@ check_superuser(void (*usage_fn)(void))
 #endif
 }
 
-int 
-open_dns(int localport, in_addr_t listen_ip) 
+char *
+format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len)
+{
+       static char dst[INET6_ADDRSTRLEN + 1];
+
+       memset(dst, 0, sizeof(dst));
+       if (sockaddr->ss_family == AF_INET && sockaddr_len >= sizeof(struct sockaddr_in)) {
+               getnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST);
+       } else if (sockaddr->ss_family == AF_INET6 && sockaddr_len >= sizeof(struct sockaddr_in6)) {
+               struct sockaddr_in6 *addr = (struct sockaddr_in6 *) sockaddr;
+               if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
+                       struct in_addr ia;
+                       /* Get mapped v4 addr from last 32bit field */
+                       memcpy(&ia.s_addr, &addr->sin6_addr.s6_addr[12], sizeof(ia));
+                       strcpy(dst, inet_ntoa(ia));
+               } else {
+                       getnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST);
+               }
+       } else {
+               dst[0] = '?';
+       }
+       return dst;
+}
+
+int
+get_addr(char *host, int port, int addr_family, int flags, struct sockaddr_storage *out)
+{
+       struct addrinfo hints, *addr;
+       int res;
+       char portnum[8];
+
+       memset(portnum, 0, sizeof(portnum));
+       snprintf(portnum, sizeof(portnum) - 1, "%d", port);
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = addr_family;
+#if defined(WINDOWS32) || defined(OPENBSD)
+       /* AI_ADDRCONFIG misbehaves on windows, and does not exist in OpenBSD */
+       hints.ai_flags = flags;
+#else
+       hints.ai_flags = AI_ADDRCONFIG | flags;
+#endif
+       hints.ai_socktype = SOCK_DGRAM;
+       hints.ai_protocol = IPPROTO_UDP;
+
+       res = getaddrinfo(host, portnum, &hints, &addr);
+       if (res == 0) {
+               int addrlen = addr->ai_addrlen;
+               /* Grab first result */
+               memcpy(out, addr->ai_addr, addr->ai_addrlen);
+               freeaddrinfo(addr);
+               return addrlen;
+       }
+       return res;
+}
+
+int
+open_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len)
 {
-       struct sockaddr_in addr;
        int flag = 1;
        int fd;
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_port = htons(localport);
-       /* 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) {
-               fprintf(stderr, "got fd %d\n", fd);
+       if ((fd = socket(sockaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                err(1, "socket");
        }
 
@@ -138,6 +189,8 @@ open_dns(int localport, in_addr_t listen_ip)
 #ifndef WINDOWS32
        /* To get destination address from each UDP datagram, see iodined.c:read_dns() */
        setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
+
+       fd_set_close_on_exec(fd);
 #endif
 
 #ifdef IP_OPT_DONT_FRAG
@@ -146,14 +199,27 @@ open_dns(int localport, in_addr_t listen_ip)
        setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
 #endif
 
-       if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
+       if(bind(fd, (struct sockaddr*) sockaddr, sockaddr_len) < 0)
                err(1, "bind");
 
-       fprintf(stderr, "Opened UDP socket\n");
+       fprintf(stderr, "Opened IPv%d UDP socket\n", sockaddr->ss_family == AF_INET6 ? 6 : 4);
 
        return fd;
 }
 
+int
+open_dns_from_host(char *host, int port, int addr_family, int flags)
+{
+       struct sockaddr_storage addr;
+       int addrlen;
+
+       addrlen = get_addr(host, port, addr_family, flags, &addr);
+       if (addrlen < 0)
+               return addrlen;
+
+       return open_dns(&addr, addrlen);
+}
+
 void
 close_dns(int fd)
 {
@@ -167,8 +233,9 @@ do_chroot(char *newroot)
        if (chroot(newroot) != 0 || chdir("/") != 0)
                err(1, "%s", newroot);
 
-       seteuid(geteuid());
-       setuid(getuid());
+       if (seteuid(geteuid()) != 0 || setuid(getuid()) != 0) {
+               err(1, "set[e]uid()");
+       }
 #else
        warnx("chroot not available");
 #endif
@@ -219,14 +286,14 @@ do_detach()
 void
 read_password(char *buf, size_t len)
 {
-       char pwd[80];
+       char pwd[80] = {0};
 #ifndef WINDOWS32
        struct termios old;
        struct termios tp;
 
        tcgetattr(0, &tp);
        old = tp;
-       
+
        tp.c_lflag &= (~ECHO);
        tcsetattr(0, TCSANOW, &tp);
 #else
@@ -236,7 +303,7 @@ read_password(char *buf, size_t len)
        fprintf(stderr, "Enter password: ");
        fflush(stderr);
 #ifndef WINDOWS32
-       scanf("%79s", pwd);
+       fscanf(stdin, "%79[^\n]", pwd);
 #else
        for (i = 0; i < sizeof(pwd); i++) {
                pwd[i] = getch();
@@ -252,7 +319,7 @@ read_password(char *buf, size_t len)
        fprintf(stderr, "\n");
 
 #ifndef WINDOWS32
-       tcsetattr(0, TCSANOW, &old);    
+       tcsetattr(0, TCSANOW, &old);
 #endif
 
        strncpy(buf, pwd, len);
@@ -260,29 +327,75 @@ read_password(char *buf, size_t len)
 }
 
 int
-check_topdomain(char *str)
+check_topdomain(char *str, char **errormsg)
 {
-       int i;
-
-       if(str[0] == '.') /* special case */
-               return 1;
-
-       for( i = 0; i < strlen(str); i++) {
-               if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
-                       continue;
-               else 
-                      return 1;
-       }
-       return 0;
+       int i;
+       int dots = 0;
+       int chunklen = 0;
+
+       if (strlen(str) < 3) {
+               if (errormsg) *errormsg = "Too short (< 3)";
+               return 1;
+       }
+       if (strlen(str) > 128) {
+               if (errormsg) *errormsg = "Too long (> 128)";
+               return 1;
+       }
+
+       if (str[0] == '.') {
+               if (errormsg) *errormsg = "Starts with a dot";
+               return 1;
+       }
+
+       for( i = 0; i < strlen(str); i++) {
+               if(str[i] == '.') {
+                       dots++;
+                       if (chunklen == 0) {
+                               if (errormsg) *errormsg = "Consecutive dots";
+                               return 1;
+                       }
+                       if (chunklen > 63) {
+                               if (errormsg) *errormsg = "Too long domain part (> 63)";
+                               return 1;
+                       }
+                       chunklen = 0;
+               } else {
+                       chunklen++;
+               }
+               if( (str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') ||
+                               isdigit(str[i]) || str[i] == '-' || str[i] == '.' ) {
+                       continue;
+               } else {
+                       if (errormsg) *errormsg = "Contains illegal character (allowed: [a-zA-Z0-9-.])";
+                       return 1;
+               }
+       }
+
+       if (dots == 0) {
+               if (errormsg) *errormsg = "No dots";
+               return 1;
+       }
+       if (chunklen == 0) {
+               if (errormsg) *errormsg = "Ends with a dot";
+               return 1;
+       }
+       if (chunklen > 63) {
+               if (errormsg) *errormsg = "Too long domain part (> 63)";
+               return 1;
+       }
+
+       return 0;
 }
 
-#ifdef WINDOWS32
+#if defined(WINDOWS32) || defined(ANDROID)
+#ifndef ANDROID
 int
 inet_aton(const char *cp, struct in_addr *inp)
 {
  inp->s_addr = inet_addr(cp);
  return inp->s_addr != INADDR_ANY;
 }
+#endif
 
 void
 warn(const char *fmt, ...)
@@ -291,11 +404,13 @@ warn(const char *fmt, ...)
 
        va_start(list, fmt);
        if (fmt) fprintf(stderr, fmt, list);
+#ifndef ANDROID
        if (errno == 0) {
-               fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); 
+               fprintf(stderr, ": WSA error %d\n", WSAGetLastError());
        } else {
                fprintf(stderr, ": %s\n", strerror(errno));
        }
+#endif
        va_end(list);
 }
 
@@ -348,3 +463,22 @@ int recent_seqno(int ourseqno, int gotseqno)
        }
        return 0;
 }
+
+#ifndef WINDOWS32
+/* Set FD_CLOEXEC flag on file descriptor.
+ * This stops it from being inherited by system() calls.
+ */
+void
+fd_set_close_on_exec(int fd)
+{
+       int flags;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1)
+               err(4, "Failed to get fd flags");
+       flags |= FD_CLOEXEC;
+       if (fcntl(fd, F_SETFD, flags) == -1)
+               err(4, "Failed to set fd flags");
+}
+#endif
+
index 8dbbfbd42bc08a55539f5f657cd4a1183aa0dab6..3c98c0158af8c7facd8641899319ed61a5889267 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -37,8 +38,8 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <err.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #endif
 
 #define DNS_PORT 53
@@ -52,12 +53,12 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
 
 #define QUERY_NAME_SIZE 256
 
-#if defined IP_RECVDSTADDR 
-# define DSTADDR_SOCKOPT IP_RECVDSTADDR 
-# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x)) 
-#elif defined IP_PKTINFO 
-# define DSTADDR_SOCKOPT IP_PKTINFO 
-# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr)) 
+#if defined IP_RECVDSTADDR
+# define DSTADDR_SOCKOPT IP_RECVDSTADDR
+# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x))
+#elif defined IP_PKTINFO
+# define DSTADDR_SOCKOPT IP_PKTINFO
+# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
 #endif
 
 #if defined IP_MTU_DISCOVER
@@ -74,10 +75,12 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
 # define DONT_FRAG_VALUE 1
 #endif
 
+#define T_PRIVATE 65399
+/* Undefined RR type; "private use" range, see http://www.bind9.net/dns-parameters */
 #define T_UNSET 65432
-/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */
+/* Unused RR type, never actually sent */
 
-struct packet 
+struct packet
 {
        int len;                /* Total packet length */
        int sentlen;            /* Length of chunk currently transmitted */
@@ -93,7 +96,7 @@ struct query {
        unsigned short rcode;
        unsigned short id;
        struct in_addr destination;
-       struct sockaddr from;
+       struct sockaddr_storage from;
        int fromlen;
        unsigned short id2;
        struct sockaddr from2;
@@ -107,7 +110,10 @@ enum connection {
 };
 
 void check_superuser(void (*usage_fn)(void));
-int open_dns(int, in_addr_t);
+char *format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len);
+int get_addr(char *, int, int, int, struct sockaddr_storage *);
+int open_dns(struct sockaddr_storage *, size_t);
+int open_dns_from_host(char *host, int port, int addr_family, int flags);
 void close_dns(int);
 
 void do_chroot(char *);
@@ -117,10 +123,12 @@ void do_pidfile(char *);
 
 void read_password(char*, size_t);
 
-int check_topdomain(char *);
+int check_topdomain(char *, char **);
 
-#ifdef WINDOWS32
+#if defined(WINDOWS32) || defined(ANDROID)
+#ifndef ANDROID
 int inet_aton(const char *cp, struct in_addr *inp);
+#endif
 
 void err(int eval, const char *fmt, ...);
 void warn(const char *fmt, ...);
@@ -130,4 +138,8 @@ void warnx(const char *fmt, ...);
 
 int recent_seqno(int , int);
 
+#ifndef WINDOWS32
+void fd_set_close_on_exec(int fd);
+#endif
+
 #endif
index fb2bcaf3d42f1dc227df7c4b9bd9aa38835cbeee..0d3b8b3b48d97d8625530920cbbb71a9e8b14ca0 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <strings.h>
 #include <ctype.h>
 
 #ifdef WINDOWS32
 #include "windows.h"
 #else
+#ifdef ANDROID
+#include "android_dns.h"
+#endif
 #include <arpa/nameser.h>
 #ifdef DARWIN
 #define BIND_8_COMPAT
 #include <arpa/nameser_compat.h>
 #endif
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <err.h>
 #endif
@@ -41,7 +47,7 @@
 
 int dnsc_use_edns0 = 1;
 
-#define CHECKLEN(x) if (buflen - (p-buf) < (x))  return 0
+#define CHECKLEN(x) if (buflen < (x) + (unsigned)(p-buf))  return 0
 
 int
 dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
@@ -56,9 +62,9 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                return 0;
 
        memset(buf, 0, buflen);
-       
+
        header = (HEADER*)buf;
-       
+
        header->id = htons(q->id);
        header->qr = (qr == QR_ANSWER);
        header->opcode = 0;
@@ -72,7 +78,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
        switch (qr) {
        case QR_ANSWER:
                header->qdcount = htons(1);
-       
+
                name = 0xc000 | ((p - buf) & 0x3fff);
 
                /* Question section */
@@ -91,7 +97,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                        int namelen;
 
                        CHECKLEN(10);
-                       putshort(&p, name);     
+                       putshort(&p, name);
                        if (q->type == T_A)
                                /* answer CNAME to A question */
                                putshort(&p, T_CNAME);
@@ -121,7 +127,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                        ancnt = 1;
                        while (1) {
                                CHECKLEN(10);
-                               putshort(&p, name);     
+                               putshort(&p, name);
                                putshort(&p, q->type);
                                putshort(&p, C_IN);
                                putlong(&p, 0);         /* TTL */
@@ -156,7 +162,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                        int txtlen;
 
                        CHECKLEN(10);
-                       putshort(&p, name);     
+                       putshort(&p, name);
                        putshort(&p, q->type);
                        putshort(&p, C_IN);
                        putlong(&p, 0);         /* TTL */
@@ -173,7 +179,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                        /* NULL has raw binary data */
 
                        CHECKLEN(10);
-                       putshort(&p, name);     
+                       putshort(&p, name);
                        putshort(&p, q->type);
                        putshort(&p, C_IN);
                        putlong(&p, 0);         /* TTL */
@@ -192,7 +198,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                /* Note that iodined also uses this for forward queries */
 
                header->qdcount = htons(1);
-       
+
                datalen = MIN(datalen, buflen - (p - buf));
                putname(&p, datalen, data);
 
@@ -204,20 +210,18 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
                   (even CNAME/A/MX, 255+255+header would be >512) */
                if (dnsc_use_edns0) {
                        header->arcount = htons(1);
-                       /*XXX START adjust indent 1 tab forward*/
-               CHECKLEN(11);
-               putbyte(&p, 0x00);    /* Root */
-               putshort(&p, 0x0029); /* OPT */
-               putshort(&p, 0x1000); /* Payload size: 4096 */
-               putshort(&p, 0x0000); /* Higher bits/edns version */
-               putshort(&p, 0x8000); /* Z */
-               putshort(&p, 0x0000); /* Data length */
-                       /*XXX END adjust indent 1 tab forward*/
+                       CHECKLEN(11);
+                       putbyte(&p, 0x00);    /* Root */
+                       putshort(&p, 0x0029); /* OPT */
+                       putshort(&p, 0x1000); /* Payload size: 4096 */
+                       putshort(&p, 0x0000); /* Higher bits/edns version */
+                       putshort(&p, 0x8000); /* Z */
+                       putshort(&p, 0x0000); /* Data length */
                }
 
                break;
        }
-       
+
        len = p - buf;
 
        return len;
@@ -241,9 +245,9 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
                return 0;
 
        memset(buf, 0, buflen);
-       
+
        header = (HEADER*)buf;
-       
+
        header->id = htons(q->id);
        header->qr = 1;
        header->opcode = 0;
@@ -330,9 +334,9 @@ dns_encode_a_response(char *buf, size_t buflen, struct query *q)
                return 0;
 
        memset(buf, 0, buflen);
-       
+
        header = (HEADER*)buf;
-       
+
        header->id = htons(q->id);
        header->qr = 1;
        header->opcode = 0;
@@ -389,7 +393,7 @@ dns_get_id(char *packet, size_t packetlen)
        return ntohs(header->id);
 }
 
-#define CHECKLEN(x) if (packetlen - (data-packet) < (x))  return 0
+#define CHECKLEN(x) if (packetlen < (x) + (unsigned)(data-packet))  return 0
 
 int
 dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
@@ -400,11 +404,11 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
        short qdcount;
        short ancount;
        uint32_t ttl;
-       short class;
-       short type;
+       unsigned short class;
+       unsigned short type;
        char *data;
-       short rlen;
-       int id; 
+       unsigned short rlen;
+       int id;
        int rv;
 
        q->id2 = 0;
@@ -412,9 +416,9 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
        header = (HEADER*)packet;
 
        /* Reject short packets */
-       if (packetlen < sizeof(HEADER)) 
+       if (packetlen < sizeof(HEADER))
                return 0;
-       
+
        if (header->qr != qr) {
                warnx("header->qr does not match the requested qr");
                return -1;
@@ -423,13 +427,13 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
        data = packet + sizeof(HEADER);
        qdcount = ntohs(header->qdcount);
        ancount = ntohs(header->ancount);
-       
+
        id = ntohs(header->id);
        id = id & 0xFFFF; /* Kill any sign extension */
-               
+
        rlen = 0;
 
-       if (q != NULL) 
+       if (q != NULL)
                q->rcode = header->rcode;
 
        switch (qr) {
@@ -439,7 +443,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                        return -1;
                }
 
-               if (q != NULL) 
+               if (q != NULL)
                        q->id = id;
 
                /* Read name even if no answer, to give better error message */
@@ -447,14 +451,14 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                CHECKLEN(4);
                readshort(packet, &data, &type);
                readshort(packet, &data, &class);
-               
+
                /* if CHECKLEN okay, then we're sure to have a proper name */
                if (q != NULL) {
                        /* We only need the first char to check it */
                        q->name[0] = name[0];
                        q->name[1] = '\0';
-               } 
-               
+               }
+
                if (ancount < 1) {
                        /* DNS errors like NXDOMAIN have ancount=0 and
                           stop here. CNAME may also have A; MX/SRV may have
@@ -463,7 +467,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                }
 
                /* Here type is still the question type */
-               if (type == T_NULL) {
+               if (type == T_NULL || type == T_PRIVATE) {
                        /* Assume that first answer is what we wanted */
                        readname(packet, packetlen, &data, name, sizeof(name));
                        CHECKLEN(10);
@@ -505,7 +509,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                         */
                        char names[250][QUERY_NAME_SIZE];
                        char *rdatastart;
-                       short pref;
+                       unsigned short pref;
                        int i;
                        int offset;
 
@@ -535,7 +539,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
                                        names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0';
                                }
 
-                               /* always trust rlen, not name encoding */ 
+                               /* always trust rlen, not name encoding */
                                data = rdatastart + rlen;
                                CHECKLEN(0);
                        }
index 72d4fe91b245bf6a4b5c80730ebf5e308af1f4ce..7c1faffe4e61e4db2a5bd1e253471d85340cef01 100644 (file)
--- a/src/dns.h
+++ b/src/dns.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 896d67d8721cb05ce96a92a84565043c907924f5..af7620ea5919084b211c6e3db356fe87427b7cd1 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #include "encoding.h"
 
 int
-build_hostname(char *buf, size_t buflen, 
-               const char *data, const size_t datalen, 
+build_hostname(char *buf, size_t buflen,
+               const char *data, const size_t datalen,
                const char *topdomain, struct encoder *encoder, int maxlen)
 {
-       int encsize;
        size_t space;
        char *b;
 
-       space = MIN(maxlen, buflen) - strlen(topdomain) - 8;
+       space = MIN((size_t)maxlen, buflen) - strlen(topdomain) - 8;
        /* 8 = 5 max header length + 1 dot before topdomain + 2 safety */
 
        if (!encoder->places_dots())
                space -= (space / 57); /* space for dots */
 
        memset(buf, 0, buflen);
-       
-       encsize = encoder->encode(buf, &space, data, datalen);
+
+       encoder->encode(buf, &space, data, datalen);
 
        if (!encoder->places_dots())
                inline_dotify(buf, buflen);
@@ -45,7 +45,7 @@ build_hostname(char *buf, size_t buflen,
 
        /* move b back one step to see if the dot is there */
        b--;
-       if (*b != '.') 
+       if (*b != '.')
                *++b = '.';
        b++;
        /* move b ahead of the string so we can copy to it */
@@ -63,7 +63,7 @@ unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder
        return enc->decode(buf, &buflen, data, datalen);
 }
 
-int 
+int
 inline_dotify(char *buf, size_t buflen)
 {
        unsigned dots;
@@ -101,7 +101,7 @@ inline_dotify(char *buf, size_t buflen)
        return total;
 }
 
-int 
+int
 inline_undotify(char *buf, size_t len)
 {
        unsigned pos;
@@ -124,7 +124,7 @@ inline_undotify(char *buf, size_t len)
                *writer++ = *reader++;
                pos++;
        }
-       
+
        /* return new length of string */
        return len - dots;
 }
index 7ddf6e04b140524271464fd1433a69b7054f7e18..ab222791132fd8b0edc985e12cf7be2b0bd78ed4 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 3727f08298c3f68994fe9ed7e1092dd49f9da724..4f7d8c4f0a3949c0dbd74e3217b68b6a34de64c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2008-2014 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
@@ -29,9 +29,9 @@ void fw_query_init()
 void fw_query_put(struct fw_query *fw_query)
 {
        memcpy(&(fwq[fwq_ix]), fw_query, sizeof(struct fw_query));
-       
+
        ++fwq_ix;
-       if (fwq_ix >= FW_QUERY_CACHE_SIZE) 
+       if (fwq_ix >= FW_QUERY_CACHE_SIZE)
                fwq_ix = 0;
 }
 
index 7568a5f565d9835fddeb330c16c615ac850e02ec..f8f0de666e3497c81e4d5d5cc6c12fee00362b22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2008-2014 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
@@ -28,7 +28,7 @@
 #define FW_QUERY_CACHE_SIZE 16
 
 struct fw_query {
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
        int addrlen;
        unsigned short id;
 };
index 03efb18856b9ed5b7209a8b629e250e441d38296..5c195763cdd600349f10f98a65d8c31aec10eb2f 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -32,6 +33,7 @@
 #else
 #include <grp.h>
 #include <pwd.h>
+#include <netdb.h>
 #endif
 
 #include "common.h"
@@ -51,11 +53,17 @@ static char *__progname;
 #define PASSWORD_ENV_VAR "IODINE_PASS"
 
 static void
-sighandler(int sig) 
+sighandler(int sig)
 {
        client_stop();
 }
 
+#if defined(__GNUC__) || defined(__clang__)
+/* mark as no return to help some compilers to avoid warnings
+ * about use of uninitialized variables */
+static void usage() __attribute__((noreturn));
+#endif
+
 static void
 usage() {
        extern char *__progname;
@@ -75,7 +83,7 @@ help() {
                        "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
                        "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
        fprintf(stderr, "Options to try if connection doesn't work:\n");
-       fprintf(stderr, "  -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
+       fprintf(stderr, "  -T force dns type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
        fprintf(stderr, "  -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n");
        fprintf(stderr, "     Base128, or (only for TXT:) Raw  (default: autodetect)\n");
        fprintf(stderr, "  -I max interval between requests (default 4 sec) to prevent DNS timeouts\n");
@@ -101,8 +109,9 @@ help() {
 
 static void
 version() {
+
        fprintf(stderr, "iodine IP over DNS tunneling client\n");
-       fprintf(stderr, "version: 0.6.0-rc1 from 2010-02-13\n");
+       fprintf(stderr, "version: 0.7.0 from 2014-06-16\n");
 
        exit(0);
 }
@@ -110,8 +119,9 @@ version() {
 int
 main(int argc, char **argv)
 {
-       char *nameserv_addr;
+       char *nameserv_host;
        char *topdomain;
+       char *errormsg;
 #ifndef WINDOWS32
        struct passwd *pw;
 #endif
@@ -132,9 +142,16 @@ main(int argc, char **argv)
        int lazymode;
        int selecttimeout;
        int hostname_maxlen;
+#ifdef OPENBSD
+       int rtable = 0;
+#endif
+       struct sockaddr_storage nameservaddr;
+       int nameservaddr_len;
+       int nameserv_family;
 
-       nameserv_addr = NULL;
+       nameserv_host = NULL;
        topdomain = NULL;
+       errormsg = NULL;
 #ifndef WINDOWS32
        pw = NULL;
 #endif
@@ -154,6 +171,7 @@ main(int argc, char **argv)
        lazymode = 1;
        selecttimeout = 4;
        hostname_maxlen = 0xFF;
+       nameserv_family = AF_UNSPEC;
 
 #ifdef WINDOWS32
        WSAStartup(req_version, &wsa_data);
@@ -161,7 +179,7 @@ main(int argc, char **argv)
 
        srand((unsigned) time(NULL));
        client_init();
-       
+
 #if !defined(BSD) && !defined(__GLIBC__)
        __progname = strrchr(argv[0], '/');
        if (__progname == NULL)
@@ -170,8 +188,14 @@ main(int argc, char **argv)
                __progname++;
 #endif
 
-       while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) {
+       while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) {
                switch(choice) {
+               case '4':
+                       nameserv_family = AF_INET;
+                       break;
+               case '6':
+                       nameserv_family = AF_INET6;
+                       break;
                case 'v':
                        version();
                        /* NOTREACHED */
@@ -185,6 +209,7 @@ main(int argc, char **argv)
                        break;
                case 'r':
                        raw_mode = 0;
+                       break;
                case 'u':
                        username = optarg;
                        break;
@@ -194,12 +219,17 @@ main(int argc, char **argv)
                case 'd':
                        device = optarg;
                        break;
+#ifdef OPENBSD
+               case 'R':
+                       rtable = atoi(optarg);
+                       break;
+#endif
                case 'P':
                        strncpy(password, optarg, sizeof(password));
                        password[sizeof(password)-1] = 0;
-                       
+
                        /* XXX: find better way of cleaning up ps(1) */
-                       memset(optarg, 0, strlen(optarg)); 
+                       memset(optarg, 0, strlen(optarg));
                        break;
                case 'm':
                        autodetect_frag_size = 0;
@@ -217,12 +247,13 @@ main(int argc, char **argv)
                        break;
                case 'F':
                        pidfile = optarg;
-                       break;    
+                       break;
                case 'T':
-                       set_qtype(optarg);
+                       if (client_set_qtype(optarg))
+                               errx(5, "Invalid query type '%s'", optarg);
                        break;
                case 'O':       /* not -D, is Debug in server */
-                       set_downenc(optarg);
+                       client_set_downenc(optarg);
                        break;
                case 'L':
                        lazymode = atoi(optarg);
@@ -243,7 +274,7 @@ main(int argc, char **argv)
                        /* NOTREACHED */
                }
        }
-       
+
        check_superuser(usage);
 
        argc -= optind;
@@ -251,11 +282,11 @@ main(int argc, char **argv)
 
        switch (argc) {
        case 1:
-               nameserv_addr = get_resolvconf_addr();
+               nameserv_host = get_resolvconf_addr();
                topdomain = strdup(argv[0]);
                break;
        case 2:
-               nameserv_addr = argv[0];
+               nameserv_host = argv[0];
                topdomain = strdup(argv[1]);
                break;
        default:
@@ -269,22 +300,21 @@ main(int argc, char **argv)
                /* NOTREACHED */
        }
 
-       if (nameserv_addr) {
-               client_set_nameserver(nameserv_addr, DNS_PORT);
+       if (nameserv_host) {
+               nameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr);
+               if (nameservaddr_len < 0) {
+                       errx(1, "Cannot lookup nameserver '%s': %s ",
+                               nameserv_host, gai_strerror(nameservaddr_len));
+               }
+               client_set_nameserver(&nameservaddr, nameservaddr_len);
        } else {
                warnx("No nameserver found - not connected to any network?\n");
                usage();
                /* NOTREACHED */
-       }       
+       }
 
-       if (strlen(topdomain) <= 128) {
-               if(check_topdomain(topdomain)) {
-                       warnx("Topdomain contains invalid characters.\n");
-                       usage();
-                       /* NOTREACHED */
-               }
-       } else {
-               warnx("Use a topdomain max 128 chars long.\n");
+       if(check_topdomain(topdomain, &errormsg)) {
+               warnx("Invalid topdomain: %s", errormsg);
                usage();
                /* NOTREACHED */
        }
@@ -293,7 +323,7 @@ main(int argc, char **argv)
        client_set_lazymode(lazymode);
        client_set_topdomain(topdomain);
        client_set_hostname_maxlen(hostname_maxlen);
-       
+
        if (username != NULL) {
 #ifndef WINDOWS32
                if ((pw = getpwnam(username)) == NULL) {
@@ -303,51 +333,55 @@ main(int argc, char **argv)
                }
 #endif
        }
-       
+
        if (strlen(password) == 0) {
                if (NULL != getenv(PASSWORD_ENV_VAR))
                        snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
                else
                        read_password(password, sizeof(password));
        }
-       
+
        client_set_password(password);
 
        if ((tun_fd = open_tun(device)) == -1) {
                retval = 1;
                goto cleanup1;
        }
-       if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) {
+       if ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {
                retval = 1;
                goto cleanup2;
        }
+#ifdef OPENBSD
+       if (rtable > 0)
+               socket_setrtable(dns_fd, rtable);
+#endif
 
        signal(SIGINT, sighandler);
        signal(SIGTERM, sighandler);
 
        fprintf(stderr, "Sending DNS queries for %s to %s\n",
-               topdomain, nameserv_addr);
+               topdomain, format_addr(&nameservaddr, nameservaddr_len));
 
        if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
                retval = 1;
                goto cleanup2;
        }
-       
+
        if (client_get_conn() == CONN_RAW_UDP) {
                fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
        }
 
        fprintf(stderr, "Connection setup complete, transmitting data.\n");
 
-       if (foreground == 0) 
+       if (foreground == 0)
                do_detach();
-       
+
        if (pidfile != NULL)
                do_pidfile(pidfile);
 
        if (newroot != NULL)
                do_chroot(newroot);
-       
+
        if (username != NULL) {
 #ifndef WINDOWS32
                gid_t gids[1];
index 3681084e28389d03d33d28da89826d6c335233dd..1065c33073e7fdab9febe60ac8d3cd800d2dbba8 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -18,6 +19,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/param.h>
 #include "fw_query.h"
 #include "version.h"
 
+#ifdef HAVE_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+
 #ifdef WINDOWS32
 WORD req_version = MAKEWORD(2, 2);
 WSADATA wsa_data;
@@ -93,8 +99,60 @@ static int read_dns(int, int, struct query *);
 static void write_dns(int, struct query *, char *, int, char);
 static void handle_full_packet(int, int, int);
 
+/* Ask externalip.net webservice to get external ip */
+static int get_external_ip(struct in_addr *ip)
+{
+       int sock;
+       struct addrinfo *addr;
+       int res;
+       const char *getstr = "GET /ip/ HTTP/1.0\r\n"
+               /* HTTP 1.0 to avoid chunked transfer coding */
+               "Host: api.externalip.net\r\n\r\n";
+       char buf[512];
+       char *b;
+       int len;
+
+       res = getaddrinfo("api.externalip.net", "80", NULL, &addr);
+       if (res < 0) return 1;
+
+       sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+       if (sock < 0) {
+               freeaddrinfo(addr);
+               return 2;
+       }
+
+       res = connect(sock, addr->ai_addr, addr->ai_addrlen);
+       freeaddrinfo(addr);
+       if (res < 0) return 3;
+
+       res = write(sock, getstr, strlen(getstr));
+       if (res != strlen(getstr)) return 4;
+
+       /* Zero buf before receiving, leave at least one zero at the end */
+       memset(buf, 0, sizeof(buf));
+       res = read(sock, buf, sizeof(buf) - 1);
+       if (res < 0) return 5;
+       len = res;
+
+       res = close(sock);
+       if (res < 0) return 6;
+
+       b = buf;
+       while (len > 9) {
+               /* Look for split between headers and data */
+               if (strncmp("\r\n\r\n", b, 4) == 0) break;
+               b++;
+               len--;
+       }
+       if (len < 10) return 7;
+       b += 4;
+
+       res = inet_aton(b, ip);
+       return (res == 0);
+}
+
 static void
-sigint(int sig) 
+sigint(int sig)
 {
        running = 0;
 }
@@ -116,6 +174,7 @@ syslog(int a, const char *str, ...)
 }
 #endif
 
+/* This will not check that user has passed login challenge */
 static int
 check_user_and_ip(int userid, struct query *q)
 {
@@ -124,7 +183,7 @@ check_user_and_ip(int userid, struct query *q)
        /* Note: duplicate in handle_raw_login() except IP-address check */
 
        if (userid < 0 || userid >= created_users ) {
-               return 1; 
+               return 1;
        }
        if (!users[userid].active || users[userid].disabled) {
                return 1;
@@ -142,6 +201,20 @@ check_user_and_ip(int userid, struct query *q)
        return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
 }
 
+/* This checks that user has passed normal (non-raw) login challenge */
+static int
+check_authenticated_user_and_ip(int userid, struct query *q)
+{
+       int res = check_user_and_ip(userid, q);
+       if (res)
+               return res;
+
+       if (!users[userid].authenticated)
+               return 1;
+
+       return 0;
+}
+
 static void
 send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)
 {
@@ -159,13 +232,11 @@ send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)
        packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
 
        if (debug >= 2) {
-               struct sockaddr_in *tempin;
-               tempin = (struct sockaddr_in *) &(q->from);
-               fprintf(stderr, "TX-raw: client %s, cmd %d, %d bytes\n", 
-                       inet_ntoa(tempin->sin_addr), cmd, len);
+               fprintf(stderr, "TX-raw: client %s, cmd %d, %d bytes\n",
+                       format_addr(&q->from, q->fromlen), cmd, len);
        }
 
-       sendto(fd, packet, len, 0, &q->from, q->fromlen);
+       sendto(fd, packet, len, 0, (struct sockaddr *) &q->from, q->fromlen);
 }
 
 
@@ -496,12 +567,12 @@ send_chunk_or_dataless(int dns_fd, int userid, struct query *q)
        pkt[0] = (1<<7) | ((users[userid].inpacket.seqno & 7) << 4) |
                (users[userid].inpacket.fragment & 15);
        /* Second byte is 3 bits downstream seqno, 4 bits downstream fragment, 1 bit last flag */
-       pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) | 
+       pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) |
                ((users[userid].outpacket.fragment & 15) << 1) | (last & 1);
 
        if (debug >= 1) {
                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, 
+                       users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15,
                        last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid);
        }
        write_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc);
@@ -555,7 +626,7 @@ tunnel_tun(int tun_fd, int dns_fd)
 
        if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
                return 0;
-       
+
        /* find target ip in packet, in is padded with 4 bytes TUN header */
        header = (struct ip*) (in + 4);
        userid = find_user_by_ip(header->ip_dst.s_addr);
@@ -601,7 +672,7 @@ static void
 send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, struct query *q)
 {
        char out[9];
-       
+
        switch (ack) {
        case VERSION_ACK:
                strncpy(out, "VACK", sizeof(out));
@@ -613,7 +684,7 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, s
                strncpy(out, "VFUL", sizeof(out));
                break;
        }
-       
+
        out[4] = ((payload >> 24) & 0xff);
        out[5] = ((payload >> 16) & 0xff);
        out[6] = ((payload >> 8) & 0xff);
@@ -686,7 +757,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32);
                /* Version greeting, compare and send ack/nak */
-               if (read > 4) { 
+               if (read > 4) {
                        /* Received V + 32bits version */
                        version = (((unpacked[0] & 0xff) << 24) |
                                           ((unpacked[1] & 0xff) << 16) |
@@ -704,13 +775,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                                /* Store remote IP number */
                                tempin = (struct sockaddr_in *) &(q->from);
                                memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
-                               
+
                                memcpy(&(users[userid].q), q, sizeof(struct query));
                                users[userid].encoder = get_base32_encoder();
                                users[userid].downenc = 'T';
                                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));
+                                       userid, format_addr(&q->from, q->fromlen));
                                users[userid].q.id = 0;
                                users[userid].q.id2 = 0;
                                users[userid].q_sendrealsoon.id = 0;
@@ -751,13 +822,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                        } 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));
+                               syslog(LOG_INFO, "dropped user from %s, server full",
+                                       format_addr(&q->from, q->fromlen));
                        }
                } 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);
+                       syslog(LOG_INFO, "dropped user from %s, sent bad version %08X",
+                               format_addr(&q->from, q->fromlen), version);
                }
                return;
        } else if(in[0] == 'L' || in[0] == 'l') {
@@ -773,21 +844,23 @@ 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, 'T');
                        syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s",
-                               userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
+                               userid, format_addr(&q->from, q->fromlen));
                        return;
                } else {
                        users[userid].last_pkt = time(NULL);
                        login_calculate(logindata, 16, password, users[userid].seed);
 
                        if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
-                               /* Login ok, send ip/mtu/netmask info */
+                               /* Store login ok */
+                               users[userid].authenticated = 1;
 
+                               /* Send ip/mtu/netmask info */
                                tempip.s_addr = my_ip;
                                tmp[0] = strdup(inet_ntoa(tempip));
                                tempip.s_addr = users[userid].tun_ip;
                                tmp[1] = strdup(inet_ntoa(tempip));
 
-                               read = snprintf(out, sizeof(out), "%s-%s-%d-%d", 
+                               read = snprintf(out, sizeof(out), "%s-%s-%d-%d",
                                                tmp[0], tmp[1], my_mtu, netmask);
 
                                write_dns(dns_fd, q, out, read, users[userid].downenc);
@@ -799,7 +872,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                        } else {
                                write_dns(dns_fd, q, "LNAK", 4, 'T');
                                syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password",
-                                       userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr));
+                                       userid, format_addr(&q->from, q->fromlen));
                        }
                }
                return;
@@ -808,9 +881,9 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                in_addr_t replyaddr;
                unsigned addr;
                char reply[5];
-               
+
                userid = b32_8to5(in[1]);
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
@@ -846,12 +919,12 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                }
 
                userid = b32_8to5(in[1]);
-               
-               if (check_user_and_ip(userid, q) != 0) {
+
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
-               
+
                codec = b32_8to5(in[2]);
 
                switch (codec) {
@@ -888,7 +961,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                userid = b32_8to5(in[1]);
 
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
@@ -1016,13 +1089,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                /* Downstream fragsize probe packet */
                userid = (b32_8to5(in[1]) >> 1) & 15;
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
-                               
+
                req_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31);
-               if (req_frag_size < 2 || req_frag_size > 2047) {        
+               if (req_frag_size < 2 || req_frag_size > 2047) {
                        write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc);
                } else {
                        char buf[2048];
@@ -1051,13 +1124,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                /* Downstream fragsize packet */
                userid = unpacked[0];
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
-                               
+
                max_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff);
-               if (max_frag_size < 2) {        
+               if (max_frag_size < 2) {
                        write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc);
                } else {
                        users[userid].fragsize = max_frag_size;
@@ -1084,7 +1157,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                /* Ping packet, store userid */
                userid = unpacked[0];
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
@@ -1122,7 +1195,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                        memcpy(&(users[userid].q.from2), &(q->from), q->fromlen);
                        return;
                }
+
                if (users[userid].q_sendrealsoon.id != 0 &&
                    q->type == users[userid].q_sendrealsoon.type &&
                    !strcmp(q->name, users[userid].q_sendrealsoon.name)) {
@@ -1138,7 +1211,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                               &(q->from), q->fromlen);
                        return;
                }
-                               
+
                dn_seq = unpacked[1] >> 4;
                dn_frag = unpacked[1] & 15;
 
@@ -1214,7 +1287,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                userid = code;
                /* Check user and sending ip number */
-               if (check_user_and_ip(userid, q) != 0) {
+               if (check_authenticated_user_and_ip(userid, q) != 0) {
                        write_dns(dns_fd, q, "BADIP", 5, 'T');
                        return; /* illegal id */
                }
@@ -1233,7 +1306,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                   like to re-try early and often (with _different_ .id!)  */
                if (users[userid].q.id != 0 &&
                    q->type == users[userid].q.type &&
-                   !strcmp(q->name, users[userid].q.name) && 
+                   !strcmp(q->name, users[userid].q.name) &&
                    users[userid].lazy) {
                        /* We have this packet already, and it's waiting to be
                           answered. Always keep the last duplicate, since the
@@ -1250,7 +1323,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                        memcpy(&(users[userid].q.from2), &(q->from), q->fromlen);
                        return;
                }
-  
+
                if (users[userid].q_sendrealsoon.id != 0 &&
                    q->type == users[userid].q_sendrealsoon.type &&
                    !strcmp(q->name, users[userid].q_sendrealsoon.name)) {
@@ -1266,7 +1339,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
                               &(q->from), q->fromlen);
                        return;
                }
-  
+
 
                /* Decode data header */
                up_seq = (b32_8to5(in[1]) >> 2) & 7;
@@ -1277,7 +1350,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
 
                process_downstream_ack(userid, dn_seq, dn_frag);
 
-               if (up_seq == users[userid].inpacket.seqno && 
+               if (up_seq == users[userid].inpacket.seqno &&
                        up_frag <= users[userid].inpacket.fragment) {
                        /* Got repeated old packet _with data_, probably
                           because client didn't receive our ack. So re-send
@@ -1435,12 +1508,10 @@ handle_ns_request(int dns_fd, struct query *q)
                warnx("dns_encode_ns_response doesn't fit");
                return;
        }
-       
+
        if (debug >= 2) {
-               struct sockaddr_in *tempin;
-               tempin = (struct sockaddr_in *) &(q->from);
-               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n", 
-                       inet_ntoa(tempin->sin_addr), q->type, q->name, len);
+               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n",
+                       format_addr(&q->from, q->fromlen), q->type, q->name, len);
        }
        if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
                warn("ns reply send error");
@@ -1469,12 +1540,10 @@ handle_a_request(int dns_fd, struct query *q, int fakeip)
                warnx("dns_encode_a_response doesn't fit");
                return;
        }
-       
+
        if (debug >= 2) {
-               struct sockaddr_in *tempin;
-               tempin = (struct sockaddr_in *) &(q->from);
                fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes A reply\n",
-                       inet_ntoa(tempin->sin_addr), q->type, q->name, len);
+                       format_addr(&q->from, q->fromlen), q->type, q->name, len);
        }
        if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
                warn("a reply send error");
@@ -1506,7 +1575,7 @@ forward_query(int bind_fd, struct query *q)
        myaddr = (struct sockaddr_in *) &(q->from);
        memcpy(&(myaddr->sin_addr), &newaddr, sizeof(in_addr_t));
        myaddr->sin_port = htons(bind_port);
-       
+
        if (debug >= 2) {
                fprintf(stderr, "TX: NS reply \n");
        }
@@ -1515,45 +1584,45 @@ forward_query(int bind_fd, struct query *q)
                warn("forward query error");
        }
 }
-  
+
 static int
 tunnel_bind(int bind_fd, int dns_fd)
 {
        char packet[64*1024];
-       struct sockaddr_in from;
+       struct sockaddr_storage from;
        socklen_t fromlen;
        struct fw_query *query;
        unsigned short id;
        int r;
 
        fromlen = sizeof(struct sockaddr);
-       r = recvfrom(bind_fd, packet, sizeof(packet), 0, 
+       r = recvfrom(bind_fd, packet, sizeof(packet), 0,
                (struct sockaddr*)&from, &fromlen);
 
        if (r <= 0)
                return 0;
 
        id = dns_get_id(packet, r);
-       
+
        if (debug >= 2) {
                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) {
-               fprintf(stderr, "Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
+       if (!query) {
+               if (debug >= 2) {
+                       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);
                fprintf(stderr, "TX: client %s id %u, %d bytes\n",
-                       inet_ntoa(in->sin_addr), (id & 0xffff), r);
+                       format_addr(&query->addr, query->addrlen), (id & 0xffff), r);
        }
-       
-       if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), 
+
+       if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr),
                query->addrlen) <= 0) {
                warn("forward reply error");
        }
@@ -1567,16 +1636,14 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
        struct query q;
        int read;
        int domain_len;
-       int inside_topdomain;
+       int inside_topdomain = 0;
 
        if ((read = read_dns(dns_fd, tun_fd, &q)) <= 0)
                return 0;
 
        if (debug >= 2) {
-               struct sockaddr_in *tempin;
-               tempin = (struct sockaddr_in *) &(q.from);
-               fprintf(stderr, "RX: client %s, type %d, name %s\n", 
-                       inet_ntoa(tempin->sin_addr), q.type, q.name);
+               fprintf(stderr, "RX: client %s, type %d, name %s\n",
+                       format_addr(&q.from, q.fromlen), q.type, q.name);
        }
 
        domain_len = strlen(q.name) - strlen(topdomain);
@@ -1612,6 +1679,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
 
                switch (q.type) {
                case T_NULL:
+               case T_PRIVATE:
                case T_CNAME:
                case T_A:
                case T_MX:
@@ -1636,12 +1704,13 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
 }
 
 static int
-tunnel(int tun_fd, int dns_fd, int bind_fd)
+tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time)
 {
        struct timeval tv;
        fd_set fds;
        int i;
        int userid;
+       time_t last_action = time(NULL);
 
        while (running) {
                int maxfd;
@@ -1655,7 +1724,7 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
                   requests during heavy upstream traffic.
                   20msec: ~8 packs every 1/50sec = ~400 DNSreq/sec,
                   or ~1200bytes every 1/50sec = ~0.5 Mbit/sec upstream */
-               for (userid = 0; userid < USERS; userid++) {
+               for (userid = 0; userid < created_users; userid++) {
                        if (users[userid].active && !users[userid].disabled &&
                            users[userid].last_pkt + 60 > time(NULL)) {
                                users[userid].q_sendrealsoon_new = 0;
@@ -1685,29 +1754,41 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
                }
 
                i = select(maxfd + 1, &fds, NULL, NULL, &tv);
-               
+
                if(i < 0) {
-                       if (running) 
+                       if (running)
                                warn("select");
                        return 1;
                }
 
-               if (i==0) {     
-                       /* timeout; whatever; doesn't matter anymore */
+               if (i==0) {
+                       if (max_idle_time) {
+                               /* only trigger the check if that's worth ( ie, no need to loop over if there
+                               is something to send */
+                               if (last_action + max_idle_time < time(NULL)) {
+                                       for (userid = 0; userid < created_users; userid++) {
+                                               last_action = ( users[userid].last_pkt > last_action ) ? users[userid].last_pkt : last_action;
+                                       }
+                                       if (last_action + max_idle_time < time(NULL)) {
+                                               fprintf(stderr, "Idling since too long, shutting down...\n");
+                                               running = 0;
+                                       }
+                               }
+                       }
                } else {
                        if (FD_ISSET(tun_fd, &fds)) {
                                tunnel_tun(tun_fd, dns_fd);
                        }
                        if (FD_ISSET(dns_fd, &fds)) {
                                tunnel_dns(tun_fd, dns_fd, bind_fd);
-                       } 
+                       }
                        if (FD_ISSET(bind_fd, &fds)) {
                                tunnel_bind(bind_fd, dns_fd);
                        }
                }
 
                /* Send realsoon's if tun or dns didn't already */
-               for (userid = 0; userid < USERS; userid++)
+               for (userid = 0; userid < created_users; userid++)
                        if (users[userid].active && !users[userid].disabled &&
                            users[userid].last_pkt + 60 > time(NULL) &&
                            users[userid].q_sendrealsoon.id != 0 &&
@@ -1728,7 +1809,7 @@ handle_full_packet(int tun_fd, int dns_fd, int userid)
        int ret;
 
        outlen = sizeof(out);
-       ret = uncompress((uint8_t*)out, &outlen, 
+       ret = uncompress((uint8_t*)out, &outlen,
                   (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
 
        if (ret == Z_OK) {
@@ -1742,31 +1823,29 @@ handle_full_packet(int tun_fd, int dns_fd, int userid)
                        write_tun(tun_fd, out, outlen);
                } else {
                        /* send the compressed(!) packet to other client */
-               /*XXX START adjust indent 1 tab forward*/
-               if (users[touser].conn == CONN_DNS_NULL) {
-                       if (users[touser].outpacket.len == 0) {
-                               start_new_outpacket(touser,
-                                       users[userid].inpacket.data,
-                                       users[userid].inpacket.len);
-
-                               /* Start sending immediately if query is waiting */
-                               if (users[touser].q_sendrealsoon.id != 0)
-                                       send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon);
-                               else if (users[touser].q.id != 0)
-                                       send_chunk_or_dataless(dns_fd, touser, &users[touser].q);
+                       if (users[touser].conn == CONN_DNS_NULL) {
+                               if (users[touser].outpacket.len == 0) {
+                                       start_new_outpacket(touser,
+                                               users[userid].inpacket.data,
+                                               users[userid].inpacket.len);
+
+                                       /* Start sending immediately if query is waiting */
+                                       if (users[touser].q_sendrealsoon.id != 0)
+                                               send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon);
+                                       else if (users[touser].q.id != 0)
+                                               send_chunk_or_dataless(dns_fd, touser, &users[touser].q);
 #ifdef OUTPACKETQ_LEN
-                       } else {
-                               save_to_outpacketq(touser,
-                                       users[userid].inpacket.data,
-                                       users[userid].inpacket.len);
+                               } else {
+                                       save_to_outpacketq(touser,
+                                               users[userid].inpacket.data,
+                                               users[userid].inpacket.len);
 #endif
+                               }
+                       } else{ /* CONN_RAW_UDP */
+                               send_raw(dns_fd, users[userid].inpacket.data,
+                                        users[userid].inpacket.len, touser,
+                                        RAW_HDR_CMD_DATA, &users[touser].q);
                        }
-               } else{ /* CONN_RAW_UDP */
-                       send_raw(dns_fd, users[userid].inpacket.data,
-                                users[userid].inpacket.len, touser,
-                                RAW_HDR_CMD_DATA, &users[touser].q);
-               }
-               /*XXX END adjust indent 1 tab forward*/
                }
        } else {
                if (debug >= 1)
@@ -1782,13 +1861,14 @@ static void
 handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
 {
        char myhash[16];
-       
+
        if (len < 16) return;
 
-       /* can't use check_user_and_ip() since IP address will be different,
+       /* can't use check_authenticated_user_and_ip() since IP address will be different,
           so duplicate here except IP address */
        if (userid < 0 || userid >= created_users) return;
        if (!users[userid].active || users[userid].disabled) return;
+       if (!users[userid].authenticated) return;
        if (users[userid].last_pkt + 60 < time(NULL)) return;
 
        if (debug >= 1) {
@@ -1808,20 +1888,23 @@ handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
                /* Store remote IP number */
                tempin = (struct sockaddr_in *) &(q->from);
                memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
-                
+
                /* Correct hash, reply with hash of seed - 1 */
                user_set_conn_type(userid, CONN_RAW_UDP);
                login_calculate(myhash, 16, password, users[userid].seed - 1);
                send_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q);
+
+               users[userid].authenticated_raw = 1;
        }
 }
 
 static void
 handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, int userid)
 {
-       if (check_user_and_ip(userid, q) != 0) {
+       if (check_authenticated_user_and_ip(userid, q) != 0) {
                return;
        }
+       if (!users[userid].authenticated_raw) return;
 
        /* Update query and time info for user */
        users[userid].last_pkt = time(NULL);
@@ -1843,9 +1926,10 @@ handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd,
 static void
 handle_raw_ping(struct query *q, int dns_fd, int userid)
 {
-       if (check_user_and_ip(userid, q) != 0) {
+       if (check_authenticated_user_and_ip(userid, q) != 0) {
                return;
        }
+       if (!users[userid].authenticated_raw) return;
 
        /* Update query and time info for user */
        users[userid].last_pkt = time(NULL);
@@ -1914,7 +1998,7 @@ read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw
        msg.msg_control = address;
        msg.msg_controllen = sizeof(address);
        msg.msg_flags = 0;
-       
+
        r = recvmsg(fd, &msg, 0);
 #else
        addrlen = sizeof(struct sockaddr);
@@ -1932,22 +2016,22 @@ read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw
                if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) {
                        return 0;
                }
-               
+
 #ifndef WINDOWS32
-               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 
-                       cmsg = CMSG_NXTHDR(&msg, cmsg)) { 
-                       
-                       if (cmsg->cmsg_level == IPPROTO_IP && 
-                               cmsg->cmsg_type == DSTADDR_SOCKOPT) { 
-                               
-                               q->destination = *dstaddr(cmsg); 
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+
+                       if (cmsg->cmsg_level == IPPROTO_IP &&
+                               cmsg->cmsg_type == DSTADDR_SOCKOPT) {
+
+                               q->destination = *dstaddr(cmsg);
                                break;
-                       } 
+                       }
                }
 #endif
 
                return strlen(q->name);
-       } else if (r < 0) { 
+       } else if (r < 0) {
                /* Error */
                warn("read dns");
        }
@@ -1977,7 +2061,7 @@ write_dns_nameenc(char *buf, size_t buflen, char *data, int datalen, char downen
        space = MIN(0xFF, buflen) - 4 - 2;
        /* -1 encoding type, -3 ".xy", -2 for safety */
 
-       memset(buf, 0, sizeof(buf));
+       memset(buf, 0, buflen);
 
        if (downenc == 'S') {
                buf[0] = 'i';
@@ -2012,7 +2096,7 @@ write_dns_nameenc(char *buf, size_t buflen, char *data, int datalen, char downen
        /* Add dot (if it wasn't there already) and topdomain */
        b = buf;
        b += strlen(buf) - 1;
-       if (*b != '.') 
+       if (*b != '.')
                *++b = '.';
         b++;
 
@@ -2104,12 +2188,10 @@ write_dns(int fd, struct query *q, char *data, int datalen, char downenc)
                warnx("dns_encode doesn't fit");
                return;
        }
-       
+
        if (debug >= 2) {
-               struct sockaddr_in *tempin;
-               tempin = (struct sockaddr_in *) &(q->from);
-               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n", 
-                       inet_ntoa(tempin->sin_addr), q->type, q->name, datalen);
+               fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n",
+                       format_addr(&q->from, q->fromlen), q->type, q->name, datalen);
        }
 
        sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
@@ -2122,7 +2204,7 @@ usage() {
        fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] "
                "[-t chrootdir] [-d device] [-m mtu] [-z context] "
                "[-l ip address to listen on] [-p port] [-n external ip] "
-               "[-b dnsport] [-P password] [-F pidfile] "
+               "[-b dnsport] [-P password] [-F pidfile] [-i max idle time] "
                "tunnel_ip[/netmask] topdomain\n", __progname);
        exit(2);
 }
@@ -2156,6 +2238,7 @@ help() {
        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, "  -F pidfile to write pid to a file\n");
+       fprintf(stderr, "  -i maximum idle time before shutting down\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");
@@ -2165,7 +2248,7 @@ help() {
 static void
 version() {
        fprintf(stderr, "iodine IP over DNS tunneling server\n");
-       fprintf(stderr, "version: 0.6.0-rc1 from 2010-02-13\n");
+       fprintf(stderr, "version: 0.7.0 from 2014-06-16\n");
        exit(0);
 }
 
@@ -2173,7 +2256,8 @@ int
 main(int argc, char **argv)
 {
        extern char *__progname;
-       in_addr_t listen_ip;
+       char *listen_ip;
+       char *errormsg;
 #ifndef WINDOWS32
        struct passwd *pw;
 #endif
@@ -2186,21 +2270,29 @@ main(int argc, char **argv)
        int dnsd_fd;
        int tun_fd;
 
-       /* settings for forwarding normal DNS to 
+       /* settings for forwarding normal DNS to
         * local real DNS server */
        int bind_fd;
        int bind_enable;
-       
+
        int choice;
        int port;
        int mtu;
        int skipipconfig;
        char *netsize;
+       int ns_get_externalip;
        int retval;
+       int max_idle_time = 0;
+       struct sockaddr_storage dnsaddr;
+       int dnsaddr_len;
+#ifdef HAVE_SYSTEMD
+       int nb_fds;
+#endif
 
 #ifndef WINDOWS32
        pw = NULL;
 #endif
+       errormsg = NULL;
        username = NULL;
        newroot = NULL;
        context = NULL;
@@ -2210,9 +2302,10 @@ main(int argc, char **argv)
        bind_fd = 0;
        mtu = 1130;     /* Very many relays give fragsize 1150 or slightly
                           higher for NULL; tun/zlib adds ~17 bytes. */
-       listen_ip = INADDR_ANY;
+       listen_ip = NULL;
        port = 53;
        ns_ip = INADDR_ANY;
+       ns_get_externalip = 0;
        check_ip = 1;
        skipipconfig = 0;
        debug = 0;
@@ -2223,7 +2316,7 @@ main(int argc, char **argv)
        b64 = get_base64_encoder();
        b64u = get_base64u_encoder();
        b128 = get_base128_encoder();
-       
+
        retval = 0;
 
 #ifdef WINDOWS32
@@ -2241,8 +2334,8 @@ main(int argc, char **argv)
        memset(password, 0, sizeof(password));
        srand(time(NULL));
        fw_query_init();
-       
-       while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:n:b:P:z:F:")) != -1) {
+
+       while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:n:b:P:z:F:i:")) != -1) {
                switch(choice) {
                case 'v':
                        version();
@@ -2275,13 +2368,17 @@ main(int argc, char **argv)
                        mtu = atoi(optarg);
                        break;
                case 'l':
-                       listen_ip = inet_addr(optarg);
+                       listen_ip = optarg;
                        break;
                case 'p':
                        port = atoi(optarg);
                        break;
                case 'n':
-                       ns_ip = inet_addr(optarg);
+                       if (optarg && strcmp("auto", optarg) == 0) {
+                               ns_get_externalip = 1;
+                       } else {
+                               ns_ip = inet_addr(optarg);
+                       }
                        break;
                case 'b':
                        bind_enable = 1;
@@ -2289,13 +2386,16 @@ main(int argc, char **argv)
                        break;
                case 'F':
                        pidfile = optarg;
-                       break;    
+                       break;
+               case 'i':
+                       max_idle_time = atoi(optarg);
+                       break;
                case 'P':
                        strncpy(password, optarg, sizeof(password));
                        password[sizeof(password)-1] = 0;
-                       
+
                        /* XXX: find better way of cleaning up ps(1) */
-                       memset(optarg, 0, strlen(optarg)); 
+                       memset(optarg, 0, strlen(optarg));
                        break;
                case 'z':
                        context = optarg;
@@ -2311,9 +2411,9 @@ main(int argc, char **argv)
 
        check_superuser(usage);
 
-       if (argc != 2) 
+       if (argc != 2)
                usage();
-       
+
        netsize = strchr(argv[0], '/');
        if (netsize) {
                *netsize = 0;
@@ -2322,21 +2422,17 @@ main(int argc, char **argv)
        }
 
        my_ip = inet_addr(argv[0]);
-       
+
        if (my_ip == INADDR_NONE) {
                warnx("Bad IP address to use inside tunnel.");
                usage();
        }
 
        topdomain = strdup(argv[1]);
-       if (strlen(topdomain) <= 128) {
-               if(check_topdomain(topdomain)) {
-                       warnx("Topdomain contains invalid characters.");
-                       usage();
-               }
-       } else {
-               warnx("Use a topdomain max 128 chars long.");
+       if(check_topdomain(topdomain, &errormsg)) {
+               warnx("Invalid topdomain: %s", errormsg);
                usage();
+               /* NOTREACHED */
        }
 
        if (username != NULL) {
@@ -2352,20 +2448,38 @@ main(int argc, char **argv)
                warnx("Bad MTU given.");
                usage();
        }
-       
+
        if(port < 1 || port > 65535) {
                warnx("Bad port number given.");
                usage();
        }
-       
+
+       if (port != 53) {
+               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) {
+               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;
+       }
+
+       dnsaddr_len = get_addr(listen_ip, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dnsaddr);
+       if (dnsaddr_len < 0) {
+               warnx("Bad IP address to listen on.");
+               usage();
+       }
+
        if(bind_enable) {
+               in_addr_t dns_ip = ((struct sockaddr_in *) &dnsaddr)->sin_addr.s_addr;
                if (bind_port < 1 || bind_port > 65535) {
                        warnx("Bad DNS server port number given.");
                        usage();
                        /* NOTREACHED */
                }
                /* Avoid forwarding loops */
-               if (bind_port == port && (listen_ip == INADDR_ANY || listen_ip == htonl(0x7f000001L))) {
+               if (bind_port == port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) {
                        warnx("Forward port is same as listen port (%d), will create a loop!", bind_port);
                        fprintf(stderr, "Use -l to set listen ip to avoid this.\n");
                        usage();
@@ -2374,23 +2488,18 @@ main(int argc, char **argv)
                fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n",
                        topdomain, bind_port);
        }
-       
-       if (port != 53) {
-               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) {
-               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;
+       if (ns_get_externalip) {
+               struct in_addr extip;
+               int res = get_external_ip(&extip);
+               if (res) {
+                       fprintf(stderr, "Failed to get external IP via web service.\n");
+                       exit(3);
+               }
+               ns_ip = extip.s_addr;
+               fprintf(stderr, "Using %s as external IP.\n", inet_ntoa(extip));
        }
 
-       if (listen_ip == INADDR_NONE) {
-               warnx("Bad IP address to listen on.");
-               usage();
-       }
-       
        if (ns_ip == INADDR_NONE) {
                warnx("Bad IP address to return as nameserver.");
                usage();
@@ -2399,7 +2508,7 @@ main(int argc, char **argv)
                warnx("Bad netmask (%d bits). Use 8-30 bits.", netmask);
                usage();
        }
-       
+
        if (strlen(password) == 0) {
                if (NULL != getenv(PASSWORD_ENV_VAR))
                        snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
@@ -2414,33 +2523,49 @@ main(int argc, char **argv)
                goto cleanup0;
        }
        if (!skipipconfig) {
-               if (tun_setip(argv[0], users_get_first_ip(), netmask) != 0 || tun_setmtu(mtu) != 0) {
+               const char *other_ip = users_get_first_ip();
+               if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {
                        retval = 1;
+                       free((void*) other_ip);
                        goto cleanup1;
                }
+               free((void*) other_ip);
        }
-       if ((dnsd_fd = open_dns(port, listen_ip)) == -1) {
+#ifdef HAVE_SYSTEMD
+       nb_fds = sd_listen_fds(0);
+       if (nb_fds > 1) {
                retval = 1;
-               goto cleanup2;
+               warnx("Too many file descriptors received!\n");
+               goto cleanup1;
+       } else if (nb_fds == 1) {
+               dnsd_fd = SD_LISTEN_FDS_START;
+       } else {
+#endif
+               if ((dnsd_fd = open_dns(&dnsaddr, dnsaddr_len)) < 0) {
+                       retval = 1;
+                       goto cleanup2;
+               }
+#ifdef HAVE_SYSTEMD
        }
+#endif
        if (bind_enable) {
-               if ((bind_fd = open_dns(0, INADDR_ANY)) == -1) {
+               if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
                        retval = 1;
                        goto cleanup3;
                }
        }
 
        my_mtu = mtu;
-       
+
        if (created_users < USERS) {
                fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n",
                        created_users, netmask);
        }
        fprintf(stderr, "Listening to dns for domain %s\n", topdomain);
 
-       if (foreground == 0) 
+       if (foreground == 0)
                do_detach();
-       
+
        if (pidfile != NULL)
                do_pidfile(pidfile);
 
@@ -2470,8 +2595,8 @@ main(int argc, char **argv)
                do_setcon(context);
 
        syslog(LOG_INFO, "started, listening on port %d", port);
-       
-       tunnel(tun_fd, dnsd_fd, bind_fd);
+
+       tunnel(tun_fd, dnsd_fd, bind_fd, max_idle_time);
 
        syslog(LOG_INFO, "stopping");
 cleanup3:
@@ -2479,7 +2604,7 @@ cleanup3:
 cleanup2:
        close_dns(dnsd_fd);
 cleanup1:
-       close_tun(tun_fd);      
+       close_tun(tun_fd);
 cleanup0:
 
        return retval;
index c8827c3e754600d371a6f4a1c18578917f4277a6..a809998e6fec794cb7596f9ec8974125c0717781 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #ifdef WINDOWS32
 #include "windows.h"
 #else
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 
 #include "md5.h"
 
-/* 
- * Needs a 16byte array for output, and 32 bytes password 
+/*
+ * Needs a 16byte array for output, and 32 bytes password
  */
-void 
-login_calculate(char *buf, int buflen, const char *pass, int seed) 
+void
+login_calculate(char *buf, int buflen, const char *pass, int seed)
 {
        unsigned char temp[32];
        md5_state_t ctx;
@@ -37,7 +39,7 @@ login_calculate(char *buf, int buflen, const char *pass, int seed)
        int i;
        int k;
 
-       if (buflen < 16) 
+       if (buflen < 16)
                return;
 
        memcpy(temp, pass, 32);
index 840c9208d7b4a130d8ca2177f0c604e6ca0004ec..ebea25cf2463b3b94dc7298aab9196d8ba47fab7 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 698c995d8f4e9d98766d568fe88863381f94d16f..3baa4dcdfe2c3ac365ed897eaa6e06853501a9cf 100644 (file)
--- a/src/md5.h
+++ b/src/md5.h
@@ -71,7 +71,7 @@ typedef struct md5_state_s {
 } md5_state_t;
 
 #ifdef __cplusplus
-extern "C" 
+extern "C"
 {
 #endif
 
old mode 100644 (file)
new mode 100755 (executable)
index 787ffaa..9eda8f0
@@ -17,17 +17,26 @@ link)
                        echo '-lws2_32 -liphlpapi';
                ;;
                Linux)
-                       [ -e /usr/include/selinux/selinux.h ] && echo '-lselinux';
+                       FLAGS="";
+                       [ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -lselinux";
+                       [ -e /usr/include/systemd/sd-daemon.h ] && FLAGS="$FLAGS -lsystemd-daemon";
+                       echo $FLAGS;
                ;;
        esac
        ;;
 cflags)
        case $1 in
+               windows32)
+                       echo '-DWINVER=0x0501';
+               ;;
                BeOS)
                        echo '-Dsocklen_t=int';
                ;;
                Linux)
-                       [ -e /usr/include/selinux/selinux.h ] && echo '-DHAVE_SETCON';
+                       FLAGS="-D_GNU_SOURCE"
+                       [ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -DHAVE_SETCON";
+                       [ -e /usr/include/systemd/sd-daemon.h ] && FLAGS="$FLAGS -DHAVE_SYSTEMD";
+                       echo $FLAGS;
                ;;
        esac
 ;;
index ff40382b61a5f1c7bdfbee2a5aea3518e7ba7b64..a2dcd96ebcdb2d97c943b8c50247a5e4cee8d73d 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -60,7 +61,7 @@ readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length,
 
                        c--;
                }
-               
+
                if (len >= length - 1) {
                        break; /* We used up all space */
                }
@@ -84,15 +85,15 @@ readname(char *packet, int packetlen, char **src, char *dst, size_t length)
 }
 
 int
-readshort(char *packet, char **src, short *dst)
+readshort(char *packet, char **src, unsigned short *dst)
 {
        unsigned char *p;
 
        p = (unsigned char *) *src;
        *dst = (p[0] << 8) | p[1];
 
-       (*src) += sizeof(short);
-       return sizeof(short);
+       (*src) += sizeof(unsigned short);
+       return sizeof(unsigned short);
 }
 
 int
@@ -103,8 +104,8 @@ readlong(char *packet, char **src, uint32_t *dst)
 
        p = (unsigned char *) *src;
 
-       *dst = ((uint32_t)p[0] << 24) 
-                | ((uint32_t)p[1] << 16) 
+       *dst = ((uint32_t)p[0] << 24)
+                | ((uint32_t)p[1] << 16)
                 | ((uint32_t)p[2] << 8)
                 | ((uint32_t)p[3]);
 
@@ -115,9 +116,6 @@ readlong(char *packet, char **src, uint32_t *dst)
 int
 readdata(char *packet, char **src, char *dst, size_t len)
 {
-       if (len < 0)
-               return 0;
-
        memcpy(dst, *src, len);
 
        (*src) += len;
@@ -165,7 +163,7 @@ putname(char **buf, size_t buflen, const char *host)
        h = strdup(host);
        left = buflen;
        p = *buf;
-       
+
        word = strtok(h, ".");
        while(word) {
                if (strlen(word) > 63 || strlen(word) > left) {
@@ -232,11 +230,8 @@ putlong(char **dst, uint32_t value)
 int
 putdata(char **dst, char *data, size_t len)
 {
-       if (len < 0)
-               return 0;
-
        memcpy(*dst, data, len);
-       
+
        (*dst) += len;
        return len;
 }
index b33f3bb92bd896111039b3b6604cefc8b892a51a..2aac355b1422b3d758eb3c58f89337ef6c5a8d34 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -18,7 +19,7 @@
 #define _READ_H_
 
 int readname(char *, int, char **, char *, size_t);
-int readshort(char *, char **, short *);
+int readshort(char *, char **, unsigned short *);
 int readlong(char *, char **, uint32_t *);
 int readdata(char *, char **, char *, size_t);
 int readtxtbin(char *, char **, size_t, char *, size_t);
index 68028505f65688ab5f59f51910c7f0a6d1f69c5d..60eedd74f3ddb85d5065d25c69b7220320e5aada 100644 (file)
--- a/src/tun.c
+++ b/src/tun.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#ifndef IFCONFIGPATH
+#define IFCONFIGPATH "PATH=/sbin:/bin "
+#endif
+
 #ifdef WINDOWS32
-#include <winsock2.h>
-#include <winioctl.h>
 #include "windows.h"
+#include <winioctl.h>
 
-HANDLE dev_handle;
-struct tun_data data;
+static HANDLE dev_handle;
+static struct tun_data data;
 
 static void get_name(char *ifname, int namelen, char *dev_name);
 
@@ -47,8 +51,8 @@ static void get_name(char *ifname, int namelen, char *dev_name);
 #define NET_CFG_INST_ID "NetCfgInstanceId"
 #else
 #include <err.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #define TUN_MAX_TRY 50
 #endif
@@ -56,22 +60,25 @@ static void get_name(char *ifname, int namelen, char *dev_name);
 #include "tun.h"
 #include "common.h"
 
-char if_name[250];
+static char if_name[250];
 
-#ifndef WINDOWS32
 #ifdef LINUX
 
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <linux/if_tun.h>
 
-int 
-open_tun(const char *tun_device) 
+int
+open_tun(const char *tun_device)
 {
        int i;
        int tun_fd;
        struct ifreq ifreq;
+#ifdef ANDROID
+       char *tunnel = "/dev/tun";
+#else
        char *tunnel = "/dev/net/tun";
+#endif
 
        if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
                warn("open_tun: %s: %s", tunnel, strerror(errno));
@@ -80,7 +87,7 @@ open_tun(const char *tun_device)
 
        memset(&ifreq, 0, sizeof(ifreq));
 
-       ifreq.ifr_flags = IFF_TUN; 
+       ifreq.ifr_flags = IFF_TUN;
 
        if (tun_device != NULL) {
                strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
@@ -90,6 +97,7 @@ open_tun(const char *tun_device)
 
                if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
                        fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
+                       fd_set_close_on_exec(tun_fd);
                        return tun_fd;
                }
 
@@ -104,6 +112,7 @@ open_tun(const char *tun_device)
                        if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
                                fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
                                snprintf(if_name, sizeof(if_name), "dns%d", i);
+                               fd_set_close_on_exec(tun_fd);
                                return tun_fd;
                        }
 
@@ -119,49 +128,8 @@ open_tun(const char *tun_device)
        return -1;
 }
 
-#else /* BSD */
-
-int 
-open_tun(const char *tun_device) 
-{
-       int i;
-       int tun_fd;
-       char tun_name[50];
-
-       if (tun_device != NULL) {
-               snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
-               strncpy(if_name, tun_device, sizeof(if_name));
-               if_name[sizeof(if_name)-1] = '\0';
+#elif WINDOWS32
 
-               if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
-                       warn("open_tun: %s: %s", tun_name, strerror(errno));
-                       return -1;
-               }
-
-               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) {
-                               fprintf(stderr, "Opened %s\n", tun_name);
-                               snprintf(if_name, sizeof(if_name), "tun%d", i);
-                               return tun_fd;
-                       }
-
-                       if (errno == ENOENT)
-                               break;
-               }
-
-               warn("open_tun: Failed to open tunneling device");
-       }
-
-       return -1;
-}
-
-#endif /* !LINUX */
-#else /* WINDOWS32 */
 static void
 get_device(char *device, int device_len, const char *wanted_dev)
 {
@@ -176,7 +144,7 @@ get_device(char *device, int device_len, const char *wanted_dev)
                warnx("Error opening registry key " TAP_ADAPTER_KEY );
                return;
        }
-       
+
        while (TRUE) {
                char name[256];
                char unit[256];
@@ -214,7 +182,7 @@ get_device(char *device, int device_len, const char *wanted_dev)
                        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);
@@ -280,7 +248,7 @@ DWORD WINAPI tun_reader(LPVOID arg)
        OVERLAPPED olpd;
        int sock;
 
-       sock = open_dns(0, INADDR_ANY);
+       sock = open_dns_from_host("127.0.0.1", 0, AF_INET, 0);
 
        olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
@@ -291,21 +259,22 @@ DWORD WINAPI tun_reader(LPVOID arg)
                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));
+                       res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),
+                               tun->addrlen);
                }
        }
 
        return 0;
 }
 
-int 
-open_tun(const char *tun_device) 
+int
+open_tun(const char *tun_device)
 {
        char adapter[256];
        char tapfile[512];
        int tunfd;
-       in_addr_t local;
+       struct sockaddr_storage localsock;
+       int localsock_len;
 
        memset(adapter, 0, sizeof(adapter));
        memset(if_name, 0, sizeof(if_name));
@@ -319,7 +288,7 @@ open_tun(const char *tun_device)
                }
                return -1;
        }
-       
+
        fprintf(stderr, "Opening device %s\n", if_name);
        snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
        dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
@@ -330,34 +299,115 @@ open_tun(const char *tun_device)
 
        /* 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 
+        * 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);
+
+       localsock_len = get_addr("127.0.0.1", 55353, AF_INET, 0, &localsock);
+       tunfd = open_dns(&localsock, localsock_len);
 
        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;
+       memcpy(&(data.addr), &localsock, localsock_len);
+       data.addrlen = localsock_len;
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
-       
+
        return tunfd;
 }
-#endif 
 
-void 
-close_tun(int tun_fd) 
+#else /* BSD and friends */
+
+int
+open_tun(const char *tun_device)
+{
+       int i;
+       int tun_fd;
+       char tun_name[50];
+
+       if (tun_device != NULL) {
+               snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
+               strncpy(if_name, tun_device, sizeof(if_name));
+               if_name[sizeof(if_name)-1] = '\0';
+
+               if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
+                       warn("open_tun: %s: %s", tun_name, strerror(errno));
+                       return -1;
+               }
+
+               fprintf(stderr, "Opened %s\n", tun_name);
+               fd_set_close_on_exec(tun_fd);
+               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) {
+                               fprintf(stderr, "Opened %s\n", tun_name);
+                               snprintf(if_name, sizeof(if_name), "tun%d", i);
+                               fd_set_close_on_exec(tun_fd);
+                               return tun_fd;
+                       }
+
+                       if (errno == ENOENT)
+                               break;
+               }
+
+               warn("open_tun: Failed to open tunneling device");
+       }
+
+       return -1;
+}
+
+#endif
+
+void
+close_tun(int tun_fd)
 {
        if (tun_fd >= 0)
                close(tun_fd);
 }
 
-int 
-write_tun(int tun_fd, char *data, size_t len) 
+#ifdef WINDOWS32
+int
+write_tun(int tun_fd, char *data, size_t len)
+{
+       DWORD written;
+       DWORD res;
+       OVERLAPPED olpd;
+
+       data += 4;
+       len -= 4;
+
+       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;
+               }
+       }
+       return 0;
+}
+
+ssize_t
+read_tun(int tun_fd, char *buf, size_t len)
+{
+       int bytes;
+       memset(buf, 0, 4);
+
+       bytes = recv(tun_fd, buf + 4, len - 4, 0);
+       if (bytes < 0) {
+               return bytes;
+       } else {
+               return bytes + 4;
+       }
+}
+#else
+int
+write_tun(int tun_fd, char *data, size_t len)
 {
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
        data += 4;
        len -= 4;
 #else /* !FREEBSD/DARWIN */
@@ -374,47 +424,22 @@ 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) 
+read_tun(int tun_fd, char *buf, size_t len)
 {
-#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
+#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
        /* FreeBSD/Darwin/NetBSD has no header */
        int bytes;
        memset(buf, 0, 4);
-#ifdef WINDOWS32
-       /* Windows needs recv() since it is local UDP socket */
-       bytes = recv(tun_fd, buf + 4, len - 4, 0);
-#else
-       /* The other need read() because fd is not a socket */
+
        bytes = read(tun_fd, buf + 4, len - 4);
-#endif /*WINDOWS32*/
        if (bytes < 0) {
                return bytes;
        } else {
@@ -424,9 +449,10 @@ read_tun(int tun_fd, char *buf, size_t len)
        return read(tun_fd, buf, len);
 #endif /* !FREEBSD */
 }
+#endif
 
 int
-tun_setip(const char *ip, const char *remoteip, int netbits)
+tun_setip(const char *ip, const char *other_ip, int netbits)
 {
        char cmdline[512];
        int netmask;
@@ -440,6 +466,11 @@ tun_setip(const char *ip, const char *remoteip, int netbits)
        DWORD ipdata[3];
        struct in_addr addr;
        DWORD len;
+#else
+       const char *display_ip;
+#ifndef LINUX
+       struct in_addr netip;
+#endif
 #endif
 
        netmask = 0;
@@ -454,28 +485,32 @@ tun_setip(const char *ip, const char *remoteip, int netbits)
                return 1;
        }
 #ifndef WINDOWS32
-       snprintf(cmdline, sizeof(cmdline), 
-                       "/sbin/ifconfig %s %s %s netmask %s",
+# ifdef FREEBSD
+       display_ip = other_ip; /* FreeBSD wants other IP as second IP */
+# else
+       display_ip = ip;
+# endif
+       snprintf(cmdline, sizeof(cmdline),
+                       IFCONFIGPATH "ifconfig %s %s %s netmask %s",
                        if_name,
                        ip,
-#ifdef FREEBSD
-                       remoteip, /* FreeBSD wants other IP as second IP */
-#else
-                       ip,
-#endif
+                       display_ip,
                        inet_ntoa(net));
-       
+
        fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
 #ifndef LINUX
+       netip.s_addr = inet_addr(ip);
+       netip.s_addr = netip.s_addr & net.s_addr;
        r = system(cmdline);
        if(r != 0) {
                return r;
        } else {
+
                snprintf(cmdline, sizeof(cmdline),
                                "/sbin/route add %s/%d %s",
-                               ip, netbits, ip);
+                               inet_ntoa(netip), netbits, ip);
        }
-       fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip);
+       fprintf(stderr, "Adding route %s/%d to %s\n", inet_ntoa(netip), netbits, ip);
 #endif
        return system(cmdline);
 #else /* WINDOWS32 */
@@ -483,13 +518,13 @@ tun_setip(const char *ip, const char *remoteip, int netbits)
        /* Set device as connected */
        fprintf(stderr, "Enabling interface '%s'\n", if_name);
        status = 1;
-       r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, 
+       r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,
                sizeof(status), &status, sizeof(status), &len, NULL);
        if (!r) {
                fprintf(stderr, "Failed to enable interface\n");
                return -1;
        }
-       
+
        if (inet_aton(ip, &addr)) {
                ipdata[0] = (DWORD) addr.s_addr;   /* local ip addr */
                ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
@@ -499,7 +534,7 @@ tun_setip(const char *ip, const char *remoteip, int netbits)
        }
 
        /* Tell ip/networkaddr/netmask to device for arp use */
-       r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata, 
+       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");
@@ -514,18 +549,18 @@ tun_setip(const char *ip, const char *remoteip, int netbits)
 #endif
 }
 
-int 
+int
 tun_setmtu(const unsigned mtu)
 {
 #ifndef WINDOWS32
        char cmdline[512];
 
        if (mtu > 200 && mtu <= 1500) {
-               snprintf(cmdline, sizeof(cmdline), 
-                               "/sbin/ifconfig %s mtu %u",
+               snprintf(cmdline, sizeof(cmdline),
+                               IFCONFIGPATH "ifconfig %s mtu %u",
                                if_name,
                                mtu);
-               
+
                fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu);
                return system(cmdline);
        } else {
index 89ffcfacb7e5f979a721541727536697f4524a3a..230484c4cdec5938fcb41f5dc988ee25aac3041f 100644 (file)
--- a/src/tun.h
+++ b/src/tun.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index dfe9c3658143329d95726b33a970e7c75e04d422..0dc95db7fcc1be6ffc5a1b3eed319bcbfd9eaf1e 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -33,7 +34,8 @@
 #include "encoding.h"
 #include "user.h"
 
-struct user users[USERS];
+struct tun_user *users;
+unsigned usercount;
 
 int
 init_users(in_addr_t my_ip, int netbits)
@@ -41,7 +43,6 @@ init_users(in_addr_t my_ip, int netbits)
        int i;
        int skip = 0;
        char newip[16];
-       int created_users = 0;
 
        int maxusers;
 
@@ -57,9 +58,10 @@ init_users(in_addr_t my_ip, int netbits)
        ipstart.s_addr = my_ip & net.s_addr;
 
        maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */
-       
-       memset(users, 0, USERS * sizeof(struct user));
-       for (i = 0; i < USERS; i++) {
+       usercount = MIN(maxusers, USERS);
+
+       users = calloc(usercount, sizeof(struct tun_user));
+       for (i = 0; i < usercount; i++) {
                in_addr_t ip;
                users[i].id = i;
                snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
@@ -72,17 +74,14 @@ init_users(in_addr_t my_ip, int netbits)
                }
                users[i].tun_ip = ip;
                net.s_addr = ip;
-               if (maxusers--  < 1) {
-                       users[i].disabled = 1;
-               } else {
-                       users[i].disabled = 0;
-                       created_users++;
-               }
+               users[i].disabled = 0;
+               users[i].authenticated = 0;
+               users[i].authenticated_raw = 0;
                users[i].active = 0;
                /* Rest is reset on login ('V' packet) */
        }
 
-       return created_users;
+       return usercount;
 }
 
 const char*
@@ -90,7 +89,7 @@ users_get_first_ip()
 {
        struct in_addr ip;
        ip.s_addr = users[0].tun_ip;
-       return inet_ntoa(ip);
+       return strdup(inet_ntoa(ip));
 }
 
 int
@@ -100,14 +99,14 @@ users_waiting_on_reply()
        int i;
 
        ret = 0;
-       for (i = 0; i < USERS; i++) {
-               if (users[i].active && !users[i].disabled && 
+       for (i = 0; i < usercount; i++) {
+               if (users[i].active && !users[i].disabled &&
                        users[i].last_pkt + 60 > time(NULL) &&
                        users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) {
                        ret++;
                }
        }
-       
+
        return ret;
 }
 
@@ -118,8 +117,10 @@ find_user_by_ip(uint32_t ip)
        int i;
 
        ret = -1;
-       for (i = 0; i < USERS; i++) {
-               if (users[i].active && !users[i].disabled &&
+       for (i = 0; i < usercount; i++) {
+               if (users[i].active &&
+                       users[i].authenticated &&
+                       !users[i].disabled &&
                        users[i].last_pkt + 60 > time(NULL) &&
                        ip == users[i].tun_ip) {
                        ret = i;
@@ -143,11 +144,11 @@ all_users_waiting_to_send()
 
        ret = 1;
        now = time(NULL);
-       for (i = 0; i < USERS; i++) {
+       for (i = 0; i < usercount; i++) {
                if (users[i].active && !users[i].disabled &&
                        users[i].last_pkt + 60 > now &&
-                       ((users[i].conn == CONN_RAW_UDP) || 
-                       ((users[i].conn == CONN_DNS_NULL) 
+                       ((users[i].conn == CONN_RAW_UDP) ||
+                       ((users[i].conn == CONN_DNS_NULL)
 #ifdef OUTPACKETQ_LEN
                                && users[i].outpacketq_filled < 1
 #else
@@ -167,10 +168,12 @@ find_available_user()
 {
        int ret = -1;
        int i;
-       for (i = 0; i < USERS; i++) {
+       for (i = 0; i < usercount; i++) {
                /* Not used at all or not used in one minute */
                if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {
                        users[i].active = 1;
+                       users[i].authenticated = 0;
+                       users[i].authenticated_raw = 0;
                        users[i].last_pkt = time(NULL);
                        users[i].fragsize = 4096;
                        users[i].conn = CONN_DNS_NULL;
@@ -184,21 +187,21 @@ find_available_user()
 void
 user_switch_codec(int userid, struct encoder *enc)
 {
-       if (userid < 0 || userid >= USERS)
+       if (userid < 0 || userid >= usercount)
                return;
-       
+
        users[userid].encoder = enc;
 }
 
 void
 user_set_conn_type(int userid, enum connection c)
 {
-       if (userid < 0 || userid >= USERS)
+       if (userid < 0 || userid >= usercount)
                return;
 
        if (c < 0 || c >= CONN_MAX)
                return;
-       
+
        users[userid].conn = c;
 }
-       
+
index 51a6092c2dbba29c02310cdaee06ba015af2ce07..76fc54be855e797ed45609fb59e47a87c3f185f9 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #define QMEMDATA_LEN 15
 /* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */
 
-struct user {
+struct tun_user {
        char id;
        int active;
+       int authenticated;
+       int authenticated_raw;
        int disabled;
        time_t last_pkt;
        int seed;
@@ -73,7 +76,7 @@ struct user {
 #endif
 };
 
-extern struct user users[USERS];
+extern struct tun_user *users;
 
 int init_users(in_addr_t, int);
 const char* users_get_first_ip();
index bc5fc8d8d9baa2b6518c75b14ff9741271e8a210..f4a538e73a6bc1d8a22372e64bd1aec999b49f5a 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -25,12 +26,22 @@ get_resolvconf_addr()
 #ifndef WINDOWS32
        char buf[80];
        FILE *fp;
-       
+#ifdef ANDROID
+       fp = popen("getprop net.dns1", "r");
+       if (fp == NULL)
+               err(1, "getprop net.dns1 failed");
+       if (fgets(buf, sizeof(buf), fp) == NULL)
+               err(1, "read getprop net.dns1 failed");
+       if (sscanf(buf, "%15s", addr) == 1)
+               rv = addr;
+       pclose(fp);
+#else
+
        rv = NULL;
 
-       if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) 
+       if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
                err(1, "/etc/resolv.conf");
-       
+
        while (feof(fp) == 0) {
                fgets(buf, sizeof(buf), fp);
 
@@ -39,8 +50,9 @@ get_resolvconf_addr()
                        break;
                }
        }
-       
+
        fclose(fp);
+#endif
 #else /* !WINDOWS32 */
        FIXED_INFO  *fixed_info;
        ULONG       buflen;
@@ -67,3 +79,15 @@ get_resolvconf_addr()
        return rv;
 }
 
+#ifdef OPENBSD
+void
+socket_setrtable(int fd, int rtable)
+{
+#ifdef SO_RTABLE
+       if (setsockopt (fd, IPPROTO_IP, SO_RTABLE, &rtable, sizeof(rtable)) == -1)
+               err(1, "Failed to set routing table %d", rtable);
+#else
+       fprintf(stderr, "Routing domain support was not available at compile time.\n");
+#endif
+}
+#endif
index f514139ef8b08a88c44b9d373a26de091f2ac5d0..68720773cc436cc70af0a27cdd4d7ff2ad3e4f2d 100644 (file)
@@ -2,5 +2,6 @@
 #define __UTIL_H__
 
 char *get_resolvconf_addr();
+void socket_setrtable(int fd, int rtable);
 
 #endif
index 1561b9ec675df8e65e49e9ec63e33f3c513b81a5..2ab00ff5114f7f89ae197cb7f49f3d2d63009f33 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 7e0e16cd1a84229a3389fd621ba983b6b99b0597..c665a60ce0c8ae38e19948528360b320b205fa05 100644 (file)
@@ -1,5 +1,6 @@
 /*\r
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>\r
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\r
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>\r
  *\r
  * Permission to use, copy, modify, and distribute this software for any\r
  * purpose with or without fee is hereby granted, provided that the above\r
@@ -19,9 +20,9 @@
 \r
 typedef unsigned int in_addr_t;\r
 \r
+#include <winsock2.h>\r
 #include <windows.h>\r
 #include <windns.h>\r
-#include <winsock2.h>\r
 #include <ws2tcpip.h>\r
 #include <iphlpapi.h>\r
 \r
@@ -94,7 +95,8 @@ DWORD WINAPI tun_reader(LPVOID arg);
 struct tun_data {\r
        HANDLE tun;\r
        int sock;\r
-       struct sockaddr_in addr;\r
+       struct sockaddr_storage addr;\r
+       int addrlen;\r
 };\r
 \r
 #endif\r
index 3a7ac01ef7fcf6cdd0272a93f4c4b5723cd5f610..03eed98b114c94bd5c31a6858cba497afd9f6f41 100644 (file)
@@ -1,26 +1,24 @@
-CC = gcc
 TEST = test
-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
+OBJS = test.o base32.o base64.o common.o read.o dns.o encoding.o login.o user.o fw_query.o
+SRCOBJS = ../src/base32.o  ../src/base64.o ../src/common.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"`
 
 CHECK_PATH = /usr/local
-LDFLAGS = -L$(CHECK_PATH)/lib -lcheck `../src/osflags link`
-CFLAGS = -g -Wall -D$(OS) -I../src -I$(CHECK_PATH)/include -pedantic `../src/osflags cflags`
+LDFLAGS = -L$(CHECK_PATH)/lib `pkg-config check --libs` -lpthread `sh ../src/osflags $(TARGETOS) link`
+CFLAGS = -std=c99 -g -Wall -D$(OS) `pkg-config check --cflags` -I../src -I$(CHECK_PATH)/include -pedantic `sh ../src/osflags $(TARGETOS) cflags`
 
 all: $(TEST)
        @LD_LIBRARY_PATH=${CHECK_PATH}/lib ./$(TEST)
 
 $(TEST): $(OBJS) $(SRCOBJS)
        @echo LD $(TEST)
-       @$(CC) -o $@ $(SRCOBJS) $(OBJS) $(LDFLAGS) 
+       @$(CC) -o $@ $(SRCOBJS) $(OBJS) $(LDFLAGS)
 
-.c.o: 
+.c.o:
        @echo CC $<
        @$(CC) $(CFLAGS) -c $<
 
-
 clean:
        @echo "Cleaning tests/"
        @rm -f *~ *.core $(TEST) $(OBJS)
index 9ff0cf74ce0cf57cbfe529f246f8feca2d029ce1..419253f435037e2759c318217d3f086053fd695b 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -50,6 +51,7 @@ START_TEST(test_base32_encode)
        len = sizeof(buf);
        val = b32->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
 
+       fail_unless(val == strlen(testpairs[_i].b));
        fail_unless(strcmp(buf, testpairs[_i].b) == 0,
                        "'%s' != '%s'", buf, testpairs[_i].b);
 }
@@ -61,13 +63,13 @@ START_TEST(test_base32_decode)
        char buf[4096];
        struct encoder *b32;
        int val;
-       
+
        b32 = get_base32_encoder();
 
        len = sizeof(buf);
        val = b32->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
 
-       fail_unless(buf != NULL, "buf == NULL");
+       fail_unless(val == strlen(testpairs[_i].a));
        fail_unless(strcmp(buf, testpairs[_i].a) == 0,
                        "'%s' != '%s'", buf, testpairs[_i].a);
 }
@@ -79,7 +81,7 @@ START_TEST(test_base32_5to8_8to5)
        int c;
 
        for (i = 0; i < 32; i++) {
-               c = b32_5to8(i);        
+               c = b32_5to8(i);
                fail_unless(b32_8to5(c) == i);
        }
 }
index bd0e9ce5c7b4890708b43d6c6b92becf0d813f69..cd96d21c21d5495fd07c3a442b832ead963c9995 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -76,6 +77,7 @@ START_TEST(test_base64_encode)
        len = sizeof(buf);
        val = b64->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
 
+       fail_unless(val == strlen(testpairs[_i].b));
        fail_unless(strcmp(buf, testpairs[_i].b) == 0,
                        "'%s' != '%s'", buf, testpairs[_i].b);
 }
@@ -93,7 +95,7 @@ START_TEST(test_base64_decode)
        len = sizeof(buf);
        val = b64->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
 
-       fail_unless(buf != NULL, "buf == NULL");
+       fail_unless(val == strlen(testpairs[_i].a));
        fail_unless(strcmp(buf, testpairs[_i].a) == 0,
                        "'%s' != '%s'", buf, testpairs[_i].a);
 }
diff --git a/tests/common.c b/tests/common.c
new file mode 100644 (file)
index 0000000..c1bc73f
--- /dev/null
@@ -0,0 +1,203 @@
+#include <check.h>
+#include <common.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+START_TEST(test_topdomain_ok)
+{
+       char *error;
+
+       fail_if(check_topdomain("foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error));
+
+       /* Not allowed to start with dot */
+       fail_unless(check_topdomain(".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com", &error));
+       fail_if(strcmp("Starts with a dot", error));
+
+       /* Test missing error msg ptr */
+       fail_unless(check_topdomain(".foo", NULL));
+}
+END_TEST
+
+START_TEST(test_topdomain_length)
+{
+       char *error;
+
+       /* Test empty and too short */
+       fail_unless(check_topdomain("", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+       fail_unless(check_topdomain("a", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+       fail_unless(check_topdomain(".a", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+       fail_unless(check_topdomain("a.", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+       fail_unless(check_topdomain("ab", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+       fail_if(check_topdomain("a.b", &error));
+       fail_if(strcmp("Too short (< 3)", error));
+
+       /* Test too long (over 128, need rest of space for data) */
+       fail_unless(check_topdomain(
+               "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345."
+               "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345."
+               "abcd12345.abcd12345.foo129xxx", &error));
+       fail_if(strcmp("Too long (> 128)", error));
+       fail_if(check_topdomain(
+               "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345."
+               "abcd12345.abcd12345.abcd12345.abcd12345.abcd12345."
+               "abcd12345.abcd12345.foo128xx", &error));
+}
+END_TEST
+
+START_TEST(test_topdomain_chunks)
+{
+       char *error;
+
+       /* Must have at least one dot */
+       fail_if(check_topdomain("abcde.gh", &error));
+       fail_unless(check_topdomain("abcdefgh", &error));
+       fail_if(strcmp("No dots", error));
+
+       /* Not two consecutive dots */
+       fail_unless(check_topdomain("abc..defgh", &error));
+       fail_if(strcmp("Consecutive dots", error));
+
+       /* Not end with a dots */
+       fail_unless(check_topdomain("abc.defgh.", &error));
+       fail_if(strcmp("Ends with a dot", error));
+
+       /* No chunk longer than 63 chars */
+       fail_if(check_topdomain("123456789012345678901234567890"
+               "123456789012345678901234567890333.com", &error));
+       fail_unless(check_topdomain("123456789012345678901234567890"
+               "1234567890123456789012345678904444.com", &error));
+       fail_if(strcmp("Too long domain part (> 63)", error));
+
+       fail_if(check_topdomain("abc.123456789012345678901234567890"
+               "123456789012345678901234567890333.com", &error));
+       fail_unless(check_topdomain("abc.123456789012345678901234567890"
+               "1234567890123456789012345678904444.com", &error));
+       fail_if(strcmp("Too long domain part (> 63)", error));
+
+       fail_if(check_topdomain("abc.123456789012345678901234567890"
+               "123456789012345678901234567890333", &error));
+       fail_unless(check_topdomain("abc.123456789012345678901234567890"
+               "1234567890123456789012345678904444", &error));
+       fail_if(strcmp("Too long domain part (> 63)", error));
+}
+END_TEST
+
+START_TEST(test_parse_format_ipv4)
+{
+       char *host = "192.168.2.10";
+       char *formatted;
+       struct sockaddr_storage addr;
+       struct sockaddr_in *v4addr;
+       int addr_len;
+
+       addr_len = get_addr(host, 53, AF_INET, 0, &addr);
+       fail_unless(addr_len == sizeof(struct sockaddr_in));
+
+       v4addr = (struct sockaddr_in *) &addr;
+       fail_unless(v4addr->sin_addr.s_addr == htonl(0xc0a8020a));
+       fail_unless(v4addr->sin_port == htons(53));
+
+       formatted = format_addr(&addr, addr_len);
+       fail_if(strcmp(host, formatted));
+}
+END_TEST
+
+START_TEST(test_parse_format_ipv4_listen_all)
+{
+       char *host = "0.0.0.0";
+       char *formatted;
+       struct sockaddr_storage addr;
+       struct sockaddr_in *v4addr;
+       int addr_len;
+
+       addr_len = get_addr(NULL, 53, AF_INET, AI_PASSIVE, &addr);
+       fail_unless(addr_len == sizeof(struct sockaddr_in));
+
+       v4addr = (struct sockaddr_in *) &addr;
+       fail_unless(v4addr->sin_addr.s_addr == htonl(0x00000000));
+       fail_unless(v4addr->sin_port == htons(53));
+
+       formatted = format_addr(&addr, addr_len);
+       fail_if(strcmp(host, formatted));
+}
+END_TEST
+
+START_TEST(test_parse_format_ipv6)
+{
+       char *host = "2001:0db8:0505:0::123:0abc";
+       char *compact = "2001:db8:505::123:abc";
+       unsigned char v6_bits[] = {
+               0x20, 0x01, 0x0d, 0xb8, 0x05, 0x05, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x0a, 0xbc,
+       };
+       char *formatted;
+       struct sockaddr_storage addr;
+       struct sockaddr_in6 *v6addr;
+       int addr_len;
+
+       addr_len = get_addr(host, 53, AF_UNSPEC, 0, &addr);
+       fail_unless(addr_len == sizeof(struct sockaddr_in6));
+
+       v6addr = (struct sockaddr_in6 *) &addr;
+       fail_if(memcmp(&v6addr->sin6_addr, v6_bits, sizeof(v6_bits)));
+       fail_unless(v6addr->sin6_port == htons(53));
+
+       formatted = format_addr(&addr, addr_len);
+       fail_if(strcmp(compact, formatted));
+}
+END_TEST
+
+START_TEST(test_parse_format_ipv4_mapped_ipv6)
+{
+       char *v4mapped = "::FFFF:192.168.2.10";
+       char *host = "192.168.2.10";
+       unsigned char v6_bits[] = {
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x02, 0x0a,
+       };
+       char *formatted;
+       struct sockaddr_storage addr;
+       struct sockaddr_in6 *v6addr;
+       int addr_len;
+
+       addr_len = get_addr(v4mapped, 53, AF_INET6, 0, &addr);
+       fail_unless(addr_len == sizeof(struct sockaddr_in6));
+
+       v6addr = (struct sockaddr_in6 *) &addr;
+       fail_if(memcmp(&v6addr->sin6_addr, v6_bits, sizeof(v6_bits)));
+       fail_unless(v6addr->sin6_port == htons(53));
+
+       /* Format as IPv4 address */
+       formatted = format_addr(&addr, addr_len);
+       fail_if(strcmp(host, formatted));
+}
+END_TEST
+
+TCase *
+test_common_create_tests()
+{
+       TCase *tc;
+       int sock;
+
+       tc = tcase_create("Common");
+       tcase_add_test(tc, test_topdomain_ok);
+       tcase_add_test(tc, test_topdomain_length);
+       tcase_add_test(tc, test_topdomain_chunks);
+       tcase_add_test(tc, test_parse_format_ipv4);
+       tcase_add_test(tc, test_parse_format_ipv4_listen_all);
+
+       /* Tests require IPv6 support */
+       sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+       if (sock >= 0) {
+               close(sock);
+               tcase_add_test(tc, test_parse_format_ipv6);
+               tcase_add_test(tc, test_parse_format_ipv4_mapped_ipv6);
+       }
+       return tc;
+}
index 3d21e4c1cb6d57372615d940d56a287f09fdc155..cdd3378fb7842d0618fd024936c76e3d9f2ff6d5 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
 #include <netinet/in.h>
 #include <sys/stat.h>
 #include <arpa/nameser.h>
+#ifdef DARWIN
+#define BIND_8_COMPAT
+#include <arpa/nameser_compat.h>
+#endif
 
 #include "common.h"
 #include "dns.h"
@@ -159,8 +164,8 @@ START_TEST(test_decode_response)
        memset(&buf, 0, sizeof(buf));
 
        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(strncmp(msgData, buf, strlen(msgData)) == 0, "Did not extract expected data");
        fail_unless(q.id == 0x0539);
 }
 END_TEST
@@ -176,8 +181,8 @@ START_TEST(test_decode_response_with_high_trans_id)
        memset(&buf, 0, sizeof(buf));
 
        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(strncmp(msgData, buf, strlen(msgData)) == 0, "Did not extract expected data");
        fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539);
 }
 END_TEST
index ac224521e193b20addfa687a9145544cc7951b78..665c4dd18d38ec5a75019bfeaf92c003fb3d033f 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -84,7 +85,7 @@ START_TEST(test_build_hostname)
        }
 
        buflen = sizeof(buf);
-       
+
        for (i = 1; i < sizeof(data); i++) {
                int len = build_hostname(buf, buflen, data, i, topdomain, get_base32_encoder(), sizeof(buf));
 
index 6d2392479e05fb887b92d2e675a749436c86006e..c6ed2c79c0a908122603c0de0963b772d94f01fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2009 Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2009-2014 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
@@ -28,7 +28,7 @@ START_TEST(test_fw_query_simple)
        q.id = 0x848A;
 
        fw_query_init();
-       
+
        /* Test empty cache */
        fw_query_get(0x848A, &qp);
        fail_unless(qp == NULL);
@@ -49,7 +49,7 @@ START_TEST(test_fw_query_edge)
        int i;
 
        fw_query_init();
-       
+
        q.addrlen = 33;
        q.id = 0x848A;
        fw_query_put(&q);
@@ -64,7 +64,7 @@ START_TEST(test_fw_query_edge)
        fw_query_get(0x848A, &qp);
        fail_unless(qp->addrlen == 33);
        fail_unless(qp->id == 0x848A);
-               
+
        q.addrlen++;
        q.id++;
        fw_query_put(&q);
index 1ef23f4c6a17ed12d953719b98ddf65532aa86f8..e154ee21bb6d2325fa2e1c9ebf062d7a9c9b10c7 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
index 18cc29ce9b4ce9fe3fe253dfab88e620da755903..24a5214149776ddb9674bc596f390ef7175aef84 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -20,7 +21,8 @@
 #include <sys/stat.h>
 #include <arpa/nameser.h>
 #ifdef DARWIN
-#include <arpa/nameser8_compat.h>
+#define BIND_8_COMPAT
+#include <arpa/nameser_compat.h>
 #endif
 #include <stdio.h>
 #include <stdint.h>
@@ -49,7 +51,7 @@ START_TEST(test_read_putshort)
                                        i, ntohs(k), i);
 
                p = (char*)&k;
-               readshort(NULL, &p, (short *) &l);
+               readshort(NULL, &p, &l);
                fail_unless(l == i,
                                "Bad value on readshort for %d: %d != %d",
                                        i, l, i);
@@ -96,6 +98,7 @@ START_TEST(test_read_name_empty_loop)
        data = (char*) emptyloop + sizeof(HEADER);
        buf[1023] = 'A';
        rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
+       fail_unless(rv == 0);
        fail_unless(buf[1023] == 'A');
 }
 END_TEST
@@ -113,6 +116,7 @@ START_TEST(test_read_name_inf_loop)
        data = (char*) infloop + sizeof(HEADER);
        buf[4] = '\a';
        rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
+       fail_unless(rv == 3);
        fail_unless(buf[4] == '\a');
 }
 END_TEST
@@ -136,6 +140,7 @@ START_TEST(test_read_name_longname)
        data = (char*) longname + sizeof(HEADER);
        buf[256] = '\a';
        rv = readname((char*) longname, sizeof(longname), &data, buf, 256);
+       fail_unless(rv == 256);
        fail_unless(buf[256] == '\a');
 }
 END_TEST
@@ -213,11 +218,8 @@ START_TEST(test_putname)
        char buf[256];
        char *domain = "BADGER.BADGER.KRYO.SE";
        char *b;
-       int len;
        int ret;
 
-       len = 256;
-
        memset(buf, 0, 256);
        b = buf;
        ret = putname(&b, 256, domain);
@@ -234,11 +236,8 @@ START_TEST(test_putname_nodot)
                "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
        char *b;
-       int len;
        int ret;
 
-       len = 256;
-
        memset(buf, 0, 256);
        b = buf;
        ret = putname(&b, 256, nodot);
@@ -259,11 +258,8 @@ START_TEST(test_putname_toolong)
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.";
        char *b;
-       int len;
        int ret;
 
-       len = 256;
-
        memset(buf, 0, 256);
        b = buf;
        ret = putname(&b, 256, toolong);
index 5bee9d23be8879f4f898f5084758d14c99d87336..cc753d44b00e339b4f715516f43a60dc7a6e5f14 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -38,6 +39,9 @@ main()
        test = test_base64_create_tests();
        suite_add_tcase(iodine, test);
 
+       test = test_common_create_tests();
+       suite_add_tcase(iodine, test);
+
        test = test_dns_create_tests();
        suite_add_tcase(iodine, test);
 
index 1022a9ea1159b44754682c8a39334c12d050d59f..511cf3121170c830b8182bcd3b708813be012d7d 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -19,6 +20,7 @@
 
 TCase *test_base32_create_tests();
 TCase *test_base64_create_tests();
+TCase *test_common_create_tests();
 TCase *test_dns_create_tests();
 TCase *test_encoding_create_tests();
 TCase *test_read_create_tests();
@@ -27,11 +29,11 @@ TCase *test_user_create_tests();
 TCase *test_fw_query_create_tests();
 
 char *va_str(const char *, ...);
-       
+
 #if (CHECK_MAJOR_VERSION == 0 && \
        ((CHECK_MINOR_VERSION == 9 && CHECK_MICRO_VERSION < 2) || \
         (CHECK_MINOR_VERSION < 9)))
-#define tcase_set_timeout(...) 
+#define tcase_set_timeout(...)
 #endif
 
 #endif
index afd61cac3a5c7dda1eaafe9f75dfc75a235214bf..2e4f36d44c752dc796bfae7c2ed557146788f2bd 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@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
@@ -19,8 +20,8 @@
 #include <string.h>
 #include <time.h>
 #include <sys/socket.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "common.h"
 #include "encoding.h"
@@ -32,10 +33,11 @@ START_TEST(test_init_users)
        in_addr_t ip;
        char givenip[16];
        int i;
+       int count;
 
        ip = inet_addr("127.0.0.1");
-       init_users(ip, 27);
-       for (i = 0; i < USERS; i++) {
+       count = init_users(ip, 27);
+       for (i = 0; i < count; i++) {
                fail_unless(users[i].id == i);
                fail_unless(users[i].q.id == 0);
                fail_unless(users[i].inpacket.len == 0);
@@ -60,12 +62,12 @@ START_TEST(test_users_waiting)
        fail_unless(users_waiting_on_reply() == 0);
 
        users[3].last_pkt = time(NULL);
-       
+
        fail_unless(users_waiting_on_reply() == 0);
-       
+
        users[3].conn = CONN_DNS_NULL;
        users[3].q.id = 1;
-       
+
        fail_unless(users_waiting_on_reply() == 1);
 }
 END_TEST
@@ -81,17 +83,22 @@ START_TEST(test_find_user_by_ip)
 
        testip = (unsigned int) inet_addr("10.0.0.1");
        fail_unless(find_user_by_ip(testip) == -1);
-       
+
        testip = (unsigned int) inet_addr("127.0.0.2");
        fail_unless(find_user_by_ip(testip) == -1);
-       
+
        users[0].active = 1;
-       
+
        testip = (unsigned int) inet_addr("127.0.0.2");
        fail_unless(find_user_by_ip(testip) == -1);
-       
+
        users[0].last_pkt = time(NULL);
-       
+
+       testip = (unsigned int) inet_addr("127.0.0.2");
+       fail_unless(find_user_by_ip(testip) == -1);
+
+       users[0].authenticated = 1;
+
        testip = (unsigned int) inet_addr("127.0.0.2");
        fail_unless(find_user_by_ip(testip) == 0);
 }
@@ -105,15 +112,15 @@ START_TEST(test_all_users_waiting_to_send)
        init_users(ip, 27);
 
        fail_unless(all_users_waiting_to_send() == 1);
-       
+
        users[0].conn = CONN_DNS_NULL;
        users[0].active = 1;
-       
+
        fail_unless(all_users_waiting_to_send() == 1);
-       
+
        users[0].last_pkt = time(NULL);
        users[0].outpacket.len = 0;
-       
+
        fail_unless(all_users_waiting_to_send() == 0);
 
 #ifdef OUTPACKETQ_LEN
@@ -121,7 +128,7 @@ START_TEST(test_all_users_waiting_to_send)
 #else
        users[0].outpacket.len = 44;
 #endif
-       
+
        fail_unless(all_users_waiting_to_send() == 1);
 }
 END_TEST
@@ -135,7 +142,11 @@ START_TEST(test_find_available_user)
        init_users(ip, 27);
 
        for (i = 0; i < USERS; i++) {
+               users[i].authenticated = 1;
+               users[i].authenticated_raw = 1;
                fail_unless(find_available_user() == i);
+               fail_if(users[i].authenticated);
+               fail_if(users[i].authenticated_raw);
        }
 
        for (i = 0; i < USERS; i++) {
@@ -148,7 +159,7 @@ START_TEST(test_find_available_user)
        fail_unless(find_available_user() == -1);
 
        users[3].last_pkt = 55;
-       
+
        fail_unless(find_available_user() == 3);
        fail_unless(find_available_user() == -1);
 }
@@ -176,7 +187,7 @@ START_TEST(test_find_available_user_small_net)
        fail_unless(find_available_user() == -1);
 
        users[3].last_pkt = 55;
-       
+
        fail_unless(find_available_user() == 3);
        fail_unless(find_available_user() == -1);
 }