From 5d8801d4687035ae45143f0f3bc3eeaf75dc17ec Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Mon, 11 Aug 2014 23:26:36 +0200 Subject: Upgrade code to iodine 0.7.0 and improve logging --- jni/Android.mk | 11 - jni/iodine-client.c | 12 +- jni/iodine/CHANGELOG | 26 +- jni/iodine/Makefile | 80 +++-- jni/iodine/README | 50 ++- jni/iodine/README-android.txt | 45 +++ jni/iodine/README-win32.txt | 3 + jni/iodine/doc/iodine-server.service | 11 + jni/iodine/doc/iodine-server.socket | 8 + jni/iodine/doc/proto_00000502.txt | 7 +- jni/iodine/man/iodine.8 | 54 ++- jni/iodine/src/Android.mk | 22 ++ jni/iodine/src/Makefile | 5 +- jni/iodine/src/android_dns.h | 39 +++ jni/iodine/src/base128.c | 12 +- jni/iodine/src/base32.c | 21 +- jni/iodine/src/base32.h | 3 +- jni/iodine/src/base64.c | 15 +- jni/iodine/src/base64.h | 3 +- jni/iodine/src/client.c | 463 ++++++++++++-------------- jni/iodine/src/client.h | 11 +- jni/iodine/src/common.c | 262 +++++++++++---- jni/iodine/src/common.h | 53 +-- jni/iodine/src/dns.c | 86 ++--- jni/iodine/src/dns.h | 7 +- jni/iodine/src/dns_android.h | 625 ----------------------------------- jni/iodine/src/encoding.c | 22 +- jni/iodine/src/encoding.h | 3 +- jni/iodine/src/fw_query.c | 6 +- jni/iodine/src/fw_query.h | 4 +- jni/iodine/src/iodine.c | 106 ++++-- jni/iodine/src/iodined.c | 477 ++++++++++++++++---------- jni/iodine/src/login.c | 14 +- jni/iodine/src/login.h | 3 +- jni/iodine/src/md5.h | 2 +- jni/iodine/src/osflags | 13 +- jni/iodine/src/read.c | 25 +- jni/iodine/src/read.h | 5 +- jni/iodine/src/tun.c | 285 +++++++++------- jni/iodine/src/tun.h | 3 +- jni/iodine/src/user.c | 59 ++-- jni/iodine/src/user.h | 9 +- jni/iodine/src/util.c | 34 +- jni/iodine/src/util.h | 1 + jni/iodine/src/version.h | 3 +- jni/iodine/src/windows.h | 8 +- jni/iodine/tests/Makefile | 14 +- jni/iodine/tests/base32.c | 10 +- jni/iodine/tests/base64.c | 6 +- jni/iodine/tests/common.c | 203 ++++++++++++ jni/iodine/tests/dns.c | 11 +- jni/iodine/tests/encoding.c | 5 +- jni/iodine/tests/fw_query.c | 8 +- jni/iodine/tests/login.c | 3 +- jni/iodine/tests/read.c | 20 +- jni/iodine/tests/test.c | 6 +- jni/iodine/tests/test.h | 8 +- jni/iodine/tests/user.c | 49 +-- 58 files changed, 1763 insertions(+), 1596 deletions(-) create mode 100644 jni/iodine/README-android.txt create mode 100644 jni/iodine/doc/iodine-server.service create mode 100644 jni/iodine/doc/iodine-server.socket create mode 100644 jni/iodine/src/Android.mk create mode 100644 jni/iodine/src/android_dns.h delete mode 100644 jni/iodine/src/dns_android.h create mode 100644 jni/iodine/tests/common.c (limited to 'jni') diff --git a/jni/Android.mk b/jni/Android.mk index fcb4b00..6b25558 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -34,15 +34,4 @@ LOCAL_SRC_FILES := iodine-client.c \ iodine/src/client.c \ iodine/src/util.c -$(LOCAL_PATH)/iodine/src/base64u.c: $(LOCAL_PATH)/iodine/src/base64.c $(LOCAL_PATH)/iodine/src/base64u.h - @echo Making $@ - @echo '/* No use in editing, produced by Makefile! */' > $@ - @sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < $< >> $@ - -$(LOCAL_PATH)/iodine/src/base64u.h: $(LOCAL_PATH)/iodine/src/base64.h - @echo Making $@ - @echo '/* No use in editing, produced by Makefile! */' > $@ - @sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < $< >> $@ - - include $(BUILD_SHARED_LIBRARY) diff --git a/jni/iodine-client.c b/jni/iodine-client.c index cb5db97..905b154 100644 --- a/jni/iodine-client.c +++ b/jni/iodine-client.c @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -89,13 +90,18 @@ JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_connect( // XXX strdup leaks const char *__p_nameserv_addr = (*env)->GetStringUTFChars(env, j_nameserv_addr, NULL); - const char *p_nameserv_addr = strdup(__p_nameserv_addr); + char *p_nameserv_addr = strdup(__p_nameserv_addr); + struct sockaddr_storage p_nameserv; + int p_nameserv_len = get_addr(p_nameserv_addr, 53, AF_INET, 0, &p_nameserv); (*env)->ReleaseStringUTFChars(env, j_nameserv_addr, __p_nameserv_addr); const char *__p_topdomain = (*env)->GetStringUTFChars(env, j_topdomain, NULL); const char *p_topdomain = strdup(__p_topdomain); + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Topdomain from vm: %s", p_topdomain); + (*env)->ReleaseStringUTFChars(env, j_topdomain, __p_topdomain); + __android_log_print(ANDROID_LOG_ERROR, "iodine", "Topdomain from vm: %s", p_topdomain); const char *p_password = (*env)->GetStringUTFChars(env, j_password, NULL); char passwordField[33]; @@ -126,14 +132,14 @@ JNIEXPORT jint JNICALL Java_org_xapek_andiodine_IodineClient_connect( srand((unsigned) time(NULL)); client_init(); - client_set_nameserver(p_nameserv_addr, DNS_PORT); + client_set_nameserver(&p_nameserv, p_nameserv_len); client_set_selecttimeout(selecttimeout); client_set_lazymode(lazy_mode); client_set_topdomain(p_topdomain); client_set_hostname_maxlen(hostname_maxlen); client_set_password(passwordField); - if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) { + if ((dns_fd = open_dns_from_host(NULL, 0, AF_INET, AI_PASSIVE)) == -1) { printf("Could not open dns socket: %s", strerror(errno)); return 1; } diff --git a/jni/iodine/CHANGELOG b/jni/iodine/CHANGELOG index 888beac..93430d9 100644 --- a/jni/iodine/CHANGELOG +++ b/jni/iodine/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 diff --git a/jni/iodine/Makefile b/jni/iodine/Makefile index 01c2325..a75eaa8 100644 --- a/jni/iodine/Makefile +++ b/jni/iodine/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/jni/iodine/README b/jni/iodine/README index d9e3c29..cfc8ede 100644 --- a/jni/iodine/README +++ b/jni/iodine/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 , Erik Ekman -Also major contributions by Anne Bezemer. +Copyright (c) 2006-2014 Erik Ekman , 2006-2009 Bjorn +Andersson . 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/jni/iodine/README-android.txt b/jni/iodine/README-android.txt new file mode 100644 index 0000000..f08c6cf --- /dev/null +++ b/jni/iodine/README-android.txt @@ -0,0 +1,45 @@ + + +iodine - http://code.kryo.se/iodine + +*********************************** + +Extra README file for Android + + +== Running iodine on Android: +1. Get root access on your android device + +2. Find/build a compatible tun.ko for your specific Android kernel + +3. Copy tun.ko and the iodine binary to your device: + (Almost all devices need the armeabi binary. Only Intel powered + ones need the x86 build.) + + adb push tun.ko /data/local/tmp + adb push iodine /data/local/tmp + adb shell + su + cd /data/local/tmp + chmod 777 iodine + +4. Run iodine (see the man page for parameters) + + ./iodine ... + +For more information: http://blog.bokhorst.biz/5123 + +== Building iodine for Android: +1. Download and install the Android SDK and NDK + +2. Download and unpack the iodine sources + +3. Build: + cd src + make base64u.h base64u.c + ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk + + or run "make cross-android" in the iodine root directory. + To build for other archs, specify TARGET_ARCH_ABI: + "make cross-android TARGET_ARCH_ABI=x86" + diff --git a/jni/iodine/README-win32.txt b/jni/iodine/README-win32.txt index eec675e..de9124b 100644 --- a/jni/iodine/README-win32.txt +++ b/jni/iodine/README-win32.txt @@ -8,6 +8,9 @@ Extra README file for Win32 related stuff == Running iodine on Windows: + +0. After iodine 0.6, you need Windows XP or newer to run. + 1. Install the TAP32 driver http://openvpn.net/index.php/open-source/downloads.html Choose OpenVPN 2.0.9 Windows Installer, when installing you can diff --git a/jni/iodine/doc/iodine-server.service b/jni/iodine/doc/iodine-server.service new file mode 100644 index 0000000..64d2ecc --- /dev/null +++ b/jni/iodine/doc/iodine-server.service @@ -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/jni/iodine/doc/iodine-server.socket b/jni/iodine/doc/iodine-server.socket new file mode 100644 index 0000000..d6c57b8 --- /dev/null +++ b/jni/iodine/doc/iodine-server.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Iodine socket + +[Socket] +ListenDatagram=53 + +[Install] +WantedBy=sockets.target diff --git a/jni/iodine/doc/proto_00000502.txt b/jni/iodine/doc/proto_00000502.txt index 46cf2de..831824d 100644 --- a/jni/iodine/doc/proto_00000502.txt +++ b/jni/iodine/doc/proto_00000502.txt @@ -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 diff --git a/jni/iodine/man/iodine.8 b/jni/iodine/man/iodine.8 index 6eee603..1d1e333 100644 --- a/jni/iodine/man/iodine.8 +++ b/jni/iodine/man/iodine.8 @@ -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/jni/iodine/src/Android.mk b/jni/iodine/src/Android.mk new file mode 100644 index 0000000..8f7c729 --- /dev/null +++ b/jni/iodine/src/Android.mk @@ -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) + diff --git a/jni/iodine/src/Makefile b/jni/iodine/src/Makefile index a5b9838..80bd345 100644 --- a/jni/iodine/src/Makefile +++ b/jni/iodine/src/Makefile @@ -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/jni/iodine/src/android_dns.h b/jni/iodine/src/android_dns.h new file mode 100644 index 0000000..dafd8ec --- /dev/null +++ b/jni/iodine/src/android_dns.h @@ -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 diff --git a/jni/iodine/src/base128.c b/jni/iodine/src/base128.c index 32a29f8..7ddc38c 100644 --- a/jni/iodine/src/base128.c +++ b/jni/iodine/src/base128.c @@ -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++; diff --git a/jni/iodine/src/base32.c b/jni/iodine/src/base32.c index 8731a92..d971ce2 100644 --- a/jni/iodine/src/base32.c +++ b/jni/iodine/src/base32.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * 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++; diff --git a/jni/iodine/src/base32.h b/jni/iodine/src/base32.h index 497ca33..53975c5 100644 --- a/jni/iodine/src/base32.h +++ b/jni/iodine/src/base32.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/base64.c b/jni/iodine/src/base64.c index 5218c09..00a84fc 100644 --- a/jni/iodine/src/base64.c +++ b/jni/iodine/src/base64.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * 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; @@ -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++; diff --git a/jni/iodine/src/base64.h b/jni/iodine/src/base64.h index d550cf3..662175e 100644 --- a/jni/iodine/src/base64.h +++ b/jni/iodine/src/base64.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/client.c b/jni/iodine/src/client.c index 552344b..979f668 100644 --- a/jni/iodine/src/client.c +++ b/jni/iodine/src/client.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include #include +#include #include #include #include @@ -31,6 +33,9 @@ #include "windows.h" #include #else +#ifdef ANDROID +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT @@ -58,7 +63,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 +95,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 +152,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 +170,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 +187,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 +207,7 @@ get_qtype() } void -set_downenc(char *encoding) +client_set_downenc(char *encoding) { if (!strcasecmp(encoding, "base32")) downenc = 'T'; @@ -250,7 +221,7 @@ set_downenc(char *encoding) downenc = 'R'; } -void +void client_set_selecttimeout(int select_timeout) { selecttimeout = select_timeout; @@ -302,7 +273,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 +340,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 +373,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 +387,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 +402,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 +567,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 +595,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 */ @@ -1180,11 +1151,11 @@ client_tunnel_cb(int tun_fd, int dns_fd, int 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) { @@ -1227,7 +1198,7 @@ client_tunnel_cb(int tun_fd, int dns_fd, int if (FD_ISSET(dns_fd, &fds)) { if (tunnel_dns(tun_fd, dns_fd) <= 0) continue; - } + } } } @@ -1245,7 +1216,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)); @@ -1284,23 +1255,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; @@ -1308,7 +1279,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)); @@ -1319,7 +1290,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); @@ -1343,7 +1314,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); @@ -1379,7 +1350,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); @@ -1442,33 +1413,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)"); @@ -1487,37 +1456,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"); } @@ -1544,20 +1511,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); @@ -1565,7 +1530,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; @@ -1579,7 +1544,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++) { @@ -1587,7 +1552,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); @@ -1600,7 +1565,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"); @@ -1611,7 +1576,7 @@ handshake_raw_udp(int dns_fd, int seed) fprintf(stderr, "."); fflush(stderr); } - + fprintf(stderr, "failed\n"); return 0; } @@ -1840,7 +1805,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 ' '; @@ -1894,13 +1859,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); @@ -1925,11 +1891,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; } @@ -1972,7 +1939,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 */ @@ -2079,27 +2046,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"); } @@ -2108,7 +2073,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); } @@ -2137,23 +2102,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"); } @@ -2162,7 +2125,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"); } @@ -2180,24 +2143,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"); } @@ -2206,7 +2167,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; @@ -2226,14 +2187,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; @@ -2288,28 +2247,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; @@ -2327,7 +2284,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++) { @@ -2335,14 +2292,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); @@ -2383,7 +2338,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"); @@ -2406,22 +2361,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"); } @@ -2448,7 +2401,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) { diff --git a/jni/iodine/src/client.h b/jni/iodine/src/client.h index e2d9501..79598fb 100644 --- a/jni/iodine/src/client.h +++ b/jni/iodine/src/client.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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); diff --git a/jni/iodine/src/common.c b/jni/iodine/src/common.c index 7a57a8a..6707a14 100644 --- a/jni/iodine/src/common.c +++ b/jni/iodine/src/common.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman +/* Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * Copyright (c) 2007 Albert Lee . * * Permission to use, copy, modify, and distribute this software for any @@ -39,9 +40,11 @@ #endif #include #include -#include #include +#include #include +#include +#include #endif #ifdef HAVE_SETCON @@ -54,11 +57,11 @@ 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__) && !defined(__ANDROID__) +#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; } -#if defined(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,45 +404,16 @@ 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)); } - va_end(list); -} #endif - -#ifdef __ANDROID__ - -void android_printf(const char *fmt, ...) -{ - static char buf[1024]; - va_list list; - va_start(list, fmt); - - snprintf(buf,1024,fmt,list); - - android_log_callback(buf); - va_end(list); } - -void -warn(const char *fmt, ...) -{ - va_list list; - - va_start(list, fmt); - if (fmt) fprintf(stderr, fmt, list); - if (errno != 0) - fprintf(stderr, ": %s\n", strerror(errno)); - va_end(list); -} -#endif - -#if defined(WINDOWS32) || defined(__ANDROID__) void warnx(const char *fmt, ...) { @@ -364,6 +448,23 @@ errx(int eval, const char *fmt, ...) } #endif +#if defined(__ANDROID__) +void android_log_callback(const char *); +static char printf_buf[1024];; +void android_printf(const char *fmt, ...) +{ + va_list list; + va_start(list, fmt); + + vsnprintf(printf_buf,1024,fmt,list); + android_log_callback(printf_buf); + + __android_log_vprint(ANDROID_LOG_INFO, "Iodine", + fmt, list); + va_end(list); +} +#endif + int recent_seqno(int ourseqno, int gotseqno) /* Return 1 if we've seen gotseqno recently (current or up to 3 back). @@ -379,3 +480,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 + diff --git a/jni/iodine/src/common.h b/jni/iodine/src/common.h index 0b0efb8..26800f6 100644 --- a/jni/iodine/src/common.h +++ b/jni/iodine/src/common.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include #include -#include #include +#include #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,24 +123,21 @@ void do_pidfile(char *); void read_password(char*, size_t); -int check_topdomain(char *); +int check_topdomain(char *, char **); #ifdef __ANDROID__ -//#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "iodine", __VA_ARGS__) +#include + #define printf(...) android_printf(__VA_ARGS__) +#define fprintf(egal,...) android_printf(__VA_ARGS__) void android_printf(const char *fmt, ...); +#endif - -#define fprintf(__fd_unused, ...) printf(__VA_ARGS__) - -#include -void err(int eval, const char *fmt, ...); -void warn(const char *fmt, ...); -void errx(int eval, const char *fmt, ...); -void warnx(const char *fmt, ...); -#elif 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, ...); @@ -144,4 +147,8 @@ void warnx(const char *fmt, ...); int recent_seqno(int , int); +#ifndef WINDOWS32 +void fd_set_close_on_exec(int fd); +#endif + #endif diff --git a/jni/iodine/src/dns.c b/jni/iodine/src/dns.c index fb2bcaf..946fe83 100644 --- a/jni/iodine/src/dns.c +++ b/jni/iodine/src/dns.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,16 +21,21 @@ #include #include #include +#include #include #ifdef WINDOWS32 #include "windows.h" #else +#if defined(ANDROID) || defined(__ANDROID__) +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT #include #endif +#include #include #include #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); } diff --git a/jni/iodine/src/dns.h b/jni/iodine/src/dns.h index be8b940..7c1faff 100644 --- a/jni/iodine/src/dns.h +++ b/jni/iodine/src/dns.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,8 +33,4 @@ int dns_encode_a_response(char *buf, size_t buflen, struct query *q); unsigned short dns_get_id(char *packet, size_t packetlen); int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t); -#ifdef __ANDROID__ -#include "dns_android.h" -#endif - #endif /* _DNS_H_ */ diff --git a/jni/iodine/src/dns_android.h b/jni/iodine/src/dns_android.h deleted file mode 100644 index f8addf7..0000000 --- a/jni/iodine/src/dns_android.h +++ /dev/null @@ -1,625 +0,0 @@ -/* This file is modified to serve minimal requirements of iodine */ - - -/* - * Copyright (c) 1983, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * $BINDId: nameser.h,v 8.37 2000/03/30 21:16:49 vixie Exp $ - */ - -#ifndef _ARPA_NAMESER_H_ -#define _ARPA_NAMESER_H_ - -/*% - * Revision information. This is the release date in YYYYMMDD format. - * It can change every day so the right thing to do with it is use it - * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not - * compare for equality; rather, use it to determine whether your libbind.a - * contains a new enough lib/nameser/ to support the feature you need. - */ - -#define __NAMESER 19991006 /*%< New interface version stamp. */ -/* - * Define constants based on RFC 883, RFC 1034, RFC 1035 - */ -#define NS_PACKETSZ 512 /*%< default UDP packet size */ -#define NS_MAXDNAME 1025 /*%< maximum domain name */ -#define NS_MAXMSG 65535 /*%< maximum message size */ -#define NS_MAXCDNAME 255 /*%< maximum compressed domain name */ -#define NS_MAXLABEL 63 /*%< maximum length of domain label */ -#define NS_HFIXEDSZ 12 /*%< #/bytes of fixed data in header */ -#define NS_QFIXEDSZ 4 /*%< #/bytes of fixed data in query */ -#define NS_RRFIXEDSZ 10 /*%< #/bytes of fixed data in r record */ -#define NS_INT32SZ 4 /*%< #/bytes of data in a u_int32_t */ -#define NS_INT16SZ 2 /*%< #/bytes of data in a u_int16_t */ -#define NS_INT8SZ 1 /*%< #/bytes of data in a u_int8_t */ -#define NS_INADDRSZ 4 /*%< IPv4 T_A */ -#define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */ -#define NS_CMPRSFLGS 0xc0 /*%< Flag bits indicating name compression. */ -#define NS_DEFAULTPORT 53 /*%< For both TCP and UDP. */ -/* - * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() - * in synch with it. - */ -typedef enum __ns_sect { - ns_s_qd = 0, /*%< Query: Question. */ - ns_s_zn = 0, /*%< Update: Zone. */ - ns_s_an = 1, /*%< Query: Answer. */ - ns_s_pr = 1, /*%< Update: Prerequisites. */ - ns_s_ns = 2, /*%< Query: Name servers. */ - ns_s_ud = 2, /*%< Update: Update. */ - ns_s_ar = 3, /*%< Query|Update: Additional records. */ - ns_s_max = 4 -} ns_sect; - -/*% - * This is a message handle. It is caller allocated and has no dynamic data. - * This structure is intended to be opaque to all but ns_parse.c, thus the - * leading _'s on the member names. Use the accessor functions, not the _'s. - */ -typedef struct __ns_msg { - const u_char *_msg, *_eom; - u_int16_t _id, _flags, _counts[ns_s_max]; - const u_char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; - const u_char *_msg_ptr; -} ns_msg; - -/* Private data structure - do not use from outside library. */ -struct _ns_flagdata { int mask, shift; }; -extern const struct _ns_flagdata _ns_flagdata[]; - -/* Accessor macros - this is part of the public interface. */ - -#define ns_msg_id(handle) ((handle)._id + 0) -#define ns_msg_base(handle) ((handle)._msg + 0) -#define ns_msg_end(handle) ((handle)._eom + 0) -#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) -#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) - -/*% - * This is a parsed record. It is caller allocated and has no dynamic data. - */ -typedef struct __ns_rr { - char name[NS_MAXDNAME]; - u_int16_t type; - u_int16_t rr_class; - u_int32_t ttl; - u_int16_t rdlength; - const u_char * rdata; -} ns_rr; - -/* Accessor macros - this is part of the public interface. */ -#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") -#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) -#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) -#define ns_rr_ttl(rr) ((rr).ttl + 0) -#define ns_rr_rdlen(rr) ((rr).rdlength + 0) -#define ns_rr_rdata(rr) ((rr).rdata + 0) - -/*% - * These don't have to be in the same order as in the packet flags word, - * and they can even overlap in some cases, but they will need to be kept - * in synch with ns_parse.c:ns_flagdata[]. - */ -typedef enum __ns_flag { - ns_f_qr, /*%< Question/Response. */ - ns_f_opcode, /*%< Operation code. */ - ns_f_aa, /*%< Authoritative Answer. */ - ns_f_tc, /*%< Truncation occurred. */ - ns_f_rd, /*%< Recursion Desired. */ - ns_f_ra, /*%< Recursion Available. */ - ns_f_z, /*%< MBZ. */ - ns_f_ad, /*%< Authentic Data (DNSSEC). */ - ns_f_cd, /*%< Checking Disabled (DNSSEC). */ - ns_f_rcode, /*%< Response code. */ - ns_f_max -} ns_flag; - -/*% - * Currently defined opcodes. - */ -typedef enum __ns_opcode { - ns_o_query = 0, /*%< Standard query. */ - ns_o_iquery = 1, /*%< Inverse query (deprecated/unsupported). */ - ns_o_status = 2, /*%< Name server status query (unsupported). */ - /* Opcode 3 is undefined/reserved. */ - ns_o_notify = 4, /*%< Zone change notification. */ - ns_o_update = 5, /*%< Zone update message. */ - ns_o_max = 6 -} ns_opcode; - -/*% - * Currently defined response codes. - */ -typedef enum __ns_rcode { - ns_r_noerror = 0, /*%< No error occurred. */ - ns_r_formerr = 1, /*%< Format error. */ - ns_r_servfail = 2, /*%< Server failure. */ - ns_r_nxdomain = 3, /*%< Name error. */ - ns_r_notimpl = 4, /*%< Unimplemented. */ - ns_r_refused = 5, /*%< Operation refused. */ - /* these are for BIND_UPDATE */ - ns_r_yxdomain = 6, /*%< Name exists */ - ns_r_yxrrset = 7, /*%< RRset exists */ - ns_r_nxrrset = 8, /*%< RRset does not exist */ - ns_r_notauth = 9, /*%< Not authoritative for zone */ - ns_r_notzone = 10, /*%< Zone of record different from zone section */ - ns_r_max = 11, - /* The following are EDNS extended rcodes */ - ns_r_badvers = 16, - /* The following are TSIG errors */ - ns_r_badsig = 16, - ns_r_badkey = 17, - ns_r_badtime = 18 -} ns_rcode; - -/* BIND_UPDATE */ -typedef enum __ns_update_operation { - ns_uop_delete = 0, - ns_uop_add = 1, - ns_uop_max = 2 -} ns_update_operation; - -/*% - * This structure is used for TSIG authenticated messages - */ -struct ns_tsig_key { - char name[NS_MAXDNAME], alg[NS_MAXDNAME]; - unsigned char *data; - int len; -}; -typedef struct ns_tsig_key ns_tsig_key; - -/*% - * This structure is used for TSIG authenticated TCP messages - */ -struct ns_tcp_tsig_state { - int counter; - struct dst_key *key; - void *ctx; - unsigned char sig[NS_PACKETSZ]; - int siglen; -}; -typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; - -#define NS_TSIG_FUDGE 300 -#define NS_TSIG_TCP_COUNT 100 -#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" - -#define NS_TSIG_ERROR_NO_TSIG -10 -#define NS_TSIG_ERROR_NO_SPACE -11 -#define NS_TSIG_ERROR_FORMERR -12 - -/*% - * Currently defined type values for resources and queries. - */ -typedef enum __ns_type { - ns_t_invalid = 0, /*%< Cookie. */ - ns_t_a = 1, /*%< Host address. */ - ns_t_ns = 2, /*%< Authoritative server. */ - ns_t_md = 3, /*%< Mail destination. */ - ns_t_mf = 4, /*%< Mail forwarder. */ - ns_t_cname = 5, /*%< Canonical name. */ - ns_t_soa = 6, /*%< Start of authority zone. */ - ns_t_mb = 7, /*%< Mailbox domain name. */ - ns_t_mg = 8, /*%< Mail group member. */ - ns_t_mr = 9, /*%< Mail rename name. */ - ns_t_null = 10, /*%< Null resource record. */ - ns_t_wks = 11, /*%< Well known service. */ - ns_t_ptr = 12, /*%< Domain name pointer. */ - ns_t_hinfo = 13, /*%< Host information. */ - ns_t_minfo = 14, /*%< Mailbox information. */ - ns_t_mx = 15, /*%< Mail routing information. */ - ns_t_txt = 16, /*%< Text strings. */ - ns_t_rp = 17, /*%< Responsible person. */ - ns_t_afsdb = 18, /*%< AFS cell database. */ - ns_t_x25 = 19, /*%< X_25 calling address. */ - ns_t_isdn = 20, /*%< ISDN calling address. */ - ns_t_rt = 21, /*%< Router. */ - ns_t_nsap = 22, /*%< NSAP address. */ - ns_t_nsap_ptr = 23, /*%< Reverse NSAP lookup (deprecated). */ - ns_t_sig = 24, /*%< Security signature. */ - ns_t_key = 25, /*%< Security key. */ - ns_t_px = 26, /*%< X.400 mail mapping. */ - ns_t_gpos = 27, /*%< Geographical position (withdrawn). */ - ns_t_aaaa = 28, /*%< Ip6 Address. */ - ns_t_loc = 29, /*%< Location Information. */ - ns_t_nxt = 30, /*%< Next domain (security). */ - ns_t_eid = 31, /*%< Endpoint identifier. */ - ns_t_nimloc = 32, /*%< Nimrod Locator. */ - ns_t_srv = 33, /*%< Server Selection. */ - ns_t_atma = 34, /*%< ATM Address */ - ns_t_naptr = 35, /*%< Naming Authority PoinTeR */ - ns_t_kx = 36, /*%< Key Exchange */ - ns_t_cert = 37, /*%< Certification record */ - ns_t_a6 = 38, /*%< IPv6 address (deprecated, use ns_t_aaaa) */ - ns_t_dname = 39, /*%< Non-terminal DNAME (for IPv6) */ - ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */ - ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */ - ns_t_apl = 42, /*%< Address prefix list (RFC3123) */ - ns_t_tkey = 249, /*%< Transaction key */ - ns_t_tsig = 250, /*%< Transaction signature. */ - ns_t_ixfr = 251, /*%< Incremental zone transfer. */ - ns_t_axfr = 252, /*%< Transfer zone of authority. */ - ns_t_mailb = 253, /*%< Transfer mailbox records. */ - ns_t_maila = 254, /*%< Transfer mail agent records. */ - ns_t_any = 255, /*%< Wildcard match. */ - ns_t_zxfr = 256, /*%< BIND-specific, nonstandard. */ - ns_t_max = 65536 -} ns_type; - -/* Exclusively a QTYPE? (not also an RTYPE) */ -#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ - (t) == ns_t_mailb || (t) == ns_t_maila) -/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ -#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) -/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ -#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) -#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) -#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ - (t) == ns_t_zxfr) - -/*% - * Values for class field - */ -typedef enum __ns_class { - ns_c_invalid = 0, /*%< Cookie. */ - ns_c_in = 1, /*%< Internet. */ - ns_c_2 = 2, /*%< unallocated/unsupported. */ - ns_c_chaos = 3, /*%< MIT Chaos-net. */ - ns_c_hs = 4, /*%< MIT Hesiod. */ - /* Query class values which do not appear in resource records */ - ns_c_none = 254, /*%< for prereq. sections in update requests */ - ns_c_any = 255, /*%< Wildcard match. */ - ns_c_max = 65536 -} ns_class; - -/* DNSSEC constants. */ - -typedef enum __ns_key_types { - ns_kt_rsa = 1, /*%< key type RSA/MD5 */ - ns_kt_dh = 2, /*%< Diffie Hellman */ - ns_kt_dsa = 3, /*%< Digital Signature Standard (MANDATORY) */ - ns_kt_private = 254 /*%< Private key type starts with OID */ -} ns_key_types; - -typedef enum __ns_cert_types { - cert_t_pkix = 1, /*%< PKIX (X.509v3) */ - cert_t_spki = 2, /*%< SPKI */ - cert_t_pgp = 3, /*%< PGP */ - cert_t_url = 253, /*%< URL private type */ - cert_t_oid = 254 /*%< OID private type */ -} ns_cert_types; - -/* Flags field of the KEY RR rdata. */ -#define NS_KEY_TYPEMASK 0xC000 /*%< Mask for "type" bits */ -#define NS_KEY_TYPE_AUTH_CONF 0x0000 /*%< Key usable for both */ -#define NS_KEY_TYPE_CONF_ONLY 0x8000 /*%< Key usable for confidentiality */ -#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /*%< Key usable for authentication */ -#define NS_KEY_TYPE_NO_KEY 0xC000 /*%< No key usable for either; no key */ -/* The type bits can also be interpreted independently, as single bits: */ -#define NS_KEY_NO_AUTH 0x8000 /*%< Key unusable for authentication */ -#define NS_KEY_NO_CONF 0x4000 /*%< Key unusable for confidentiality */ -#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ -#define NS_KEY_EXTENDED_FLAGS 0x1000 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED4 0x0800 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED5 0x0400 /*%< reserved - must be zero */ -#define NS_KEY_NAME_TYPE 0x0300 /*%< these bits determine the type */ -#define NS_KEY_NAME_USER 0x0000 /*%< key is assoc. with user */ -#define NS_KEY_NAME_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ -#define NS_KEY_NAME_ZONE 0x0100 /*%< key is zone key */ -#define NS_KEY_NAME_RESERVED 0x0300 /*%< reserved meaning */ -#define NS_KEY_RESERVED8 0x0080 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED9 0x0040 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED10 0x0020 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED11 0x0010 /*%< reserved - must be zero */ -#define NS_KEY_SIGNATORYMASK 0x000F /*%< key can sign RR's of same name */ -#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ - NS_KEY_RESERVED4 | \ - NS_KEY_RESERVED5 | \ - NS_KEY_RESERVED8 | \ - NS_KEY_RESERVED9 | \ - NS_KEY_RESERVED10 | \ - NS_KEY_RESERVED11 ) -#define NS_KEY_RESERVED_BITMASK2 0xFFFF /*%< no bits defined here */ -/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ -#define NS_ALG_MD5RSA 1 /*%< MD5 with RSA */ -#define NS_ALG_DH 2 /*%< Diffie Hellman KEY */ -#define NS_ALG_DSA 3 /*%< DSA KEY */ -#define NS_ALG_DSS NS_ALG_DSA -#define NS_ALG_EXPIRE_ONLY 253 /*%< No alg, no security */ -#define NS_ALG_PRIVATE_OID 254 /*%< Key begins with OID giving alg */ -/* Protocol values */ -/* value 0 is reserved */ -#define NS_KEY_PROT_TLS 1 -#define NS_KEY_PROT_EMAIL 2 -#define NS_KEY_PROT_DNSSEC 3 -#define NS_KEY_PROT_IPSEC 4 -#define NS_KEY_PROT_ANY 255 - -/* Signatures */ -#define NS_MD5RSA_MIN_BITS 512 /*%< Size of a mod or exp in bits */ -#define NS_MD5RSA_MAX_BITS 4096 - /* Total of binary mod and exp */ -#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) - /* Max length of text sig block */ -#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) -#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) -#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) - -#define NS_DSA_SIG_SIZE 41 -#define NS_DSA_MIN_SIZE 213 -#define NS_DSA_MAX_BYTES 405 - -/* Offsets into SIG record rdata to find various values */ -#define NS_SIG_TYPE 0 /*%< Type flags */ -#define NS_SIG_ALG 2 /*%< Algorithm */ -#define NS_SIG_LABELS 3 /*%< How many labels in name */ -#define NS_SIG_OTTL 4 /*%< Original TTL */ -#define NS_SIG_EXPIR 8 /*%< Expiration time */ -#define NS_SIG_SIGNED 12 /*%< Signature time */ -#define NS_SIG_FOOT 16 /*%< Key footprint */ -#define NS_SIG_SIGNER 18 /*%< Domain name of who signed it */ -/* How RR types are represented as bit-flags in NXT records */ -#define NS_NXT_BITS 8 -#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_MAX 127 - -/*% - * EDNS0 extended flags and option codes, host order. - */ -#define NS_OPT_DNSSEC_OK 0x8000U -#define NS_OPT_NSID 3 - -/*% - * Inline versions of get/put short/long. Pointer is advanced. - */ -#define NS_GET16(s, cp) do { \ - register const u_char *t_cp = (const u_char *)(cp); \ - (s) = ((u_int16_t)t_cp[0] << 8) \ - | ((u_int16_t)t_cp[1]) \ - ; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_GET32(l, cp) do { \ - register const u_char *t_cp = (const u_char *)(cp); \ - (l) = ((u_int32_t)t_cp[0] << 24) \ - | ((u_int32_t)t_cp[1] << 16) \ - | ((u_int32_t)t_cp[2] << 8) \ - | ((u_int32_t)t_cp[3]) \ - ; \ - (cp) += NS_INT32SZ; \ -} while (0) - -#define NS_PUT16(s, cp) do { \ - register u_int16_t t_s = (u_int16_t)(s); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_s >> 8; \ - *t_cp = t_s; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_PUT32(l, cp) do { \ - register u_int32_t t_l = (u_int32_t)(l); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_l >> 24; \ - *t_cp++ = t_l >> 16; \ - *t_cp++ = t_l >> 8; \ - *t_cp = t_l; \ - (cp) += NS_INT32SZ; \ -} while (0) - -#endif /* !_ARPA_NAMESER_H_ */ -/*! \file */ - - - -/*% - * from nameser.h 8.1 (Berkeley) 6/2/93 - * $BINDId: nameser_compat.h,v 8.11 1999/01/02 08:00:58 vixie Exp $ - */ - -#ifndef _ARPA_NAMESER_COMPAT_ -#define _ARPA_NAMESER_COMPAT_ - -#define __BIND 19950621 /*%< (DEAD) interface version stamp. */ - -#include - -/*% - * Structure for query header. The order of the fields is machine- and - * compiler-dependent, depending on the byte/bit order and the layout - * of bit fields. We use bit fields only in int variables, as this - * is all ANSI requires. This requires a somewhat confusing rearrangement. - */ - -typedef struct { - unsigned id :16; /*%< query identification number */ -#if BYTE_ORDER == BIG_ENDIAN - /* fields in third byte */ - unsigned qr: 1; /*%< response flag */ - unsigned opcode: 4; /*%< purpose of message */ - unsigned aa: 1; /*%< authoritive answer */ - unsigned tc: 1; /*%< truncated message */ - unsigned rd: 1; /*%< recursion desired */ - /* fields in fourth byte */ - unsigned ra: 1; /*%< recursion available */ - unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ - unsigned ad: 1; /*%< authentic data from named */ - unsigned cd: 1; /*%< checking disabled by resolver */ - unsigned rcode :4; /*%< response code */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN - /* fields in third byte */ - unsigned rd :1; /*%< recursion desired */ - unsigned tc :1; /*%< truncated message */ - unsigned aa :1; /*%< authoritive answer */ - unsigned opcode :4; /*%< purpose of message */ - unsigned qr :1; /*%< response flag */ - /* fields in fourth byte */ - unsigned rcode :4; /*%< response code */ - unsigned cd: 1; /*%< checking disabled by resolver */ - unsigned ad: 1; /*%< authentic data from named */ - unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ - unsigned ra :1; /*%< recursion available */ -#endif - /* remaining bytes */ - unsigned qdcount :16; /*%< number of question entries */ - unsigned ancount :16; /*%< number of answer entries */ - unsigned nscount :16; /*%< number of authority entries */ - unsigned arcount :16; /*%< number of resource entries */ -} HEADER; - -#define PACKETSZ NS_PACKETSZ -#define MAXDNAME NS_MAXDNAME -#define MAXCDNAME NS_MAXCDNAME -#define MAXLABEL NS_MAXLABEL -#define HFIXEDSZ NS_HFIXEDSZ -#define QFIXEDSZ NS_QFIXEDSZ -#define RRFIXEDSZ NS_RRFIXEDSZ -#define INT32SZ NS_INT32SZ -#define INT16SZ NS_INT16SZ -#define INT8SZ NS_INT8SZ -#define INADDRSZ NS_INADDRSZ -#define IN6ADDRSZ NS_IN6ADDRSZ -#define INDIR_MASK NS_CMPRSFLGS -#define NAMESERVER_PORT NS_DEFAULTPORT - -#define S_ZONE ns_s_zn -#define S_PREREQ ns_s_pr -#define S_UPDATE ns_s_ud -#define S_ADDT ns_s_ar - -#define QUERY ns_o_query -#define IQUERY ns_o_iquery -#define STATUS ns_o_status -#define NS_NOTIFY_OP ns_o_notify -#define NS_UPDATE_OP ns_o_update - -#define NOERROR ns_r_noerror -#define FORMERR ns_r_formerr -#define SERVFAIL ns_r_servfail -#define NXDOMAIN ns_r_nxdomain -#define NOTIMP ns_r_notimpl -#define REFUSED ns_r_refused -#define YXDOMAIN ns_r_yxdomain -#define YXRRSET ns_r_yxrrset -#define NXRRSET ns_r_nxrrset -#define NOTAUTH ns_r_notauth -#define NOTZONE ns_r_notzone -/*#define BADSIG ns_r_badsig*/ -/*#define BADKEY ns_r_badkey*/ -/*#define BADTIME ns_r_badtime*/ - - -#define DELETE ns_uop_delete -#define ADD ns_uop_add - -#define T_A ns_t_a -#define T_NS ns_t_ns -#define T_MD ns_t_md -#define T_MF ns_t_mf -#define T_CNAME ns_t_cname -#define T_SOA ns_t_soa -#define T_MB ns_t_mb -#define T_MG ns_t_mg -#define T_MR ns_t_mr -#define T_NULL ns_t_null -#define T_WKS ns_t_wks -#define T_PTR ns_t_ptr -#define T_HINFO ns_t_hinfo -#define T_MINFO ns_t_minfo -#define T_MX ns_t_mx -#define T_TXT ns_t_txt -#define T_RP ns_t_rp -#define T_AFSDB ns_t_afsdb -#define T_X25 ns_t_x25 -#define T_ISDN ns_t_isdn -#define T_RT ns_t_rt -#define T_NSAP ns_t_nsap -#define T_NSAP_PTR ns_t_nsap_ptr -#define T_SIG ns_t_sig -#define T_KEY ns_t_key -#define T_PX ns_t_px -#define T_GPOS ns_t_gpos -#define T_AAAA ns_t_aaaa -#define T_LOC ns_t_loc -#define T_NXT ns_t_nxt -#define T_EID ns_t_eid -#define T_NIMLOC ns_t_nimloc -#define T_SRV ns_t_srv -#define T_ATMA ns_t_atma -#define T_NAPTR ns_t_naptr -#define T_A6 ns_t_a6 -#define T_DNAME ns_t_dname -#define T_TSIG ns_t_tsig -#define T_IXFR ns_t_ixfr -#define T_AXFR ns_t_axfr -#define T_MAILB ns_t_mailb -#define T_MAILA ns_t_maila -#define T_ANY ns_t_any - -#define C_IN ns_c_in -#define C_CHAOS ns_c_chaos -#define C_HS ns_c_hs -/* BIND_UPDATE */ -#define C_NONE ns_c_none -#define C_ANY ns_c_any - -#define GETSHORT NS_GET16 -#define GETLONG NS_GET32 -#define PUTSHORT NS_PUT16 -#define PUTLONG NS_PUT32 - -#endif /* _ARPA_NAMESER_COMPAT_ */ -/*! \file */ diff --git a/jni/iodine/src/encoding.c b/jni/iodine/src/encoding.c index 896d67d..af7620e 100644 --- a/jni/iodine/src/encoding.c +++ b/jni/iodine/src/encoding.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,23 +20,22 @@ #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; } diff --git a/jni/iodine/src/encoding.h b/jni/iodine/src/encoding.h index 7ddf6e0..ab22279 100644 --- a/jni/iodine/src/encoding.h +++ b/jni/iodine/src/encoding.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/fw_query.c b/jni/iodine/src/fw_query.c index 3727f08..4f7d8c4 100644 --- a/jni/iodine/src/fw_query.c +++ b/jni/iodine/src/fw_query.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Erik Ekman + * Copyright (c) 2008-2014 Erik Ekman * * 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; } diff --git a/jni/iodine/src/fw_query.h b/jni/iodine/src/fw_query.h index 7568a5f..f8f0de6 100644 --- a/jni/iodine/src/fw_query.h +++ b/jni/iodine/src/fw_query.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Erik Ekman + * Copyright (c) 2008-2014 Erik Ekman * * 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; }; diff --git a/jni/iodine/src/iodine.c b/jni/iodine/src/iodine.c index 03efb18..5c19576 100644 --- a/jni/iodine/src/iodine.c +++ b/jni/iodine/src/iodine.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include +#include #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]; diff --git a/jni/iodine/src/iodined.c b/jni/iodine/src/iodined.c index 3681084..1065c33 100644 --- a/jni/iodine/src/iodined.c +++ b/jni/iodine/src/iodined.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include #include +#include #include #include #include @@ -59,6 +61,10 @@ #include "fw_query.h" #include "version.h" +#ifdef HAVE_SYSTEMD +# include +#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; diff --git a/jni/iodine/src/login.c b/jni/iodine/src/login.c index c8827c3..a809998 100644 --- a/jni/iodine/src/login.c +++ b/jni/iodine/src/login.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,16 +21,17 @@ #ifdef WINDOWS32 #include "windows.h" #else +#include #include #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); diff --git a/jni/iodine/src/login.h b/jni/iodine/src/login.h index 840c920..ebea25c 100644 --- a/jni/iodine/src/login.h +++ b/jni/iodine/src/login.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/md5.h b/jni/iodine/src/md5.h index 698c995..3baa4dc 100644 --- a/jni/iodine/src/md5.h +++ b/jni/iodine/src/md5.h @@ -71,7 +71,7 @@ typedef struct md5_state_s { } md5_state_t; #ifdef __cplusplus -extern "C" +extern "C" { #endif diff --git a/jni/iodine/src/osflags b/jni/iodine/src/osflags index 787ffaa..9eda8f0 100755 --- a/jni/iodine/src/osflags +++ b/jni/iodine/src/osflags @@ -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 ;; diff --git a/jni/iodine/src/read.c b/jni/iodine/src/read.c index ff40382..a2dcd96 100644 --- a/jni/iodine/src/read.c +++ b/jni/iodine/src/read.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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; } diff --git a/jni/iodine/src/read.h b/jni/iodine/src/read.h index b33f3bb..2aac355 100644 --- a/jni/iodine/src/read.h +++ b/jni/iodine/src/read.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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); diff --git a/jni/iodine/src/tun.c b/jni/iodine/src/tun.c index eb52959..f8a2fd4 100644 --- a/jni/iodine/src/tun.c +++ b/jni/iodine/src/tun.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,13 +25,16 @@ #include #include +#ifndef IFCONFIGPATH +#define IFCONFIGPATH "PATH=/sbin:/bin " +#endif + #ifdef WINDOWS32 -#include -#include #include "windows.h" +#include -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 -#include #include +#include #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 #include #include -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'; - - 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; -} +#elif WINDOWS32 -#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) { -#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32) || defined(__ANDROID__) + 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(__ANDROID__) 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) || defined(__ANDROID__) - /* FreeBSD/Darwin/NetBSD/Android-VPN has no header */ +#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(__ANDROID__) + /* FreeBSD/Darwin/NetBSD/Android-SDK 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; @@ -461,32 +492,36 @@ tun_setip(const char *ip, const char *remoteip, int netbits) free(tun_config_android.remoteip); } tun_config_android.ip = strdup(ip); - tun_config_android.remoteip = strdup(remoteip); + tun_config_android.remoteip = strdup(other_ip); tun_config_android.netbits = netbits; return 0; #elif !defined(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 */ @@ -494,13 +529,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 */ @@ -510,7 +545,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"); @@ -525,7 +560,7 @@ tun_setip(const char *ip, const char *remoteip, int netbits) #endif } -int +int tun_setmtu(const unsigned mtu) { #ifdef __ANDROID__ @@ -535,11 +570,11 @@ tun_setmtu(const unsigned mtu) 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 { diff --git a/jni/iodine/src/tun.h b/jni/iodine/src/tun.h index 397e7a9..83a6171 100644 --- a/jni/iodine/src/tun.h +++ b/jni/iodine/src/tun.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/user.c b/jni/iodine/src/user.c index dfe9c36..0dc95db 100644 --- a/jni/iodine/src/user.c +++ b/jni/iodine/src/user.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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; } - + diff --git a/jni/iodine/src/user.h b/jni/iodine/src/user.h index 51a6092..76fc54b 100644 --- a/jni/iodine/src/user.h +++ b/jni/iodine/src/user.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,9 +34,11 @@ #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(); diff --git a/jni/iodine/src/util.c b/jni/iodine/src/util.c index bc5fc8d..f4a538e 100644 --- a/jni/iodine/src/util.c +++ b/jni/iodine/src/util.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 diff --git a/jni/iodine/src/util.h b/jni/iodine/src/util.h index f514139..6872077 100644 --- a/jni/iodine/src/util.h +++ b/jni/iodine/src/util.h @@ -2,5 +2,6 @@ #define __UTIL_H__ char *get_resolvconf_addr(); +void socket_setrtable(int fd, int rtable); #endif diff --git a/jni/iodine/src/version.h b/jni/iodine/src/version.h index 1561b9e..2ab00ff 100644 --- a/jni/iodine/src/version.h +++ b/jni/iodine/src/version.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/windows.h b/jni/iodine/src/windows.h index 7e0e16c..c665a60 100644 --- a/jni/iodine/src/windows.h +++ b/jni/iodine/src/windows.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,9 +20,9 @@ typedef unsigned int in_addr_t; +#include #include #include -#include #include #include @@ -94,7 +95,8 @@ DWORD WINAPI tun_reader(LPVOID arg); struct tun_data { HANDLE tun; int sock; - struct sockaddr_in addr; + struct sockaddr_storage addr; + int addrlen; }; #endif diff --git a/jni/iodine/tests/Makefile b/jni/iodine/tests/Makefile index 3a7ac01..03eed98 100644 --- a/jni/iodine/tests/Makefile +++ b/jni/iodine/tests/Makefile @@ -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) diff --git a/jni/iodine/tests/base32.c b/jni/iodine/tests/base32.c index 9ff0cf7..419253f 100644 --- a/jni/iodine/tests/base32.c +++ b/jni/iodine/tests/base32.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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); } } diff --git a/jni/iodine/tests/base64.c b/jni/iodine/tests/base64.c index bd0e9ce..cd96d21 100644 --- a/jni/iodine/tests/base64.c +++ b/jni/iodine/tests/base64.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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/jni/iodine/tests/common.c b/jni/iodine/tests/common.c new file mode 100644 index 0000000..c1bc73f --- /dev/null +++ b/jni/iodine/tests/common.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include + +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; +} diff --git a/jni/iodine/tests/dns.c b/jni/iodine/tests/dns.c index 3d21e4c..cdd3378 100644 --- a/jni/iodine/tests/dns.c +++ b/jni/iodine/tests/dns.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +25,10 @@ #include #include #include +#ifdef DARWIN +#define BIND_8_COMPAT +#include +#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 diff --git a/jni/iodine/tests/encoding.c b/jni/iodine/tests/encoding.c index ac22452..665c4dd 100644 --- a/jni/iodine/tests/encoding.c +++ b/jni/iodine/tests/encoding.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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)); diff --git a/jni/iodine/tests/fw_query.c b/jni/iodine/tests/fw_query.c index 6d23924..c6ed2c7 100644 --- a/jni/iodine/tests/fw_query.c +++ b/jni/iodine/tests/fw_query.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2009 Erik Ekman + * Copyright (c) 2009-2014 Erik Ekman * * 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); diff --git a/jni/iodine/tests/login.c b/jni/iodine/tests/login.c index 1ef23f4..e154ee2 100644 --- a/jni/iodine/tests/login.c +++ b/jni/iodine/tests/login.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/tests/read.c b/jni/iodine/tests/read.c index 18cc29c..24a5214 100644 --- a/jni/iodine/tests/read.c +++ b/jni/iodine/tests/read.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include #ifdef DARWIN -#include +#define BIND_8_COMPAT +#include #endif #include #include @@ -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); diff --git a/jni/iodine/tests/test.c b/jni/iodine/tests/test.c index 5bee9d2..cc753d4 100644 --- a/jni/iodine/tests/test.c +++ b/jni/iodine/tests/test.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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); diff --git a/jni/iodine/tests/test.h b/jni/iodine/tests/test.h index 1022a9e..511cf31 100644 --- a/jni/iodine/tests/test.h +++ b/jni/iodine/tests/test.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 diff --git a/jni/iodine/tests/user.c b/jni/iodine/tests/user.c index afd61ca..2e4f36d 100644 --- a/jni/iodine/tests/user.c +++ b/jni/iodine/tests/user.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * 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 #include #include -#include #include +#include #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); } -- cgit v1.2.1