[
  {
    "path": ".github/workflows/freebsd.yml",
    "content": "name: freebsd\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n    contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: make\n      uses: vmactions/freebsd-vm@v1.2.0\n      with:\n        prepare: |\n          pkg install -y \\\n            devel/check \\\n            devel/git \\\n            devel/pkgconf\n        run: |\n          make\n          make test\n"
  },
  {
    "path": ".github/workflows/macos.yml",
    "content": "name: macos\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n    contents: read\n\njobs:\n  build:\n\n    runs-on: macos-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: make\n      run: make\n    - name: install check\n      run: brew install check\n    - name: run tests\n      run: make test\n"
  },
  {
    "path": ".github/workflows/openbsd.yml",
    "content": "name: openbsd\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n    contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: make\n      uses: vmactions/openbsd-vm@v1.1.8\n      with:\n        prepare: |\n          pkg_add \\\n            check \\\n            git \\\n            pkgconf\n        run: |\n          make\n          make test\n"
  },
  {
    "path": ".github/workflows/ubuntu.yml",
    "content": "name: ubuntu\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n    contents: read\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: make\n      run: make\n    - name: install check\n      run: sudo apt install check\n    - name: run tests\n      run: make test\n\n  build-android:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - uses: nttld/setup-ndk@v1\n      with:\n        ndk-version: r21e\n    - name: make\n      run: make cross-android\n"
  },
  {
    "path": ".github/workflows/windows.yml",
    "content": "name: windows\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\npermissions:\n    contents: read\n\njobs:\n  build:\n\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: msys2 {0}\n\n    steps:\n    - uses: actions/checkout@v4\n    - uses: msys2/setup-msys2@v2\n      with:\n        msystem: MINGW64\n        update: false\n        install: git make mingw-w64-x86_64-toolchain mingw-w64-x86_64-zlib\n    - name: make\n      run: make TARGETOS=windows32\n"
  },
  {
    "path": ".gitignore",
    "content": "/bin/\n*.o\n/src/base64u.c\n/src/base64u.h\n/tests/test\n*.o.d\n/src/obj/local/*/iodine\n/src/libs/*/iodine\n"
  },
  {
    "path": ".vimrc",
    "content": "set noexpandtab\nset tabstop=8\nset softtabstop=8\nset shiftwidth=8\n"
  },
  {
    "path": "CHANGELOG",
    "content": "\niodine - https://code.kryo.se/iodine\n\n************************************\n\nCHANGES:\n\nmaster:\n\t- Changed deprecated tzsetwall() to tzset() (only used by FreeBSD),\n\t  patch by Pouria Mousavizadeh Tehrani.\n    - Now builds on macOS even without if_utun.h (pre 10.6).\n\n2023-04-17: 0.8.0 \"Burning Snowman\"\n\t- Mac OS X: Support native utun VPN devices. Patch by\n\t\tPeter Sagerson, ported from OpenVPN by Catalin Patulea.\n\t- Fix compilation failure on kFreeBSD and Hurd, by Gregor Herrmann\n\t- Patch from Ryan Welton that fixes compilation warning.\n\t- README converted to markdown by Nicolas Braud-Santoni.\n\t- Linux: use pkg-config for systemd support flags.\n\t\tPatch by Jason A. Donenfeld.\n\t- Add support for IPv6 in the server.\n\t   Raw mode will be with same protocol as used for login.\n\t   Traffic inside tunnel is still IPv4.\n\t- Update android build to try to support 5.0 (Lollipop) and newer.\n\t- Change external IP lookup to using myip.opendns.com via DNS.\n\t- Add option to choose IPv4 listen address from external IP lookup.\n\t- Add server support for handling multiple domains via wildcard.\n\t- Recognize tap device component id 'root' prefix on Windows.\n\n2014-06-16: 0.7.0 \"Kryoptonite\"\n\t- Partial IPv6 support (#107)\n\t   Client can connect to iodined through an relaying IPv6\n\t   nameserver. Server only supports IPv4 for now.\n\t   Traffic inside tunnel is IPv4.\n\t- Add socket activation for systemd, by Michael Scherer.\n\t- Add automated lookup of external ip (via -n auto).\n\t- Bugfix for OS X (Can't assign requested address)\n\t- Fix DNS tunneling bug caused by uninitialized variable, #94\n\t- Handle spaces when entering password interactively, fixes #93.\n\t\tPatch by Hagar.\n\t- Add -R option to set OpenBSD routing domain for the DNS socket.\n\t\tPatch by laurent at gouloum fr, fixes #95.\n\t- Add android patches and makefile, from Marcel Bokhorst, fixes #105.\n\t- Added missing break in iodine.c, by Pavel Pergamenshchik, #108.\n\t- A number of minor patches from Frank Denis, Gregor Herrmann and\n\t\tBarak A. Pearlmutter.\n\t- Testcase compilation fixes for OS X and FreeBSD\n\t- Do not let sockets be inherited by sub-processes, fixes #99.\n\t- Add unspecified RR type (called PRIVATE; id 65399, in private use\n\t\trange). For servers with RFC3597 support. Fixes #97.\n\t- Fix authentication bypass vulnerability; found by Oscar Reparaz.\n\n2010-02-06: 0.6.0-rc1 \"Hotspotify\"\n\t- Fixed tunnel not working on Windows.\n\t- Any device name is now supported on Windows, fixes #47.\n\t- Multiple installed TAP32 interfaces are now supported, fixes #46.\n\t- Return nonzero if tunnel fails to open, fixes #62.\n\t- Support for setting a SELinux context, based on patch by\n\t\tSebastien Raveau. Sample context file in doc/iodine.te\n\t- Allow listen port and DNS forward port to be the same if listen IP\n\t\tdoes not include localhost.\n\t- The client will now exit if configuring IP or MTU fails.\n\t- The starting cache miss value is randomized at startup, fixes #65.\n\t- Raw UDP mode added. If the iodined server is reachable directly,\n\t\tpackets can be sent to it without DNS encoding. Fixes #36.\n\t- Do not overwrite users CC/CFLAGS/LDFLAGS, only add to them.\n\t- Added -F option to write pidfile, based on patch from\n\t\tmisc at mandriva.org. Fixes #70.\n\t- Allow password to be set via environment variable, fixes #77.\n\t\tBased on patch by logix.\n\t- Client now prints server tunnel IP, fixes #78. Patch by logix.\n\t- Fix build error on Mac OS X 10.6, patch by G. Rischard. #79.\n\t- Added support for CNAME/TXT/A/MX query types, fixes #75.\n\t\tPatch by Anne Bezemer, merge help by logix.\n\t- Merged low-latency patch from Anne Bezemer, fixes #76.\n\t- Resolve client nameserver argument if given as hostname, fixes #82.\n\t- Open log before chroot, fixes #86: logging on FreeBSD.\n\t- Merged big bugfix patch from Anne Bezemer, #88.\n\n2009-06-01: 0.5.2 \"WifiFree\"\n\t- Fixed client segfault on OS X, #57\n\t- Added check that nameserver lookup was successful\n\t- Fixed ENOTSOCK error on OS X and FreeBSD, #58.\n\n2009-03-21: 0.5.1 \"Boringo\"\n\t- Added initial Windows support, fixes #43.\n\t- Added length check of autoprobe responses\n\t- Refactored and added unit tests\n\t- Added syslog logging for iodined on version and login packets\n\t- Fixed segfault when encoding just one block, fixes #51.\n\t\tThe normal code was never affected by this.\n\t- Added win32 code to read DNS server from system, fixes #45.\n\t- Disabled password echo on win32, fixes #44.\n\t- Fix encoding error making all autoprobing > 1024 bytes fail, #52.\n\t- Increase default interface MTU to 1200.\n\t- Fix autoprobing error making every third probe fail, set IP flag\n\t\tDont-Fragment where supported. Fixes #54.\n\t- Added TAP32 version 0901 as accepted (#53).\n\n2009-01-23: 0.5.0 \"iPassed\"\n\t- Fixed segfault in server when sending version reject.\n\t- Applied patch to make iodine build on BeOS R5-BONE and Haiku,\n\t\tfrom Francois Revol. Still work to do to get tun device working.\n\t- Added capability to forward DNS queries outside tunnel domain to\n\t\ta nameserver on localhost. Use -b port to enable, fixes #31.\n\t- iodined now replies to NS request on its own domain, fixes issue #33.\n\t\tThe destination IP address is sent as reply. Use -n to specify\n\t\ta specific IP address to return (if behind NAT etc).\n\t- Upstream data is now Base64 encoded if relay server preserves case and\n\t\tsupports the plus (+) character in domain names, fixes #16.\n\t- Fixed problem in client when DNS trans. ID has highest bit set (#37)\n\t- IP addresses are now assigned within the netmask, so iodined can\n\t\tuse any address for itself, fixes #28.\n\t- Netmask size is now adjustable. Setting a small net will reduce the\n\t\tnumber of users. Use x.x.x.x/n notation on iodined tunnel ip.\n\t\tThis fixes #27.\n\t- Downstream data is now fragmented, and the fragment size is auto-\n\t\tprobed after login. Fixes #7. It only took a few years :)\n\t- Enhanced the checks that validates incoming packets\n\t- Fixed endless loop in fragment size autodetection, #39.\n\t- Fixed broken hostname dot placing with specific lengths, #40.\n\n2008-08-06: 0.4.2 \"Opened Zone\"\n\t- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann\n\t- Applied a patch for not creating and configuring the tun interface,\n\t\tDebian bug #477692 by Vincent Bernat, controlled by -s switch\n\t- Applied a security patch from Andrew Griffiths, use setgroups() to\n\t\tlimit the groups of the user\n\t- Applied a patch to make iodine build on (Open)Solaris, from Albert Lee\n\t\tNeeds TUN/TAP driver http://www.whiteboard.ne.jp/~admin2/tuntap/\n\t\tStill needs more code in tun.c for opening/closing the device\n\t- Added option in server (-c) to disable IP/port checking on packets,\n\t\twill hopefully help when server is behind NAT\n\t- Fixed bug #21, now only IP address part of each packet is checked.\n\t\tShould remove the need for the -c option and also work with\n\t\tbugfixed DNS servers worldwide.\n\t- Added -D option on server to enable debugging. Debug level 1 now \n\t\tprints info about each RX/TX datagram.\n\n2007-11-30: 0.4.1 \"Tea Online\"\n\t- Introduced encoding API\n\t- Switched to new Base32 implementation\n\t- Added Base64 implementation that only uses 63 chars (not used yet)\n\t- Refined 'install' make target and use $(MAKE) for recursive calls\n\t- All received error messages (RCODE field) are echoed\n\t- Top domain limited to 128 chars\n\t- Case preservation check sent after login to decide codec\n\t- Fixed crash on incoming NULL query in server with bad top domain\n\t- /etc/resolv.conf is consulted if no nameserver is given on commandline\n\t- Applied patch from Matthew W. S. Bell (Detach before chroot/dropping priv)\n\n2007-03-25: 0.4.0 \"Run Home\"\n\t- Added multiuser support (up to 8 users simultaneously)\n\t- Added authentication (password entered as argument or on stdin)\n\t- Added manpage\n\t- Added install/uninstall make target\n\t- Cleanup of dns code, more test cases, use check library\n\t- Changed directory structure\n\n2006-11-08: 0.3.4\n\t- Fixed handshake() buffer overflow\n\t  (Found by poplix, Secunia: SA22674 / FrSIRT/ADV-2006-4333)\n\t- Added more tests\n\t- More name parsing enhancements\n\t- Now runs on Linux/AMD64\n\t- Added setting to change server port\n\n2006-11-05: 0.3.3\n\t- Fixed possible buffer overflow\n\t  (Found by poplix, Bugtraq ID: 20883)\n\t- Reworked dns hostname encoding\n\n2006-09-11: 0.3.2\n\t- Support for NetBSD\n\t- Fixed potential security problems\n\t- Name parsing routines rewritten, added regression tests\n\t- New encoding, 25% more peak upstream throughput\n\t- New -l option to set local ip to listen to on server\n\n2006-07-11: 0.3.1\n\t- Add Mac OSX support\n\t- Add setting device name\n\t- Use compression of domain name in reply (should allow setting MTU\n\t\tapprox 200 bytes higher)\n\n2006-06-24: 0.3.0\n\t- First public release\n\t- Support for Linux, FreeBSD, OpenBSD\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2006-2020 iodine authors\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "prefix?=/usr/local\nsbindir=$(prefix)/sbin\ndatadir=$(prefix)/share\nmandir=$(datadir)/man\ndocdir=$(datadir)/doc\n\nDESTDIR=\n\nINSTALL=install\nINSTALL_FLAGS=\n\nMKDIR=mkdir\nMKDIR_FLAGS=-p\n\nRM=rm\nRM_FLAGS=-f\n\nTARGETOS = `uname`\n\nall:\n\t@$(MAKE) -C src TARGETOS=$(TARGETOS) all\n\ninstall: all\n\t$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)\n\t$(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine\n\tchmod 755 $(DESTDIR)$(sbindir)/iodine\n\t$(INSTALL) $(INSTALL_FLAGS) bin/iodined $(DESTDIR)$(sbindir)/iodined\n\tchmod 755 $(DESTDIR)$(sbindir)/iodined\n\t$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(mandir)/man8\n\t$(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(DESTDIR)$(mandir)/man8/iodine.8\n\tchmod 644 $(DESTDIR)$(mandir)/man8/iodine.8\n\t$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(docdir)/iodine\n\t$(INSTALL) $(INSTALL_FLAGS) README.md $(DESTDIR)$(docdir)/iodine/README.md\n\tchmod 644 $(DESTDIR)$(docdir)/iodine/README.md\n\nuninstall:\n\t$(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodine\n\t$(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined\n\t$(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8\n\ntest: all\n\t@echo \"!! The check library is required for compiling and running the tests\"\n\t@echo \"!! Get it at https://libcheck.github.io/check/\"\n\t@$(MAKE) -C tests TARGETOS=$(TARGETOS) all\n\nclean:\n\t@echo \"Cleaning...\"\n\t@$(MAKE) -C src clean\n\t@$(MAKE) -C tests clean\n\t@rm -rf bin iodine-latest*\n\n#Helper target for windows/android zipfiles\niodine-latest:\n\t@rm -rf iodine-latest*\n\t@mkdir -p iodine-latest\n\t@echo \"Create date: \" > iodine-latest/VERSION.txt\n\t@LANG=en_US date >> iodine-latest/VERSION.txt\n\t@echo \"Git version: \" >> iodine-latest/VERSION.txt\n\t@git rev-parse HEAD >> iodine-latest/VERSION.txt\n\t@for i in README.md CHANGELOG; do cp $$i iodine-latest/$$i.txt; done\n\t@unix2dos iodine-latest/*\n\n#non-PIE build for old android\ncross-android-old:\n\t@$(MAKE) -C src base64u.c\n\t@(cd src && ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_PLATFORM=android-3)\n\n#Position-indepedent build for modern android\ncross-android:\n\t@$(MAKE) -C src base64u.c\n\t@(cd src && ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.16.mk APP_PLATFORM=android-16)\n\niodine-latest-android.zip: iodine-latest\n\t@mv iodine-latest iodine-latest-android\n\t@mkdir -p iodine-latest-android/pre-kitkat/armeabi\n\t@mkdir -p iodine-latest-android/pre-kitkat/x86\n\t@$(MAKE) cross-android-old TARGET_ARCH_ABI=armeabi\n\t@cp src/libs/armeabi/* iodine-latest-android/pre-kitkat/armeabi\n\t@$(MAKE) cross-android-old TARGET_ARCH_ABI=x86\n\t@cp src/libs/x86/* iodine-latest-android/pre-kitkat/x86\n\t@rm -rf src/libs src/obj\n\t@mkdir -p iodine-latest-android/armeabi\n\t@mkdir -p iodine-latest-android/arm64-v8a\n\t@mkdir -p iodine-latest-android/x86\n\t@$(MAKE) cross-android TARGET_ARCH_ABI=armeabi\n\t@cp src/libs/armeabi/* iodine-latest-android/armeabi\n\t@$(MAKE) cross-android TARGET_ARCH_ABI=arm64-v8a\n\t@cp src/libs/arm64-v8a/* iodine-latest-android/arm64-v8a\n\t@$(MAKE) cross-android TARGET_ARCH_ABI=x86\n\t@cp src/libs/x86/* iodine-latest-android/x86\n\t@cp README-android.txt iodine-latest-android\n\t@zip -r iodine-latest-android.zip iodine-latest-android\n\ncross-mingw32:\n\t@$(MAKE) -C src TARGETOS=windows32 CC=i686-w64-mingw32-gcc all\n\ncross-mingw64:\n\t@$(MAKE) -C src TARGETOS=windows32 CC=x86_64-w64-mingw32-gcc all\n\niodine-latest-windows.zip: iodine-latest\n\t@mv iodine-latest iodine-latest-windows\n\t@mkdir -p iodine-latest-windows/64bit iodine-latest-windows/32bit\n\t@$(MAKE) -C src TARGETOS=windows32 CC=i686-w64-mingw32-gcc clean all\n\t@i686-w64-mingw32-strip bin/iodine*\n\t@for i in `ls bin`; do cp bin/$$i iodine-latest-windows/32bit/$$i.exe; done\n\t@cp /usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll iodine-latest-windows/32bit\n\t@$(MAKE) -C src TARGETOS=windows32 CC=x86_64-w64-mingw32-gcc clean all\n\t@x86_64-w64-mingw32-strip bin/iodine*\n\t@for i in `ls bin`; do cp bin/$$i iodine-latest-windows/64bit/$$i.exe; done\n\t@cp /usr/x86_64-w64-mingw32/sys-root/mingw/bin/zlib1.dll iodine-latest-windows/64bit\n\t@cp README-win32.txt iodine-latest-windows\n\t@zip -r iodine-latest-windows.zip iodine-latest-windows\n\n"
  },
  {
    "path": "README-android.txt",
    "content": "\r\n\r\niodine - https://code.kryo.se/iodine\r\n\r\n***********************************\r\n\r\nExtra README file for Android\r\n\r\n\r\n== Running iodine on Android:\r\n1. Get root access on your android device\r\n\r\n2. Find/build a compatible tun.ko for your specific Android kernel\r\n\r\n3. Copy tun.ko and the iodine binary to your device:\r\n   (Almost all devices need the armeabi binary. Only Intel powered\r\n   ones need the x86 build.)\r\n\r\n\t\tadb push tun.ko /data/local/tmp\r\n\t\tadb push iodine /data/local/tmp\r\n\t\tadb shell\r\n\t\tsu\r\n\t\tcd /data/local/tmp\r\n\t\tchmod 777 iodine\r\n\r\n4. Run iodine (see the man page for parameters)\r\n\r\n\t\t./iodine ...\r\n\r\nFor more information: http://blog.bokhorst.biz/5123\r\n\r\n== Building iodine for Android:\r\n1. Download and install the Android SDK and NDK\r\n\r\n2. Download and unpack the iodine sources\r\n\r\n3. Build:\r\n\tcd src\r\n\tmake base64u.h base64u.c\r\n\tndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.16.mk APP_PLATFORM=android-16\r\n\r\n   or run \"make cross-android\" in the iodine root directory.\r\n   To build for other archs, specify TARGET_ARCH_ABI:\r\n\t\t\"make cross-android TARGET_ARCH_ABI=x86\"\r\n\r\n   For older android versions (pre-kitkat), build with \"make cross-android-old\" in the\r\n   root directory, or manually like above but with APP_PLATFORM=android-3 and with\r\n   APP_BUILD_SCRIPT=Android.mk\r\n\r\n   The iodine binary ends up in src/libs/<arch>/iodine\r\n"
  },
  {
    "path": "README-win32.txt",
    "content": "\r\n\r\niodine - https://code.kryo.se/iodine\r\n\r\n***********************************\r\n\r\nExtra README file for Win32 related stuff\r\n\r\n\r\n== Running iodine on Windows:\r\n\r\n0. After iodine 0.6, you need Windows XP or newer to run.\r\n\r\n1. Install the TAP driver \r\n   https://openvpn.net/index.php/open-source/downloads.html\r\n   Download the OpenVPN TAP driver (under section Tap-windows)\r\n   Problems has been reported with the NDIS6 version (9.2x.y), use the\r\n   NDIS5 version for now if possible.\r\n\r\n2. Have at least one TAP32 interface installed. There are scripts for adding\r\n   and removing in the OpenVPN bin directory. If you have more than one\r\n   installed, use -d to specify which. Use double quotes if you have spaces,\r\n   example: iodine.exe -d \"Local Area Connection 4\" abc.ab\r\n\r\n3. Make sure the interface you want to use does not have a default gateway set.\r\n\r\n4. Run iodine/iodined as normal (see the main README file).\r\n   You may have to run it as administrator depending on user privileges.\r\n\r\n5. Enjoy!\r\n\r\n\r\n== Building on Windows:\r\nYou need:\r\n\tMinGW, MSYS, GCC, zlib\r\n\r\nThen just run make\r\n\r\n\r\n== Cross-compiling for MinGW:\r\nYou need:\r\n\tMinGW crosscompiler, crosscompiled zlib\r\n\r\nThen run \"make cross-mingw\"\r\nNote that the binaries will not get a .exe suffix\r\n\r\n\r\n== Zlib download\r\nYou can get zlib for MinGW here (both for native and crosscompile):\r\nhttps://code.kryo.se/iodine/deps/zlib.zip\r\nUnzip it in your MinGW directory on Windows or in $ROOT/usr for\r\ncross-compile.\r\n\r\n\r\n== Results of crappy Win32 API:\r\nThe following fixable limitations apply:\r\n- Server cannot read packet destination address\r\n\r\nThe following (probably) un-fixable limitations apply:\r\n- A password entered as -P argument can be shown in process list\r\n- Priviligies cannot be dropped\r\n- chroot() cannot be used\r\n- Detaching from terminal not possible\r\n- Server on windows must be run with /30 netmask\r\n- Client can only talk to server, not other clients\r\n\r\n"
  },
  {
    "path": "README.md",
    "content": "iodine - <https://code.kryo.se/iodine>\n=====================================\n\n\nThis is a piece of software that lets you tunnel IPv4 data through a DNS\nserver. This can be usable in different situations where internet access is\nfirewalled, but DNS queries are allowed.\n\n\nCOMPILING\n---------\n\nIodine has no configure script. There are two optional features for Linux\n(SELinux and systemd support) that will be enabled automatically if the\nrelevant header files are found in `/usr/include`.\n(See script at `./src/osflags`)\n\nRun `make` to compile the server and client binaries.\nRun `make install` to copy binaries and manpage to the destination directory.\nRun `make test` to compile and run the unit tests. (Requires the `check` library)\n\n\nQUICKSTART\n----------\n\nTry it out within your own LAN! Follow these simple steps:\n- On your server, run: `./iodined -f 10.0.0.1 test.com`.\n  If you already use the `10.0.0.0` network, use another internal net like\n  `172.16.0.0`.\n- Enter a password.\n- On the client, run: `./iodine -f -r 192.168.0.1 test.com`.\n  Replace `192.168.0.1` with your server's ip address.\n- Enter the same password.\n- Now the client has the tunnel ip `10.0.0.2` and the server has `10.0.0.1`.\n- Try pinging each other through the tunnel.\n- Done! :)\n\nTo actually use it through a relaying nameserver, see below.\n\n\nHOW TO USE\n----------\n\nNote: server and client are required to speak the exact same protocol. In most\ncases, this means running the same iodine version. Unfortunately, implementing\nbackward and forward protocol compatibility is usually not feasible.\n\n### Server side\nTo use this tunnel, you need control over a real domain (like `mydomain.com`),\nand a server with a public IP address to run `iodined` on. If this server\nalready runs a DNS program, change its listening port and then use `iodined`'s\n`-b` option to let `iodined` forward the DNS requests. (Note that this procedure\nis not advised in production environments, because `iodined`'s DNS forwarding\nis not completely transparent, for example zone transfers will not work.)\nAlternatively you can forward the subdomain from your DNS server to `iodined`\nwhich must then run on a different port (`-p`).\n\nThen, delegate a subdomain (say, `t1.mydomain.com`) to the iodined server.\nIf you use BIND for your domain, add two lines like these to the zone file:\n\n\tt1\t\tIN\tNS\tt1ns.mydomain.com.\t\t; note the dot!\n\tt1ns\t\tIN\tA\t10.15.213.99\n\nThe `NS` line is all that's needed to route queries for the `t1` subdomain\nto the `t1ns` server. We use a short name for the subdomain, to keep as much\nspace as possible available for the data traffic. At the end of the `NS` line\nis the name of your `iodined` server. This can be any name, pointing anywhere,\nbut in this case it's easily kept in the same zone file. It must be a name\n(not an IP address), and that name itself must have an `A` record\n(not a `CNAME`).\n\nIf your `iodined` server has a dynamic IP, use a dynamic DNS provider. Simply\npoint the `NS` line to it, and leave the `A` line out:\n\n\tt1\t\tIN\tNS\tmyname.mydyndnsprovider.com.\t; note the dot!\n\nThen reload or restart your nameserver program. Now any DNS queries for\ndomains ending in `t1.mydomain.com` will be sent to your `iodined` server.\n\nFinally start `iodined` on your server. The first argument is the IP address\ninside the tunnel, which can be from any range that you don't use yet (for\nexample `192.168.99.1`), and the second argument is the assigned domain (in this\ncase `t1.mydomain.com`). Using the `-f` option will keep iodined running in the\nforeground, which helps when testing. iodined will open a virtual interface\n(\"tun device\"), and will also start listening for DNS queries on UDP port 53.\nEither enter a password on the commandline (`-P pass`) or after the server has\nstarted. Now everything is ready for the client.\n\nIf there is a chance you'll be using an iodine tunnel from unexpected\nenvironments, start `iodined` with a `-c` option.\nResulting commandline in this example situation:\n\n\t./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com\n\n### Client side\nAll the setup is done, just start `iodine`. It takes one or two arguments, the\nfirst is the local relaying DNS server (optional) and the second is the domain\nyou used (`t1.mydomain.com`). If you don't specify the first argument, the\nsystem's current DNS setting will be consulted.\n\nIf DNS queries are allowed to any computer, you can directly give the `iodined`\nserver's address as first argument (in the example: `t1ns.mydomain.com` or\n`10.15.213.99`). In that case, it may also happen that _any_ traffic is allowed\nto the DNS port (53 UDP) of any computer. Iodine will detect this, and switch\nto raw UDP tunneling if possible. To force DNS tunneling in any case, use the\n`-r` option (especially useful when testing within your own network).\n\nThe client's tunnel interface will get an IP close to the server's (in this\ncase `192.168.99.2` or `.3` etc.) and a suitable MTU. Enter the same password as\non the server either as commandline option or after the client has started.\nUsing the `-f` option will keep the iodine client running in the foreground.\n\nResulting commandline in this example situation, adding -r forces DNS tunneling\neven if raw UDP tunneling would be possible:\n\n\t./iodine -f -P secretpassword t1.mydomain.com\n\nFrom either side, you should now be able to ping the IP address on the other\nend of the tunnel. In this case, `ping 192.168.99.1` from the iodine client, and\n`192.168.99.2` from the iodine server.\n\n\n### MISC. INFO\n\n#### IPv6\nThe data inside the tunnel is IPv4 only.\n\nThe server listens to both IPv4 and IPv6 for incoming requests by default.\nUse options `-4` or `-6` to only listen on one protocol. Raw mode will be\nattempted on the same protocol as used for the login.\n\nThe client can use IPv4 or IPv6 nameservers to connect to iodined. The relay\nnameservers will translate between protocols automatically if needed. Use\noptions `-4` or `-6` to force the client to use a specific IP version for its DNS\nqueries.\n\nIf your server is listening on IPv6 and is reachable, add an AAAA record for it\nto your DNS setup. Extending the example above would look like this:\n\n\tt1\t\tIN\tNS\tt1ns.mydomain.com.\t\t; note the dot!\n\tt1ns\t\tIN\tA\t10.15.213.99\n\tt1ns\t\tIN\tAAAA\t2001:db8::1001:99\n\n#### Routing\nIt is possible to route all traffic through the DNS tunnel. To do this, first\nadd a host route to the nameserver used by iodine over the wired/wireless\ninterface with the default gateway as gateway. Then replace the default\ngateway with the iodined server's IP address inside the DNS tunnel, and\nconfigure the server to do NAT.\n\nHowever, note that the tunneled data traffic is not encrypted at all, and can\nbe read and changed by external parties relatively easily. For maximum\nsecurity, run a VPN through the DNS tunnel (=double tunneling), or use secure\nshell (SSH) access, possibly with port forwarding. The latter can also be used\nfor web browsing, when you run a web proxy (for example Privoxy) on your\nserver.\n\n#### Testing\nThe `iodined` server replies to `NS` requests sent for subdomains of the tunnel\ndomain. If your iodined subdomain is `t1.mydomain.com`, send a `NS` request for\n`foo123.t1.mydomain.com` to see if the delegation works.\n`dig` is a good tool for this:\n\n\t% dig -t NS foo123.t1.mydomain.com\n\tns.io.citronna.de.\n\nAlso, the iodined server will answer requests starting with 'z' for any of the\nsupported request types, for example:\n\n\tdig -t TXT z456.t1.mydomain.com\n\tdig -t SRV z456.t1.mydomain.com\n\tdig -t CNAME z456.t1.mydomain.com\n\nThe reply should look like garbled text in all these cases.\n\n#### Mac OS X\nOn Mac OS X 10.6 and later, iodine supports the native utun devices built into\nthe OS - use `-d utunX`.\n\n\nOperational info\n----------------\n\nThe DNS-response fragment size is normally autoprobed to get maximum bandwidth.\nTo force a specific value (and speed things up), use the `-m` option.\n\nThe DNS hostnames are normally used up to their maximum length, 255 characters.\nSome DNS relays have been found that answer full-length queries rather\nunreliably, giving widely varying (and mostly very bad) results of the\nfragment size autoprobe on repeated tries. In these cases, use the `-M` switch\nto reduce the DNS hostname length to, for example 200 characters, which makes\nthese DNS relays much more stable. This is also useful on some “de-optimizing”\nDNS relays that stuff the response with two full copies of the query, leaving\nvery little space for downstream data (also not capable of EDNS0). The `-M`\nswitch can trade some upstream bandwidth for downstream bandwidth. Note that\nthe minimum `-M` value is about 100, since the protocol can split packets (1200\nbytes max) in only 16 fragments, requiring at least 75 real data bytes per\nfragment.\n\nThe upstream data is sent gzipped encoded with Base32; or Base64 if the relay\nserver supports mixed case and `+` in domain names; or Base64u if `_` is\nsupported instead; or Base128 if high-byte-value characters are supported.\nThis upstream encoding is autodetected. The DNS protocol allows one query per\npacket, and one query can be max 256 chars. Each domain name part can be max\n63 chars. So your domain name and subdomain should be as short as possible to\nallow maximum upstream throughput.\n\nSeveral DNS request types are supported, with the `NULL` and `PRIVATE` types\nexpected to provide the largest downstream bandwidth. The `PRIVATE` type uses\nvalue 65399 in the private-use range. Other available types are `TXT`, `SRV`,\n`MX`, `CNAME` and `A` (returning `CNAME`), in decreasing bandwidth order.\nNormally the “best” request type is autodetected and used. However, DNS relays\nmay impose limits on for example NULL and TXT, making SRV or MX actually the best\nchoice. This is not autodetected, but can be forced using the `-T` option.\nIt is advisable to try various alternatives especially when the autodetected\nrequest type provides a downstream fragment size of less than 200 bytes.\n\nNote that `SRV`, `MX` and `A` (returning `CNAME`) queries may/will cause\nadditional lookups by \"smart\" caching nameservers to get an actual IP address,\nwhich may either slow down or fail completely.\n\nDNS responses for non-`NULL/PRIVATE` queries can be encoded with the same set of\ncodecs as upstream data. This is normally also autodetected, but no fully\nexhaustive tests are done, so some problems may not be noticed when selecting\nmore advanced codecs. In that case, you'll see failures/corruption in the\nfragment size autoprobe. In particular, several DNS relays have been found that\nchange replies returning hostnames (`SRV`, `MX`, `CNAME`, `A`) to lowercase only\nwhen that hostname exceeds ca. 180 characters. In these and similar cases, use\nthe `-O` option to try other downstream codecs; Base32 should always work.\n\nNormal operation now is for the server to _not_ answer a DNS request until\nthe next DNS request has come in, a.k.a. being “lazy”. This way, the server\nwill always have a DNS request handy when new downstream data has to be sent.\nThis greatly improves (interactive) performance and latency, and allows to\nslow down the quiescent ping requests to 4 second intervals by default, and\npossibly much slower. In fact, the main purpose of the pings now is to force\na reply to the previous ping, and prevent DNS server timeouts (usually at\nleast 5-10 seconds per RFC1035). Some DNS servers are more impatient and will\ngive SERVFAIL errors (timeouts) in periods without tunneled data traffic. All\ndata should still get through in these cases, but `iodine` will reduce the ping\ninterval to 1 second anyway (-I1) to reduce the number of error messages. This\nmay not help for very impatient DNS relays like `dnsadvantage.com` (ultradns),\nwhich time out in 1 second or even less. Yet data will still get trough, and\nyou can ignore the `SERVFAIL` errors.\n\nIf you are running on a local network without any DNS server in-between, try\n`-I 50` (iodine and iodined close the connection after 60 seconds of silence).\nThe only time you'll notice a slowdown, is when DNS reply packets go missing;\nthe `iodined` server then has to wait for a new ping to re-send the data. You can\nspeed this up by generating some upstream traffic (keypress, ping). If this\nhappens often, check your network for bottlenecks and/or run with `-I1`.\n\nThe delayed answering in lazy mode will cause some “carrier grade” commercial\nDNS relays to repeatedly re-send the same DNS query to the iodined server.\nIf the DNS relay is actually implemented as a pool of parallel servers,\nduplicate requests may even arrive from multiple sources. This effect will\nonly be visible in the network traffic at the `iodined` server, and will not\naffect the client's connection. Iodined will notice these duplicates, and send\nthe same answer (when its time has come) to both the original query and the\nlatest duplicate. After that, the full answer is cached for a short while.\nDelayed duplicates that arrive at the server even later, get a reply that the\niodine client will ignore (if it ever arrives there).\n\nIf you have problems, try inspecting the traffic with network monitoring tools\nlike tcpdump or ethereal/wireshark, and make sure that the relaying DNS server\nhas not cached the response. A cached error message could mean that you\nstarted the client before the server. The `-D` (and `-DD`) option on the server\ncan also show received and sent queries.\n\n\nTIPS & TRICKS\n-------------\n\nIf your port 53 is taken on a specific interface by an application that does\nnot use it, use `-p` on iodined to specify an alternate port (like `-p 5353`)\nand use for instance iptables (on Linux) to forward the traffic:\n\n\tiptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353\n\n(Sent in by Tom Schouten)\n\nIodined will reject data from clients that have not been active (data/pings)\nfor more than 60 seconds. Similarly, iodine will exit when no downstream\ndata has been received for 60 seconds. In case of a long network outage or\nsimilar, just restart iodine (re-login), possibly multiple times until you get\nyour old IP address back. Once that's done, just wait a while, and you'll\neventually see the tunneled TCP traffic continue to flow from where it left\noff before the outage.\n\nWith the introduction of the downstream packet queue in the server, its memory\nusage has increased with several megabytes in the default configuration.\nFor use in low-memory environments (e.g. running on your DSL router), you can\ndecrease USERS and undefine OUTPACKETQ_LEN in user.h without any ill conse-\nquence, assuming at most one client will be connected at any time. A small\nDNSCACHE_LEN is still advised, preferably 2 or higher, however you can also\nundefine it to save a few more kilobytes.\n\nOne iodine server can handle multiple domains. Set up different NS records\non the same domain all pointing to the same host, and use a wildcard\nat the start of the topdomain argument (example `*.mydomain.com`). iodine\nwill accept tunnel traffic for all domains matching that pattern. The wildcard\nhas to be at the start of the topdomain argument and be followed by a dot.\n\n\nPERFORMANCE\n-----------\n\nThis section tabulates some performance measurements. To view properly, use\na fixed-width font like Courier.\n\nMeasurements were done in protocol 00000502 in lazy mode; upstream encoding\nalways Base128; `iodine -M255`; `iodined -m1130`. Network conditions were not\nextremely favorable; results are not benchmarks but a realistic indication of\nreal-world performance that can be expected in similar situations.\n\nUpstream/downstream throughput was measured by `scp`'ing a file previously\nread from `/dev/urandom` (i.e. incompressible), and measuring size with\n`ls -l ; sleep 30 ; ls -l` on a separate non-tunneled connection. Given the\nlarge `scp` block size of 16 kB, this gives a resolution of 4.3 kbit/s, which\nexplains why some values are exactly equal.\nPing round-trip times measured with `ping -c100`, presented are average rtt\nand mean deviation (indicating spread around the average), in milliseconds.\n\n\n### Situation 1: `Laptop  ->   Wifi AP   ->  Home server  ->  DSL provider  ->  Datacenter`\n\n\t iodine    DNS \"relay\"        bind9           DNS cache        iodined\n\n\t                        downstr.  upstream downstr.  ping-up       ping-down\n\t                        fragsize   kbit/s   kbit/s  avg +/-mdev   avg +/-mdev\n\t-----------------------------------------------------------------------------\n\n\tiodine -> Wifi AP :53\n\t  -Tnull (= -Oraw)           982    43.6    131.0   28.0    4.6   26.8    3.4\n\n\tiodine -> Home server :53\n\t  -Tnull (= -Oraw)          1174    48.0    305.8   26.6    5.0   26.9    8.4\n\n\tiodine -> DSL provider :53\n\t  -Tnull (= -Oraw)          1174    56.7    367.0   20.6    3.1   21.2    4.4\n\t  -Ttxt -Obase32             730    56.7    174.7*\n\t  -Ttxt -Obase64             874    56.7    174.7\n\t  -Ttxt -Obase128           1018    56.7    174.7\n\t  -Ttxt -Oraw               1162    56.7    358.2\n\t  -Tsrv -Obase128            910    56.7    174.7\n\t  -Tcname -Obase32           151    56.7     43.6\n\t  -Tcname -Obase128          212    56.7     52.4\n\n\tiodine -> DSL provider :53\n\t  wired (no Wifi) -Tnull    1174    74.2    585.4   20.2    5.6   19.6    3.4\n\n\t [174.7* : these all have 2frag/packet]\n\n\n### Situation 2: `Laptop  ->  Wifi+vpn / wired  ->  Home server`\n\n\t iodine                            iodined\n\n\t                        downstr.  upstream downstr.  ping-up       ping-down\n\t                        fragsize   kbit/s   kbit/s  avg +/-mdev   avg +/-mdev\n\t-----------------------------------------------------------------------------\n\n\twifi + openvpn  -Tnull      1186   166.0   1022.3    6.3    1.3    6.6    1.6\n\n\twired  -Tnull               1186   677.2   2464.1    1.3    0.2    1.3    0.1\n\n\n### Notes\n\nPerformance is strongly coupled to low ping times, as iodine requires\nconfirmation for every data fragment before moving on to the next. Allowing\nmultiple fragments in-flight like TCP could possibly increase performance,\nbut it would likely cause serious overload for the intermediary DNS servers.\nThe current protocol scales performance with DNS responsivity, since the\nDNS servers are on average handling at most one DNS request per client.\n\n\nPORTABILITY\n-----------\n\niodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD\n(ia64, x86), OpenBSD (x86), NetBSD (x86), MacOS X (ppc and x86, with\n<http://tuntaposx.sourceforge.net/>). and Windows (with OpenVPN TAP32 driver, see\nwin32 readme file).  It should be easy to port to other unix-like systems that\nhave TUN/TAP tunneling support. Let us know if you get it to run on other\nplatforms.\n\n\nTHE NAME\n--------\n\nThe name iodine was chosen since it starts with IOD (IP Over DNS) and since\niodine has atomic number 53, which happens to be the DNS port number.\n\n\nTHANKS\n------\n\n- To kuxien for FreeBSD and OS X testing\n- To poplix for code audit\n\n\nAUTHORS & LICENSE\n-----------------\n\nCopyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>, 2006-2009 Bjorn\nAndersson <flex@kryo.se>. Also major contributions by Anne Bezemer.\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n\n\nMD5 implementation by L. Peter Deutsch (license and source in `src/md5.[ch]`)\nCopyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.\n"
  },
  {
    "path": "doc/iodine-server.service",
    "content": "[Unit]\nDescription=Iodine Server\nAfter=local-fs.target network.target\n\n[Service]\nEnvironmentFile=-/etc/sysconfig/iodine-server\nExecStart=/usr/local/bin/iodined -i 30 -f $OPTIONS\nStandardOutput=syslog\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "doc/iodine-server.socket",
    "content": "[Unit]\nDescription=Iodine socket\n\n[Socket]\nListenDatagram=53\nListenDatagram=0.0.0.0:53\nBindIPv6Only=ipv6-only\n\n[Install]\nWantedBy=sockets.target\n"
  },
  {
    "path": "doc/iodine.te",
    "content": "# Sample post-initialization SELinux policy for Iodine\npolicy_module(iodine, 1.1)\n\nrequire {\n\ttype init_t;\n\ttype initrc_t;\n\ttype unconfined_t;\n\ttype unlabeled_t;\n\tclass udp_socket { read write };\n\tclass rawip_socket { write read };\n\tclass association recvfrom;\n\tclass unix_dgram_socket { create connect };\n}\n\ntype iodine_t;\ndomain_type(iodine_t)\ndomain_dyntrans_type(initrc_t)\nallow initrc_t iodine_t:process dyntransition;\n\nallow iodine_t unconfined_t:udp_socket { read write };\nallow iodine_t unconfined_t:rawip_socket { write read };\nallow iodine_t unlabeled_t:association recvfrom;\nallow iodine_t self:unix_dgram_socket { create connect };\ncorenet_raw_receive_generic_node(iodine_t)\ncorenet_rw_tun_tap_dev(iodine_t)\n"
  },
  {
    "path": "doc/proto_00000402.txt",
    "content": "Detailed specification of protocol in version 00000402\n======================================================\n\nCMC = 2 byte Cache Miss Counter, increased every time it is used\n\nVersion:\nClient sends:\n\tFirst byte v or V\n\tRest encoded with base32:\n\t4 bytes big endian protocol version\n\tCMC\nServer replies:\n\t4 chars:\n\t\tVACK (version ok), followed by login challenge\n\t\tVNAK (version differs), followed by server protocol version\n\t\tVFUL (server has no free slots), followed by max users\n\t4 byte value: means login challenge/server protocol version/max users\n\t1 byte userid of the new user, or any byte if not VACK\n\t\nLogin:\nClient sends:\n\tFirst byte l or L\n\tRest encoded with base32:\n\t1 byte userid\n\t16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge)\n\tCMC\nServer replies:\n\tLNAK means not accepted\n\tx.x.x.x-y.y.y.y-mtu means accepted (server ip, client ip, mtu)\n\nCase check:\nClient sends: \n\tFirst byte z or Z\n\tLots of data that should not be decoded\nServer replies:\n\tThe requested domain copied raw\n\nData:\nData header:\n\t 321 0 \n\t+---+-+\n\t|UUU|L|\n\t+---+-+\n\nUUU = Userid\nL = Last fragment in packet flag\n\nFirst byte is the header, 4 bits coded as hex in ASCII. \nFollowed by data encoded with Base32.\n\nPing:\nClient sends:\n\tFirst byte p or P\n\tRest encoded with Base32:\n\t1 byte userid\n\tCMC\n\nThe server response to Ping and Data packets is a DNS NULL type response:\nIf server has nothing to send, data length is 0 bytes.\nIf server has a packet to send, data length is set and the data is a full raw\nunencoded ip packet, prefixed with 32 bits tun data.\n"
  },
  {
    "path": "doc/proto_00000500.txt",
    "content": "Detailed specification of protocol in version 00000500\n======================================================\n\nCMC = 2 byte Cache Miss Counter, increased every time it is used\n\nVersion:\nClient sends:\n\tFirst byte v or V\n\tRest encoded with base32:\n\t4 bytes big endian protocol version\n\tCMC\nServer replies:\n\t4 chars:\n\t\tVACK (version ok), followed by login challenge\n\t\tVNAK (version differs), followed by server protocol version\n\t\tVFUL (server has no free slots), followed by max users\n\t4 byte value: means login challenge/server protocol version/max users\n\t1 byte userid of the new user, or any byte if not VACK\n\t\nLogin:\nClient sends:\n\tFirst byte l or L\n\tRest encoded with base32:\n\t1 byte userid\n\t16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge)\n\tCMC\nServer replies:\n\tLNAK means not accepted\n\tx.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits)\n\nCase check:\nClient sends: \n\tFirst byte z or Z\n\tLots of data that should not be decoded\nServer replies:\n\tThe requested domain copied raw\n\nSwitch codec:\nClient sends:\n\tFirst byte s or S\n\t5 bits coded as Base32 char, meaning userid\n\t5 bits coded as Base32 char, with value 5 or 6, representing number of raw\n\tbits per encoded byte\nServer sends:\n\tName of codec if accepted. After this all upstream data packets must \n\tbe encoded with the new codec.\n\tBADCODEC if not accepted. Client must then revert to Base32\n\nProbe downstream fragment size:\nClient sends:\n\tFirst byte r or R\n\t15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF\n\t\tmeaning 4 bits userid, 11 bits fragment size\n\tThen follows a long random query which contents does not matter\nServer sends:\n\tRequested number of bytes as a response. The first two bytes contains\n\tthe requested length. Rest of message can be any data.\n\tBADFRAG if requested length not accepted.\n\nSet downstream fragment size:\nClient sends:\n\tFirst byte n or N\n\tRest encoded with base32:\n\t1 byte userid\n\t2 bytes new downstream fragment size\n\tCMC\nServer sends:\n\t2 bytes new downstream fragment size. After this all downstream\n\tpayloads will be max (fragsize + 2) bytes long.\n\tBADFRAG if not accepted.\n\nData:\nUpstream data header:\n\t 3210 432 10 43 210 4321 0\n\t+----+---+--+--+---+----+-+\n\t|UUUU|SSS|FF|FF|DDD|GGGG|L|\n\t+----+---+--+--+---+----+-+\n\nDownstream data header:\n\t 7 654 3210 765 4321 0\n\t+-+---+----+---+----+-+\n\t|C|SSS|FFFF|DDD|GGGG|L|\n\t+-+---+----+---+----+-+\n\nUUUU = Userid\nL = Last fragment in packet flag\nSS = Upstream packet sequence number\nFFFF = Upstream fragment number\nDDD = Downstream packet sequence number\nGGGG = Downstream fragment number\nC = Compression enabled for downstream packet\n\nUpstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes \nBase32 encoded header, then comes the payload data, encoded with chosen codec.\n\nDownstream data starts with 2 byte header. Then payload data, which may be\ncompressed.\n\nPing:\nClient sends:\n\tFirst byte p or P\n\tRest encoded with Base32:\n\t1 byte with 4 bits userid\n\t1 byte with:\n\t\t3 bits downstream seqno\n\t\t4 bits downstream fragment\n\tCMC\n\nThe server response to Ping and Data packets is a DNS NULL type response:\nIf server has nothing to send, data length is 0 bytes.\nIf server has something to send, it will send a downstream data packet, \nprefixed with 2 bytes header as shown above.\n"
  },
  {
    "path": "doc/proto_00000502.txt",
    "content": "Detailed specification of protocol in version 00000502\n======================================================\n\nNote: work in progress!!\n\n======================================================\n1. DNS protocol\n======================================================\n\nQuick alphabetical index / register:\n\t0-9\tData packet\n\tA-F\tData packet\n\tI\tIP address\n\tL\tLogin\n\tN\tDownstream fragsize\t(NS.topdomain A-type reply)\n\tO\tOptions\n\tP\tPing\n\tR\tDownstream fragsize probe\n\tS\tSwitch upstream codec\n\tV\tVersion\n\tW\t\t\t\t(WWW.topdomain A-type reply)\n\tY\tDownstream codec check\n\tZ\tUpstream codec check\n\n\nCMC = 2 byte Cache Miss Counter, increased every time it is used\n\nVersion:\nClient sends:\n\tFirst byte v or V\n\tRest encoded with base32:\n\t4 bytes big endian protocol version\n\tCMC\nServer replies:\n\t4 chars:\n\t\tVACK (version ok), followed by login challenge\n\t\tVNAK (version differs), followed by server protocol version\n\t\tVFUL (server has no free slots), followed by max users\n\t4 byte value: means login challenge/server protocol version/max users\n\t1 byte userid of the new user, or any byte if not VACK\n\nLogin:\nClient sends:\n\tFirst byte l or L\n\tRest encoded with base32:\n\t1 byte userid\n\t16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge)\n\tCMC\nServer replies:\n\tLNAK means not accepted\n\tx.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits)\n\nIP Request: (for where to try raw login)\nClient sends:\n\tFirst byte i or I\n\t5 bits coded as Base32 char, meaning userid\n\tCMC as 3 Base32 chars\nServer replies\n\tBADIP if bad userid\n\tFirst byte I\n\tThen comes external IP address of iodined server\n\tas 4 bytes (IPv4) or 16 bytes (IPv6)\n\nUpstream codec check / bounce:\nClient sends:\n\tFirst byte z or Z\n\tLots of data that should not be decoded\nServer replies:\n\tThe requested domain copied raw, in the lowest-grade downstream codec\n\tavailable for the request type.\n\nDownstream codec check:\nClient sends:\n\tFirst byte y or Y\n\t1 char, meaning downstream codec to use\n\t5 bits coded as Base32 char, meaning check variant\n\tCMC as 3 Base32 chars\n\tPossibly extra data, depending on check variant\nServer sends:\n\tData encoded with requested downstream codec; data content depending\n\ton check variant number.\n\tBADCODEC if requested downstream codec not available.\n\tBADLEN if check variant is not available, or problem with extra data.\n\n\tDownstream codec chars are same as in 'O' Option request, below.\n\n\tCheck variants:\n\t1: Send encoded DOWNCODECCHECK1 string as defined in encoding.h\n\n\t(Other variants reserved; possibly variant that sends a decoded-encoded\n\tcopy of Base32-encoded extra data in the request)\n\nSwitch codec:\nClient sends:\n\tFirst byte s or S\n\t5 bits coded as Base32 char, meaning userid\n\t5 bits coded as Base32 char, representing number of raw bits per\n\tencoded byte:\n\t\t5: Base32   (a-z0-5)\n\t\t6: Base64   (a-zA-Z0-9+-)\n\t\t26: Base64u (a-zA-Z0-9_-)\n\t\t7: Base128  (a-zA-Z0-9\\274-\\375)\n\tCMC as 3 Base32 chars\nServer sends:\n\tName of codec if accepted. After this all upstream data packets must\n\tbe encoded with the new codec.\n\tBADCODEC if not accepted. Client must then revert to previous codec\n\tBADLEN if length of query is too short\n\nOptions:\nClient sends:\n\tFirst byte o or O\n\t5 bits coded as Base32 char, meaning userid\n\t1 char, meaning option\n\tCMC as 3 Base32 chars\nServer sends:\n\tFull name of option if accepted. After this, option immediately takes\n\teffect in server.\n\tBADCODEC if not accepted. Previous situation remains.\n\tAll options affect only the requesting client.\n\n\tOption chars:\n\tt or T: Downstream encoding Base32, for TXT/CNAME/A/MX (default)\n\ts or S: Downstream encoding Base64, for TXT/CNAME/A/MX\n\tu or U: Downstream encoding Base64u, for TXT/CNAME/A/MX\n\tv or V: Downstream encoding Base128, for TXT/CNAME/A/MX\n\tr or R: Downstream encoding Raw, for PRIVATE/TXT/NULL (default for\n\t\tPRIVATE and NULL)\n\tIf codec unsupported for request type, server will use Base32; note\n\tthat server will answer any mix of request types that a client sends.\n\tServer may disregard this option; client must always use the downstream\n\tencoding type indicated in every downstream DNS packet.\n\n\tl or L: Lazy mode, server will keep one request unanswered until the\n\tnext one comes in. Applies only to data transfer; handshake is always\n\tanswered immediately.\n\ti or I: Immediate (non-lazy) mode, server will answer all requests\n\t(nearly) immediately.\n\nProbe downstream fragment size:\nClient sends:\n\tFirst byte r or R\n\t15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF\n\t\tmeaning 4 bits userid, 11 bits fragment size\n\tThen follows a long random query which contents does not matter\nServer sends:\n\tRequested number of bytes as a response. The first two bytes contain\n\tthe requested length. The third byte is 107 (0x6B). The fourth byte\n\tis a random value, and each following byte is incremented with 107.\n\tThis is checked by the client to determine corruption.\n\tBADFRAG if requested length not accepted.\n\nSet downstream fragment size:\nClient sends:\n\tFirst byte n or N\n\tRest encoded with base32:\n\t1 byte userid\n\t2 bytes new downstream fragment size\n\tCMC\nServer sends:\n\t2 bytes new downstream fragment size. After this all downstream\n\tpayloads will be max (fragsize + 2) bytes long.\n\tBADFRAG if not accepted.\n\nData:\nUpstream data header:\n\t 3210 432 10 43 210 4321 0 43210\n\t+----+---+--+--+---+----+-+-----+\n\t|UUUU|SSS|FF|FF|DDD|GGGG|L|UDCMC|\n\t+----+---+--+--+---+----+-+-----+\n\nDownstream data header:\n\t 7 654 3210 765 4321 0\n\t+-+---+----+---+----+-+\n\t|C|SSS|FFFF|DDD|GGGG|L|\n\t+-+---+----+---+----+-+\n\nUUUU = Userid\nL = Last fragment in packet flag\nSS = Upstream packet sequence number\nFFFF = Upstream fragment number\nDDD = Downstream packet sequence number\nGGGG = Downstream fragment number\nC = Compression enabled for downstream packet\nUDCMC = Upstream Data CMC, 36 steps a-z0-9, case-insensitive\n\nUpstream data packet starts with 1 byte ASCII hex coded user byte; then 3 bytes\nBase32 encoded header; then 1 char data-CMC; then comes the payload data,\nencoded with the chosen upstream codec.\n\nDownstream data starts with 2 byte header. Then payload data, which may be\ncompressed.\n\nIn NULL and PRIVATE responses, downstream data is always raw. In all other\nresponse types, downstream data is encoded (see Options above).\nEncoding type is indicated by 1 prefix char:\nTXT:\n\tEnd result is always DNS-chopped (series of len-prefixed strings\n\t<=255 bytes)\n\tt or T: Base32\t encoded before chop, decoded after un-chop\n\ts or S: Base64\t encoded before chop, decoded after un-chop\n\tu or U: Base64u\t encoded before chop, decoded after un-chop\n\tv or V: Base128\t encoded before chop, decoded after un-chop\n\tr or R: Raw\t no encoding, only DNS-chop\nSRV/MX/CNAME/A:\n\th or H: Hostname encoded with Base32\n\ti or I: Hostname encoded with Base64\n\tj or J: Hostname encoded with Base64u\n\tk or K: Hostname encoded with Base128\nSRV and MX may reply with multiple hostnames, each encoded separately. Each\nhas a 10-multiple priority, and encoding/decoding is done in strictly\nincreasing priority sequence 10, 20, 30, etc. without gaps. Note that some DNS\nrelays will shuffle the answer records in the response.\n\nPing:\nClient sends:\n\tFirst byte p or P\n\tRest encoded with Base32:\n\t1 byte with 4 bits userid\n\t1 byte with:\n\t\t3 bits downstream seqno\n\t\t4 bits downstream fragment\n\tCMC\n\nThe server response to Ping and Data packets is a DNS NULL/TXT/.. type response,\nalways starting with the 2 bytes downstream data header as shown above.\nIf server has nothing to send, no data is added after the header.\nIf server has something to send, it will add the downstream data packet\n(or some fragment of it) after the header.\n\n\n\"Lazy-mode\" operation\n=====================\n\nClient-server DNS traffic sequence has been reordered to provide increased\n(interactive) performance and greatly reduced latency.\n\nIdea taken from Lucas Nussbaum's slides (24th IFIP International Security\nConference, 2009) at http://www.loria.fr/~lnussbau/tuns.html. Current\nimplementation is original to iodine, no code or documentation from any other\nproject was consulted during development.\n\nServer:\nUpstream data is acked immediately*, to keep the slow upstream data flowing\nas fast as possible (client waits for ack to send next frag).\n\nUpstream pings are answered _only_ when 1) downstream data arrives from tun,\nOR 2) new upstream ping/data arrives from client.\nIn most cases, this means we answer the previous DNS query instead of the\ncurrent one. The current query is kept in queue and used as soon as\ndownstream data has to be sent.\n\n*: upstream data ack is usually done as reply on the previous ping packet,\nand the upstream-data packet itself is kept in queue.\n\nClient:\nDownstream data is acked immediately, to keep it flowing fast (includes a\nping after last downstream frag).\n\nAlso, after all available upstream data is sent & acked by the server (which\nin some cases uses up the last query), send an additional ping to prime the\nserver for the next downstream data.\n\n\n======================================================\n2. Raw UDP protocol\n======================================================\n\nAll Raw UDP protcol messages start with a 3 byte header: 0x10d19e\nThis is not the start of a valid DNS message so it is easy to identify.\nThe fourth byte contains the command and the user id.\n\n\t 7654 3210\n\t+----+----+\n\t|CCCC|UUUU|\n\t+----+----+\n\nLogin message (command = 1):\nThe header is followed by a MD5 hash with the same password as in the DNS\nlogin. The client starts the raw mode by sending this message, and uses\nthe login challenge +1, and the server responds using the login challenge -1.\nAfter the login message has been exchanged, both the server and the client\nswitch to raw udp mode for the rest of the connection.\n\nData message (command = 2):\nAfter the header comes the payload data, which may be compressed.\n\nPing message (command = 3):\nSent from client to server and back to keep session open. Has no payload.\n\n"
  },
  {
    "path": "man/iodine.8",
    "content": ".\\\" groff -man -Tascii iodine.8\n.TH IODINE 8 \"APR 2023\" \"User Manuals\"\n.SH NAME\niodine, iodined \\- tunnel IPv4 over DNS\n.SH SYNOPSIS\n.B iodine [-v]\n\n.B iodine [-h]\n\n.B iodine [-4] [-6] [-f] [-r] [-u\n.I user\n.B ] [-P\n.I password\n.B ] [-m\n.I fragsize\n.B ] [-t\n.I chrootdir\n.B ] [-d\n.I device\n.B ] [-R\n.I rdomain\n.B ] [-m\n.I fragsize\n.B ] [-M\n.I namelen\n.B ] [-z\n.I context\n.B ] [-F\n.I pidfile\n.B ] [-T\n.I dnstype\n.B ] [-O\n.I downenc\n.B ] [-L\n.I 0|1\n.B ] [-I\n.I interval\n.B ]\n.B [\n.I nameserver\n.B ]\n.I topdomain\n\n.B iodined [-v]\n\n.B iodined [-h]\n\n.B iodined [-4] [-6] [-c] [-s] [-f] [-D] [-u\n.I user\n.B ] [-t\n.I chrootdir\n.B ] [-d\n.I device\n.B ] [-m\n.I mtu\n.B ] [-l\n.I listen_ip4\n.B ] [-L\n.I listen_ip6\n.B ] [-p\n.I port\n.B ] [-n\n(\n.B auto\n|\n.I external_ip\n)\n.B ] [-b\n.I dnsport\n.B ] [-P\n.I password\n.B ] [-z\n.I context\n.B ] [-F\n.I pidfile\n.B ] [-i\n.I max_idle_time\n.B ]\n.I tunnel_ip\n.B [\n.I /netmask\n.B ]\n.I topdomain\n.SH DESCRIPTION\n.B iodine\nlets you tunnel IPv4 data through a DNS\nserver. This can be useful in situations where Internet access is firewalled,\nbut DNS queries are allowed. It needs a TUN/TAP device to operate. The\nbandwidth is asymmetrical,\nwith a measured maximum of 680 kbit/s upstream and 2.3 Mbit/s\ndownstream in a wired LAN test network.\nRealistic sustained throughput on a Wifi network using a carrier-grade\nDNS cache has been measured at some 50 kbit/s upstream and over 200 kbit/s\ndownstream.\n.B iodine\nis the client application,\n.B iodined\nis the server.\n\nNote: server and client are required to speak the exact same protocol. In most\ncases, this means running the same iodine version. Unfortunately, implementing\nbackward and forward protocol compatibility is usually not feasible.\n.SH OPTIONS\n.SS Common Options:\n.TP\n.B -v\nPrint version info and exit.\n.TP\n.B -h\nPrint usage info and exit.\n.TP\n.B -f\nKeep running in foreground.\n.TP\n.B -4\nForce/allow only IPv4 DNS queries\n.TP\n.B -6\nForce/allow only IPv6 DNS queries\n.TP\n.B -u user\nDrop privileges and run as user 'user' after setting up tunnel.\n.TP\n.B -t chrootdir\nChroot to 'chrootdir' after setting up tunnel.\n.TP\n.B -d device\nUse the TUN device 'device' instead of the normal one, which is dnsX on Linux\nand otherwise tunX. On Mac OS X 10.6, this can also be utunX, which will attempt\nto use an utun device built into the OS.\n.TP\n.B -P password\nUse 'password' to authenticate. If not used,\n.B stdin\nwill be used as input. Only the first 32 characters will be used.\n.TP\n.B -z context\nApply SELinux 'context' after initialization.\n.TP\n.B -F pidfile\nCreate 'pidfile' and write process id in it.\n.SS Client Options:\n.TP\n.B -r\nSkip raw UDP mode. If not used, iodine will try getting the public IP address\nof the iodined host and test if it is reachable directly. If it is, traffic\nwill be sent to the server instead of the DNS relay.\n.TP\n.B -R rdomain\nUse OpenBSD routing domain 'rdomain' for the DNS connection.\n.TP\n.B -m fragsize\nForce maximum downstream fragment size. Not setting this will cause the\nclient to automatically probe the maximum accepted downstream fragment size.\n.TP\n.B -M namelen\nMaximum length of upstream hostnames, default 255.\nUsable range ca. 100 to 255.\nUse this option to scale back upstream bandwidth in favor of downstream\nbandwidth.\nAlso useful for DNS servers that perform unreliably when using full-length\nhostnames, noticeable when fragment size autoprobe returns very\ndifferent results each time.\n.TP\n.B -T dnstype\nDNS request type override.\nBy default, autodetection will probe for working DNS request types, and\nwill select the request type that is expected to provide the most bandwidth.\nHowever, it may turn out that a DNS relay imposes limits that skew the\npicture, which may lead to an \"unexpected\" DNS request type providing\nmore bandwidth.\nIn that case, use this option to override the autodetection.\nIn (expected) decreasing bandwidth order, the supported DNS request types are:\n.IR NULL ,\n.IR PRIVATE ,\n.IR TXT ,\n.IR SRV ,\n.IR MX ,\n.I CNAME\nand\n.I A\n(returning CNAME).\nNote that\n.IR SRV ,\n.I MX\nand\n.I A\nmay/will cause additional lookups by \"smart\" caching\nnameservers to get an actual IP address, which may either slow down or fail\ncompletely. The\n.IR PRIVATE\ntype uses value 65399 (in the 'private use' range) and requires servers\nimplementing RFC 3597.\n.TP\n.B -O downenc\nForce downstream encoding type for all query type responses except NULL.\nDefault is autodetected, but may not spot all problems for the more advanced\ncodecs.\nUse this option to override the autodetection.\n.I Base32\nis the lowest-grade codec and should always work; this is used when\nautodetection fails.\n.I Base64\nprovides more bandwidth, but may not work on all nameservers.\n.I Base64u\nis equal to Base64 except in using underscore ('_')\ninstead of plus sign ('+'), possibly working where\n.I Base64\ndoes not.\n.I Base128\nuses high byte values (mostly accented letters in iso8859-1),\nwhich might work with some nameservers.\nFor TXT queries,\n.I Raw\nwill provide maximum performance, but this will only work if the nameserver\npath is fully 8-bit-clean for responses that are assumed to be \"legible text\".\n.TP\n.B -L 0|1\nLazy-mode switch.\n\\-L1 (default): Use lazy mode for improved performance and decreased latency.\nA very small minority of DNS relays appears to be unable to handle the\nlazy mode traffic pattern, resulting in no or very little data coming through.\nThe iodine client will detect this and try to switch back to legacy mode,\nbut this may not always work.\nIn these situations use \\-L0 to force running in legacy mode\n(implies \\-I1).\n.TP\n.B -I interval\nMaximum interval between requests (pings) so that intermediate DNS\nservers will not time out. Default is 4 in lazy mode, which will work\nfine in most cases. When too many SERVFAIL errors occur, iodine\nwill automatically reduce this to 1.\nTo get absolute minimum DNS traffic,\nincrease well above 4, but not so high that SERVFAIL errors start to occur.\nThere are some DNS relays with very small timeouts,\nnotably dnsadvantage.com (ultradns), that will give\nSERVFAIL errors even with \\-I1; data will still get trough,\nand these errors can be ignored.\nMaximum useful value is 59, since iodined will close a client's\nconnection after 60 seconds of inactivity.\n.SS Server Options:\n.TP\n.B -c\nDisable checking the client IP address on all incoming requests.\nBy default, requests originating from non-matching IP addresses will be\nrejected, however this will cause problems when requests are routed\nvia a cluster of DNS servers.\n.TP\n.B -s\nDon't try to configure IP address or MTU.\nThis should only be used if you have already configured the device that will be\nused.\n.TP\n.B -D\nIncrease debug level. Level 1 prints info about each RX/TX packet.\nImplies the\n.B -f\noption.\nOn level 2 (\\-DD) or higher, DNS queries will be printed literally.\nWhen using Base128 upstream encoding, this is best viewed as\nISO Latin-1 text instead of (illegal) UTF-8.\nThis is easily done with : \"LC_ALL=C luit iodined \\-DD ...\"\n(see luit(1)).\n.TP\n.B -m mtu\nSet 'mtu' as mtu size for the tun device.\nThis will be sent to the client on login, and the client will use the same mtu\nfor its tun device.  Default 1130.  Note that the DNS traffic will be\nautomatically fragmented when needed.\n.TP\n.B -l external|listen_ip4\nMake the server listen only on 'listen_ip4' for incoming IPv4 requests.\nBy default, incoming requests are accepted from all interfaces (0.0.0.0).\nA domain name can be used as argument - use one with only one A record.\nIf listen_ip4 is 'external', iodined will use the opendns.com DNS service to\nretrieve the external IP of the host and use that as listen address.\n.TP\n.B -L listen_ip6\nMake the server listen only on 'listen_ip6' for incoming IPv6 requests.\nBy default, incoming requests are accepted from all interfaces (::).\nA domain name can be used as argument - use one with only one AAAA record.\n.TP\n.B -p port\nMake the server listen on 'port' instead of 53 for traffic.\nIf 'listen_ip4' does not include localhost, this 'port' can be the same\nas 'dnsport'.\n.B Note:\nYou must make sure the dns requests are forwarded to this port yourself.\n.TP\n.B -n auto|external_ip\nThe IP address to return in NS responses. Default is to return the address used\nas destination in the query.\nIf external_ip is 'auto', iodined will use the opendns.com DNS service to\nretrieve the external IP of the host and use that for NS responses.\n.TP\n.B -b dnsport\nIf this port is specified, all incoming requests not inside the tunnel domain\nwill be forwarded to this port on localhost, to be handled by a real dns.\nIf 'listen_ip' does not include localhost, this 'dnsport' can be the\nsame as 'port'.\n.B Note:\nThe forwarding is not fully transparent, and not advised for use\nin production environments.\n.TP\n.B -i max_idle_time\nMake the server stop itself after max_idle_time seconds if no traffic have been received.\nThis should be combined with systemd or upstart on demand activation for being effective.\n.SS Client Arguments:\n.TP\n.B nameserver\nThe nameserver to use to relay the dns traffic. This can be any relaying\nnameserver or the server running iodined if reachable. This field can be\ngiven as an IPv4/IPv6 address or as a hostname. This argument is optional,\nand if not specified a nameserver will be read from the\n.I /etc/resolv.conf\nfile.\n.TP\n.B topdomain\nThe dns traffic will be sent as queries for subdomains under\n\\'topdomain'. This is normally a subdomain to a domain you own. Use a short\ndomain name to get better throughput. If\n.B nameserver\nis the iodined server, then the topdomain can be chosen freely. This argument\nmust be the same on both the client and the server.\n.SS Server Arguments:\n.TP\n.B tunnel_ip[/netmask]\nThis is the server's ip address on the tun interface. The client will be\ngiven the next ip number in the range. It is recommended to use the\n10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overridden\nby specifying it here. Using a smaller network will limit the number of\nconcurrent users.\n.TP\n.B topdomain\nThe dns traffic is expected to arrive as queries for\nsubdomains under 'topdomain'. This is normally a subdomain to a domain you\nown. Use a short domain name to get better throughput. This argument must be\nthe same on both the client and the server. Queries for domains other\nthan 'topdomain' will be forwarded when the \\-b option is given, otherwise\nthey will be dropped. The topdomain can start with '*' which will allow all\ndomains ending with the same suffix.\n.SH EXAMPLES\nSee the README file for both a quick test scenario, and a detailed description\nof real-world deployment.\n.SH SECURITY\nLogin is a relatively secure challenge-response MD5 hash, with the\npassword never passing the wire.\nHowever, all other data is\n.B NOT\nencrypted in any way. The DNS traffic is also vulnerable to replay,\ninjection and man-in-the-middle attacks, especially when iodined is used\nwith the \\-c option. Use of ssh or vpn tunneling is strongly recommended.\nOn both server and client, use\n.IR iptables ,\n.I pf\nor other firewalls to block all traffic coming in from the tun interfaces,\nexcept to the used ssh or vpn ports.\n.SH ENVIRONMENT\n.SS IODINE_PASS\nIf the environment variable\n.B IODINE_PASS\nis set, iodine will use the value it is set to as password instead of asking\nfor one. The\n.B -P\noption still has precedence.\n.SS IODINED_PASS\nIf the environment variable\n.B IODINED_PASS\nis set, iodined will use the value it is set to as password instead of asking\nfor one. The\n.B -P\noption still has precedence.\n.SH SEE ALSO\nThe README file in the source distribution contains some more elaborate\ninformation.\n.SH BUGS\nFile bugs at https://github.com/yarrick/iodine\n.SH AUTHORS\nErik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>. Major\ncontributions by Anne Bezemer.\n"
  },
  {
    "path": "src/Android.16.mk",
    "content": "#\n# iodine for Android\n#\n# by Marcel Bokhorst\n# http://blog.bokhorst.biz/5123/computers-en-internet/iodine-for-android/\n#\n# cd iodine-0.6.0-rc1/src\n# make base64u.h base64u.c\n# .../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk\n#\n\nLOCAL_PATH:= $(call my-dir)\n\nHEAD_COMMIT = `git rev-parse --short HEAD`\n\ninclude $(CLEAR_VARS)\n\nLOCAL_MODULE    := iodine\nLOCAL_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\nLOCAL_CFLAGS    := -c -DANDROID -DLINUX -DIFCONFIGPATH=\\\"/system/bin/\\\" -Wall -DGITREVISION=\\\"$(HEAD_COMMIT)\\\"\nLOCAL_LDLIBS    := -lz\nLOCAL_CFLAGS += -fPIE\nLOCAL_LDFLAGS += -fPIE -pie\n\ninclude $(BUILD_EXECUTABLE)\n\n"
  },
  {
    "path": "src/Android.mk",
    "content": "#\n# iodine for Android\n#\n# by Marcel Bokhorst\n# http://blog.bokhorst.biz/5123/computers-en-internet/iodine-for-android/\n#\n# cd iodine-0.6.0-rc1/src\n# make base64u.h base64u.c\n# .../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk\n#\n\nLOCAL_PATH:= $(call my-dir)\n\nHEAD_COMMIT = `git rev-parse --short HEAD`\n\ninclude $(CLEAR_VARS)\n\nLOCAL_MODULE    := iodine\nLOCAL_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\nLOCAL_CFLAGS    := -c -DANDROID -DLINUX -DIFCONFIGPATH=\\\"/system/bin/\\\" -Wall -DGITREVISION=\\\"$(HEAD_COMMIT)\\\"\nLOCAL_LDLIBS    := -lz\n\ninclude $(BUILD_EXECUTABLE)\n\n"
  },
  {
    "path": "src/Makefile",
    "content": "COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o base64u.o base128.o md5.o common.o\nCLIENTOBJS = iodine.o client.o util.o\nCLIENT = ../bin/iodine\nSERVEROBJS = iodined.o user.o fw_query.o\nSERVER = ../bin/iodined\n\nOS = `echo $(TARGETOS) | tr \"a-z\" \"A-Z\"`\nARCH = `uname -m`\nHEAD_COMMIT = `git rev-parse --short HEAD`\n\nLIBPATH = -L.\nLDFLAGS +=  -lz `sh osflags $(TARGETOS) link` $(LIBPATH)\nCFLAGS += -std=c99 -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags` -DGITREVISION=\\\"$(HEAD_COMMIT)\\\"\nCFLAGS += -Wstrict-prototypes -Wtype-limits -Wmissing-declarations -Wmissing-prototypes\n\nall: stateos $(CLIENT) $(SERVER)\n\nstateos:\n\t@echo OS is $(OS), arch is $(ARCH)\n\n$(CLIENT): $(COMMONOBJS) $(CLIENTOBJS)\n\t@echo LD $@\n\t@mkdir -p ../bin\n\t@$(CC) $(COMMONOBJS) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)\n\n$(SERVER): $(COMMONOBJS) $(SERVEROBJS)\n\t@echo LD $@\n\t@mkdir -p ../bin\n\t@$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)\n\n.c.o:\n\t@echo CC $<\n\t@$(CC) $(CFLAGS) $< -o $@\n\nbase64u.c: base64.c\n\t@echo Making $@\n\t@echo '/* No use in editing, produced by Makefile! */' > $@\n\t@sed -e 's/\\([Bb][Aa][Ss][Ee]64\\)/\\1u/g ; s/0123456789+/0123456789_/' < base64.c >> $@\n\nclean:\n\t@echo \"Cleaning src/\"\n\t@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.*\n\t@rm -rf obj libs #android stuff\n\n"
  },
  {
    "path": "src/android_dns.h",
    "content": "/*\n * Copyright (c) 2009 Marcel Bokhorst <marcel@bokhorst.biz>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __FIX_ANDROID_H__\n#define __FIX_ANDROID_H__\n\n/* Newer android platforms can have this data already */\n#ifndef C_IN\n\ntypedef struct {\n\tunsigned id :16;\n\tunsigned rd :1;\n\tunsigned tc :1;\n\tunsigned aa :1;\n\tunsigned opcode :4;\n\tunsigned qr :1;\n\tunsigned rcode :4;\n\tunsigned cd: 1;\n\tunsigned ad: 1;\n\tunsigned unused :1;\n\tunsigned ra :1;\n\tunsigned qdcount :16;\n\tunsigned ancount :16;\n\tunsigned nscount :16;\n\tunsigned arcount :16;\n} HEADER;\n\n#define NOERROR\t\t0\n#define FORMERR\t\t1\n#define SERVFAIL\t2\n#define NXDOMAIN\t3\n#define NOTIMP\t\t4\n#define REFUSED\t\t5\n\n#define C_IN\t\t1\n\n#define T_A\t\t1\n#define T_CNAME\t\t5\n#define T_NULL\t\t10\n#define T_MX\t\t15\n#define T_TXT\t\t16\n#define T_SRV\t\t33\n\n#endif /* !C_IN */\n\n#endif\n"
  },
  {
    "path": "src/base128.c",
    "content": "/*\n * Copyright (C) 2009 J.A.Bezemer@opensourcepartners.nl\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n/*\n * raw\t76543210 76543210 76543210 76543210 76543210 76543210 76543210\n * enc\t65432106 54321065 43210654 32106543 21065432 10654321 06543210\n *\t^      ^       ^       ^       ^       ^       ^       ^\n *\n *\t0001 1  0001 1\n *\t0011 3  0011 3\n *\t0111 7  0111 7\n *\t1111 f  0110 6\n *\t1110 e  0100 4\n *\t1100 c\n *\t1000 8\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"encoding.h\"\n\n#define BASE128_BLKSIZE_RAW 7\n#define BASE128_BLKSIZE_ENC 8\n\n/* Don't use '-' (restricted to middle of labels), prefer iso_8859-1\n * accent chars since they might readily be entered in normal use,\n * don't use 254-255 because of possible function overloading in DNS systems.\n */\nstatic const unsigned char cb128[] =\n\t\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"\n\t\"\\274\\275\\276\\277\"\n\t\"\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\317\"\n\t\"\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\337\"\n\t\"\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\"\n\t\"\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\";\nstatic unsigned char rev128[256];\nstatic int reverse_init = 0;\n\ninline static void base128_reverse_init(void)\n{\n\tint i;\n\tunsigned char c;\n\n\tif (!reverse_init) {\n\t\tmemset(rev128, 0, 256);\n\t\tfor (i = 0; i < 128; i++) {\n\t\t\tc = cb128[i];\n\t\t\trev128[(int) c] = i;\n\t\t}\n\t\treverse_init = 1;\n\t}\n}\n\n/*\n * Fills *buf with max. *buflen characters, encoding size bytes of *data.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold the trailing '\\0'.\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n * sets *buflen to : #bytes encoded from data\n */\nstatic int base128_encode(char *buf, size_t *buflen, const void *data,\n\t\t\t  size_t size)\n{\n\tunsigned char *ubuf = (unsigned char *) buf;\n\tunsigned char *udata = (unsigned char *) data;\n\tint iout = 0;\t/* to-be-filled output char */\n\tint iin = 0;\t/* one more than last input byte that can be\n\t\t\t   successfully decoded */\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0xfe) >> 1)];\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size) {\n\t\t\tiout--; \t/* previous char is useless */\n\t\t\tbreak;\n\t\t}\n\t\tubuf[iout] = cb128[((udata[iin] & 0x01) << 6) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0xfc) >> 2) : 0)];\n\t\tiin++;\t\t\t/* 0 complete, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0x03) << 5) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0xf8) >> 3) : 0)];\n\t\tiin++;\t\t\t/* 1 complete, iin=2 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0x07) << 4) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0xf0) >> 4) : 0)];\n\t\tiin++;\t\t\t/* 2 complete, iin=3 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0x0f) << 3) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0xe0) >> 5) : 0)];\n\t\tiin++;\t\t\t/* 3 complete, iin=4 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0x1f) << 2) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0xc0) >> 6) : 0)];\n\t\tiin++;\t\t\t/* 4 complete, iin=5 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[((udata[iin] & 0x3f) << 1) |\n\t\t\t\t   ((iin + 1 < size) ?\n\t\t\t\t    ((udata[iin + 1] & 0x80) >> 7) : 0)];\n\t\tiin++;\t\t\t/* 5 complete, iin=6 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tubuf[iout] = cb128[(udata[iin] & 0x7f)];\n\t\tiin++;\t\t\t/* 6 complete, iin=7 */\n\t\tiout++;\n\t}\n\n\tubuf[iout] = '\\0';\n\n\t/* store number of bytes from data that was used */\n\t*buflen = iin;\n\n\treturn iout;\n}\n\n#define REV128(x) rev128[(int) (x)]\n\n/*\n * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.\n * Decoding stops early when *str contains \\0.\n * Illegal encoded chars are assumed to decode to zero.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold a trailing '\\0' that is added (though *buf will usually\n * contain full-binary data).\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n */\nstatic int base128_decode(void *buf, size_t *buflen, const char *str,\n\t\t\t  size_t slen)\n{\n\tunsigned char *ustr = (unsigned char *) str;\n\tunsigned char *ubuf = (unsigned char *) buf;\n\tint iout = 0;\t/* to-be-filled output byte */\n\tint iin = 0;\t/* next input char to use in decoding */\n\n\tbase128_reverse_init();\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x40) >> 6);\n\t\tiin++;  \t\t/* 0 used up, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x3f) << 2) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x60) >> 5);\n\t\tiin++;  \t\t/* 1 used up, iin=2 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x1f) << 3) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x70) >> 4);\n\t\tiin++;  \t\t/* 2 used up, iin=3 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x0f) << 4) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x78) >> 3);\n\t\tiin++;  \t\t/* 3 used up, iin=4 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x07) << 5) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x7c) >> 2);\n\t\tiin++;  \t\t/* 4 used up, iin=5 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x03) << 6) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x7e) >> 1);\n\t\tiin++;  \t\t/* 5 used up, iin=6 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV128(ustr[iin]) & 0x01) << 7) |\n\t\t\t     ((REV128(ustr[iin + 1]) & 0x7f));\n\t\tiin += 2;  \t\t/* 6,7 used up, iin=8 */\n\t\tiout++;\n\t}\n\n\tubuf[iout] = '\\0';\n\n\treturn iout;\n}\n\nconst struct encoder base128_ops = {\n\t.name = \"Base128\",\n\n\t.encode = base128_encode,\n\t.decode = base128_decode,\n\n\t.places_dots = false,\n\t.eats_dots = false,\n\n\t.blocksize_raw = BASE128_BLKSIZE_RAW,\n\t.blocksize_encoded = BASE128_BLKSIZE_ENC,\n};\n"
  },
  {
    "path": "src/base32.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"encoding.h\"\n\n#define BASE32_BLKSIZE_RAW 5\n#define BASE32_BLKSIZE_ENC 8\n\nstatic const char cb32[] =\n\t\"abcdefghijklmnopqrstuvwxyz012345\";\nstatic const char cb32_ucase[] =\n\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345\";\nstatic unsigned char rev32[256];\nstatic int reverse_init = 0;\n\ninline static void base32_reverse_init(void)\n{\n\tint i;\n\tunsigned char c;\n\n\tif (!reverse_init) {\n\t\tmemset(rev32, 0, 256);\n\t\tfor (i = 0; i < 32; i++) {\n\t\t\tc = cb32[i];\n\t\t\trev32[(int) c] = i;\n\t\t\tc = cb32_ucase[i];\n\t\t\trev32[(int) c] = i;\n\t\t}\n\t\treverse_init = 1;\n\t}\n}\n\nint b32_5to8(int in)\n{\n\treturn cb32[in & 31];\n}\n\nint b32_8to5(int in)\n{\n\tbase32_reverse_init();\n\treturn rev32[in];\n}\n\n/*\n * Fills *buf with max. *buflen characters, encoding size bytes of *data.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold the trailing '\\0'.\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n * sets *buflen to : #bytes encoded from data\n */\nstatic int base32_encode(char *buf, size_t *buflen, const void *data, size_t size)\n{\n\tunsigned char *udata = (unsigned char *) data;\n\tint iout = 0;\t/* to-be-filled output char */\n\tint iin = 0;\t/* one more than last input byte that can be\n\t\t\t   successfully decoded */\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size) {\n\t\t\tiout--; \t/* previous char is useless */\n\t\t\tbreak;\n\t\t}\n\t\tbuf[iout] = cb32[((udata[iin] & 0x07) << 2) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0xc0) >> 6) : 0)];\n\t\tiin++;\t\t\t/* 0 complete, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size) {\n\t\t\tiout--;\t\t/* previous char is useless */\n\t\t\tbreak;\n\t\t}\n\t\tbuf[iout] = cb32[((udata[iin] & 0x01) << 4) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0xf0) >> 4) : 0)];\n\t\tiin++;\t\t\t/* 1 complete, iin=2 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb32[((udata[iin] & 0x0f) << 1) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0x80) >> 7) : 0)];\n\t\tiin++;\t\t\t/* 2 complete, iin=3 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size) {\n\t\t\tiout--;\t\t/* previous char is useless */\n\t\t\tbreak;\n\t\t}\n\t\tbuf[iout] = cb32[((udata[iin] & 0x03) << 3) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0xe0) >> 5) : 0)];\n\t\tiin++;\t\t\t/* 3 complete, iin=4 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb32[((udata[iin] & 0x1f))];\n\t\tiin++;\t\t\t/* 4 complete, iin=5 */\n\t\tiout++;\n\t}\n\n\tbuf[iout] = '\\0';\n\n\t/* store number of bytes from data that was used */\n\t*buflen = iin;\n\n\treturn iout;\n}\n\n#define REV32(x) rev32[(int) (x)]\n\n/*\n * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.\n * Decoding stops early when *str contains \\0.\n * Illegal encoded chars are assumed to decode to zero.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold a trailing '\\0' that is added (though *buf will usually\n * contain full-binary data).\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n */\nstatic int base32_decode(void *buf, size_t *buflen, const char *str,\n\t\t\t size_t slen)\n{\n\tunsigned char *ubuf = (unsigned char *) buf;\n\tint iout = 0;\t/* to-be-filled output byte */\n\tint iin = 0;\t/* next input char to use in decoding */\n\n\tbase32_reverse_init();\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |\n\t\t\t     ((REV32(str[iin + 1]) & 0x1c) >> 2);\n\t\tiin++;  \t\t/* 0 used up, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 2 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0' ||\n\t\t    str[iin + 2] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |\n\t\t\t     ((REV32(str[iin + 1]) & 0x1f) << 1) |\n\t\t\t     ((REV32(str[iin + 2]) & 0x10) >> 4);\n\t\tiin += 2;  \t\t/* 1,2 used up, iin=3 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |\n\t\t\t     ((REV32(str[iin + 1]) & 0x1e) >> 1);\n\t\tiin++;  \t\t/* 3 used up, iin=4 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 2 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0' ||\n\t\t    str[iin + 2] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |\n\t\t\t     ((REV32(str[iin + 1]) & 0x1f) << 2) |\n\t\t\t     ((REV32(str[iin + 2]) & 0x18) >> 3);\n\t\tiin += 2;  \t\t/* 4,5 used up, iin=6 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |\n\t\t\t     ((REV32(str[iin + 1]) & 0x1f));\n\t\tiin += 2;  \t\t/* 6,7 used up, iin=8 */\n\t\tiout++;\n\t}\n\n\tubuf[iout] = '\\0';\n\n\treturn iout;\n}\n\nconst struct encoder base32_ops = {\n\t.name = \"Base32\",\n\n\t.encode = base32_encode,\n\t.decode = base32_decode,\n\n\t.places_dots = false,\n\t.eats_dots = false,\n\n\t.blocksize_raw = BASE32_BLKSIZE_RAW,\n\t.blocksize_encoded = BASE32_BLKSIZE_ENC,\n};\n"
  },
  {
    "path": "src/base64.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"encoding.h\"\n\n#define BASE64_BLKSIZE_RAW 3\n#define BASE64_BLKSIZE_ENC 4\n\n/* Note: the \"unofficial\" char is last here, which means that the \\377 pattern\n   in DOWNCODECCHECK1 ('Y' request) will properly test it. */\nstatic const char cb64[] =\n\t\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+\";\nstatic unsigned char rev64[256];\nstatic int reverse_init = 0;\n\ninline static void base64_reverse_init(void)\n{\n\tint i;\n\tunsigned char c;\n\n\tif (!reverse_init) {\n\t\tmemset(rev64, 0, 256);\n\t\tfor (i = 0; i < 64; i++) {\n\t\t\tc = cb64[i];\n\t\t\trev64[(int) c] = i;\n\t\t}\n\t\treverse_init = 1;\n\t}\n}\n\n/*\n * Fills *buf with max. *buflen characters, encoding size bytes of *data.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold the trailing '\\0'.\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n * sets *buflen to : #bytes encoded from data\n */\nstatic int base64_encode(char *buf, size_t *buflen, const void *data,\n\t\t\t size_t size)\n{\n\tunsigned char *udata = (unsigned char *) data;\n\tint iout = 0;\t/* to-be-filled output char */\n\tint iin = 0;\t/* one more than last input byte that can be\n\t\t\t   successfully decoded */\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb64[((udata[iin] & 0xfc) >> 2)];\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size) {\n\t\t\tiout--;\t\t/* previous char is useless */\n\t\t\tbreak;\n\t\t}\n\t\tbuf[iout] = cb64[((udata[iin] & 0x03) << 4) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0xf0) >> 4) : 0)];\n\t\tiin++;\t\t\t/* 0 complete, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb64[((udata[iin] & 0x0f) << 2) |\n\t\t\t\t  ((iin + 1 < size) ?\n\t\t\t\t   ((udata[iin + 1] & 0xc0) >> 6) : 0)];\n\t\tiin++;\t\t\t/* 1 complete, iin=2 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin >= size)\n\t\t\tbreak;\n\t\tbuf[iout] = cb64[(udata[iin] & 0x3f)];\n\t\tiin++;\t\t\t/* 2 complete, iin=3 */\n\t\tiout++;\n\t}\n\n\tbuf[iout] = '\\0';\n\n\t/* store number of bytes from data that was used */\n\t*buflen = iin;\n\n\treturn iout;\n}\n\n#define REV64(x) rev64[(int) (x)]\n\n/*\n * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.\n * Decoding stops early when *str contains \\0.\n * Illegal encoded chars are assumed to decode to zero.\n *\n * NOTE: *buf space should be at least 1 byte _more_ than *buflen\n * to hold a trailing '\\0' that is added (though *buf will usually\n * contain full-binary data).\n *\n * return value    : #bytes filled in buf   (excluding \\0)\n */\nstatic int base64_decode(void *buf, size_t *buflen, const char *str,\n\t\t\t size_t slen)\n{\n\tunsigned char *ubuf = (unsigned char *) buf;\n\tint iout = 0;\t/* to-be-filled output byte */\n\tint iin = 0;\t/* next input char to use in decoding */\n\n\tbase64_reverse_init();\n\n\t/* Note: Don't bother to optimize manually. GCC optimizes\n\t   better(!) when using simplistic array indexing. */\n\n\twhile (1) {\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |\n\t\t\t     ((REV64(str[iin + 1]) & 0x30) >> 4);\n\t\tiin++;  \t\t/* 0 used up, iin=1 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |\n\t\t\t     ((REV64(str[iin + 1]) & 0x3c) >> 2);\n\t\tiin++;  \t\t/* 1 used up, iin=2 */\n\t\tiout++;\n\n\t\tif (iout >= *buflen || iin + 1 >= slen ||\n\t\t    str[iin] == '\\0' || str[iin + 1] == '\\0')\n\t\t\tbreak;\n\t\tubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) |\n\t\t\t     (REV64(str[iin + 1]) & 0x3f);\n\t\tiin += 2;  \t\t/* 2,3 used up, iin=4 */\n\t\tiout++;\n\t}\n\n\tubuf[iout] = '\\0';\n\n\treturn iout;\n}\n\nconst struct encoder base64_ops = {\n\t.name = \"Base64\",\n\n\t.encode = base64_encode,\n\t.decode = base64_decode,\n\n\t.places_dots = false,\n\t.eats_dots = false,\n\n\t.blocksize_raw = BASE64_BLKSIZE_RAW,\n\t.blocksize_encoded = BASE64_BLKSIZE_ENC,\n};\n"
  },
  {
    "path": "src/client.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <ctype.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <signal.h>\n#include <unistd.h>\n#include <sys/param.h>\n#include <sys/time.h>\n#include <fcntl.h>\n#include <zlib.h>\n#include <time.h>\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#else\n#include <arpa/nameser.h>\n#ifdef ANDROID\n#include \"android_dns.h\"\n#endif\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n#include <grp.h>\n#include <pwd.h>\n#include <netdb.h>\n#endif\n\n#include \"common.h\"\n#include \"encoding.h\"\n#include \"dns.h\"\n#include \"login.h\"\n#include \"tun.h\"\n#include \"version.h\"\n#include \"client.h\"\n\nstatic void handshake_lazyoff(int dns_fd);\n\nstatic int running;\nstatic const char *password;\n\nstatic struct sockaddr_storage nameserv;\nstatic int nameserv_len;\nstatic struct sockaddr_storage raw_serv;\nstatic int raw_serv_len;\nstatic const char *topdomain;\n\nstatic uint16_t rand_seed;\n\n/* Current up/downstream IP packet */\nstatic struct packet outpkt;\nstatic struct packet inpkt;\nint outchunkresent = 0;\n\n/* My userid at the server */\nstatic char userid;\nstatic char userid_char;\t\t/* used when sending (lowercase) */\nstatic char userid_char2;\t\t/* also accepted when receiving (uppercase) */\n\n/* DNS id for next packet */\nstatic uint16_t chunkid;\nstatic uint16_t chunkid_prev;\nstatic uint16_t chunkid_prev2;\n\n/* The encoder used for data packets\n * Defaults to Base32, can be changed after handshake */\nconst static struct encoder *dataenc = &base32_ops;\n\n/* The encoder to use for downstream data */\nstatic char downenc = ' ';\n\n/* set query type to send */\nstatic unsigned short do_qtype = T_UNSET;\n\n/* My connection mode */\nstatic enum connection conn;\n\nstatic int selecttimeout;\t\t/* RFC says timeout minimum 5sec */\nstatic int lazymode;\nstatic long send_ping_soon;\nstatic time_t lastdownstreamtime;\nstatic long send_query_sendcnt = -1;\nstatic long send_query_recvcnt = 0;\nstatic int hostname_maxlen = 0xFF;\n\nvoid\nclient_init(void)\n{\n\trunning = 1;\n\trand_seed = ((unsigned int) rand()) & 0xFFFF;\n\tsend_ping_soon = 1;\t/* send ping immediately after startup */\n\tconn = CONN_DNS_NULL;\n\n\tchunkid = ((unsigned int) rand()) & 0xFFFF;\n\tchunkid_prev = 0;\n\tchunkid_prev2 = 0;\n\n\toutpkt.len = 0;\n\toutpkt.seqno = 0;\n\toutpkt.fragment = 0;\n\toutchunkresent = 0;\n\tinpkt.len = 0;\n\tinpkt.seqno = 0;\n\tinpkt.fragment = 0;\n}\n\nvoid\nclient_stop(void)\n{\n\trunning = 0;\n}\n\nenum connection\nclient_get_conn(void)\n{\n\treturn conn;\n}\n\nvoid\nclient_set_nameserver(struct sockaddr_storage *addr, int addrlen)\n{\n\tmemcpy(&nameserv, addr, addrlen);\n\tnameserv_len = addrlen;\n}\n\nvoid\nclient_set_topdomain(const char *cp)\n{\n\ttopdomain = cp;\n}\n\nvoid\nclient_set_password(const char *cp)\n{\n\tpassword = cp;\n}\n\nint\nclient_set_qtype(char *qtype)\n{\n\tif (!strcasecmp(qtype, \"NULL\"))\n\t\tdo_qtype = T_NULL;\n\telse if (!strcasecmp(qtype, \"PRIVATE\"))\n\t\tdo_qtype = T_PRIVATE;\n\telse if (!strcasecmp(qtype, \"CNAME\"))\n\t\tdo_qtype = T_CNAME;\n\telse if (!strcasecmp(qtype, \"A\"))\n\t\tdo_qtype = T_A;\n\telse if (!strcasecmp(qtype, \"MX\"))\n\t\tdo_qtype = T_MX;\n\telse if (!strcasecmp(qtype, \"SRV\"))\n\t\tdo_qtype = T_SRV;\n\telse if (!strcasecmp(qtype, \"TXT\"))\n\t\tdo_qtype = T_TXT;\n\treturn (do_qtype == T_UNSET);\n}\n\nchar *\nclient_get_qtype(void)\n{\n\tchar *c = \"UNDEFINED\";\n\n\tif (do_qtype == T_NULL)\t\tc = \"NULL\";\n\telse if (do_qtype == T_PRIVATE)\tc = \"PRIVATE\";\n\telse if (do_qtype == T_CNAME)\tc = \"CNAME\";\n\telse if (do_qtype == T_A)\tc = \"A\";\n\telse if (do_qtype == T_MX)\tc = \"MX\";\n\telse if (do_qtype == T_SRV)\tc = \"SRV\";\n\telse if (do_qtype == T_TXT)\tc = \"TXT\";\n\n\treturn c;\n}\n\nvoid\nclient_set_downenc(char *encoding)\n{\n\tif (!strcasecmp(encoding, \"base32\"))\n\t\tdownenc = 'T';\n\telse if (!strcasecmp(encoding, \"base64\"))\n\t\tdownenc = 'S';\n\telse if (!strcasecmp(encoding, \"base64u\"))\n\t\tdownenc = 'U';\n\telse if (!strcasecmp(encoding, \"base128\"))\n\t\tdownenc = 'V';\n\telse if (!strcasecmp(encoding, \"raw\"))\n\t\tdownenc = 'R';\n}\n\nvoid\nclient_set_selecttimeout(int select_timeout)\n{\n\tselecttimeout = select_timeout;\n}\n\nvoid\nclient_set_lazymode(int lazy_mode)\n{\n\tlazymode = lazy_mode;\n}\n\nvoid\nclient_set_hostname_maxlen(int i)\n{\n\tif (i <= 0xFF)\n\t\thostname_maxlen = i;\n}\n\nconst char *\nclient_get_raw_addr(void)\n{\n\treturn format_addr(&raw_serv, raw_serv_len);\n}\n\nstatic void\nsend_query(int fd, char *hostname)\n{\n\tchar packet[4096];\n\tstruct query q;\n\tsize_t len;\n\n\tchunkid_prev2 = chunkid_prev;\n\tchunkid_prev = chunkid;\n\tchunkid += 7727;\n\tif (chunkid == 0)\n\t\t/* 0 is used as \"no-query\" in iodined.c */\n\t\tchunkid = 7727;\n\n\tq.id = chunkid;\n\tq.type = do_qtype;\n\n\tlen = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname));\n\tif (len < 1) {\n\t\twarnx(\"dns_encode doesn't fit\");\n\t\treturn;\n\t}\n\n#if 0\n\tfprintf(stderr, \"  Sendquery: id %5d name[0] '%c'\\n\", q.id, hostname[0]);\n#endif\n\n\tsendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, nameserv_len);\n\n\t/* There are DNS relays that time out quickly but don't send anything\n\t   back on timeout.\n\t   And there are relays where, in lazy mode, our new query apparently\n\t   _replaces_ our previous query, and we get no answers at all in\n\t   lazy mode while legacy immediate-ping-pong works just fine.\n\t   Here we detect and fix these situations.\n\t   (Can't very well do this anywhere else; this is the only place\n\t   we'll reliably get to in such situations.)\n\t */\n\n\tif (send_query_sendcnt >= 0 && send_query_sendcnt < 100 && lazymode) {\n\t\tsend_query_sendcnt++;\n\n\t\tif ((send_query_sendcnt > 6 && send_query_recvcnt <= 0) ||\n\t\t    (send_query_sendcnt > 10 &&\n\t\t     4 * send_query_recvcnt < send_query_sendcnt)) {\n\t\t\tif (selecttimeout > 1) {\n\t\t\t\twarnx(\"Receiving too few answers. Setting interval to 1 (-I1)\");\n\t\t\t\tselecttimeout = 1;\n\t\t\t\t/* restart counting */\n\t\t\t\tsend_query_sendcnt = 0;\n\t\t\t\tsend_query_recvcnt = 0;\n\t\t\t} else if (lazymode) {\n\t\t\t\twarnx(\"Receiving too few answers. Will try to switch lazy mode off, but that may not always work any more. Start with -L0 next time on this network.\");\n\t\t\t\tlazymode = 0;\n\t\t\t\tselecttimeout = 1;\n\t\t\t\thandshake_lazyoff(fd);\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic void\nsend_raw(int fd, char *buf, int buflen, int cmd)\n{\n\tchar packet[4096];\n\tint len;\n\n\tlen = MIN(sizeof(packet) - RAW_HDR_LEN, buflen);\n\n\tmemcpy(packet, raw_header, RAW_HDR_LEN);\n\tif (len) {\n\t\tmemcpy(&packet[RAW_HDR_LEN], buf, len);\n\t}\n\n\tlen += RAW_HDR_LEN;\n\tpacket[RAW_HDR_CMD] = cmd | (userid & 0x0F);\n\n\tsendto(fd, packet, len, 0, (struct sockaddr*)&raw_serv, sizeof(raw_serv));\n}\n\nstatic void\nsend_raw_data(int dns_fd)\n{\n\tsend_raw(dns_fd, outpkt.data, outpkt.len, RAW_HDR_CMD_DATA);\n\toutpkt.len = 0;\n}\n\n\nstatic void\nsend_packet(int fd, char cmd, const char *data, const size_t datalen)\n{\n\tchar buf[4096];\n\n\tbuf[0] = cmd;\n\n\tbuild_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain,\n\t\t       &base32_ops, hostname_maxlen);\n\tsend_query(fd, buf);\n}\n\nstatic inline int is_sending(void)\n{\n\treturn (outpkt.len != 0);\n}\n\nstatic void\nsend_chunk(int fd)\n{\n\tchar buf[4096];\n\tint avail;\n\tint code;\n\tchar *p;\n\tstatic int datacmc = 0;\n\tchar *datacmcchars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n\n\tp = outpkt.data;\n\tp += outpkt.offset;\n\tavail = outpkt.len - outpkt.offset;\n\n\t/* Note: must be same, or smaller than send_fragsize_probe() */\n\toutpkt.sentlen = build_hostname(buf + 5, sizeof(buf) - 5, p, avail,\n\t\t\t\t\ttopdomain, dataenc, hostname_maxlen);\n\n\t/* Build upstream data header (see doc/proto_xxxxxxxx.txt) */\n\n\tbuf[0] = userid_char;\t\t/* First byte is hex userid */\n\n\tcode = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2);\n\tbuf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */\n\n\tcode = ((outpkt.fragment & 3) << 3) | (inpkt.seqno & 7);\n\tbuf[2] = b32_5to8(code); /* Third byte is 2 bits lower fragment count, 3 bits downstream packet seqno */\n\n\tcode = ((inpkt.fragment & 15) << 1) | (outpkt.sentlen == avail);\n\tbuf[3] = b32_5to8(code); /* Fourth byte is 4 bits downstream fragment count, 1 bit last frag flag */\n\n\tbuf[4] = datacmcchars[datacmc];\t/* Fifth byte is data-CMC */\n\tdatacmc++;\n\tif (datacmc >= 36)\n\t\tdatacmc = 0;\n\n#if 0\n\tfprintf(stderr, \"  Send: down %d/%d up %d/%d, %d bytes\\n\",\n\t\tinpkt.seqno, inpkt.fragment, outpkt.seqno, outpkt.fragment,\n\t\toutpkt.sentlen);\n#endif\n\n\tsend_query(fd, buf);\n}\n\nstatic void\nsend_ping(int fd)\n{\n\tif (conn == CONN_DNS_NULL) {\n\t\tchar data[4];\n\n\t\tdata[0] = userid;\n\t\tdata[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15);\n\t\tdata[2] = (rand_seed >> 8) & 0xff;\n\t\tdata[3] = (rand_seed >> 0) & 0xff;\n\n\t\trand_seed++;\n\n#if 0\n\t\tfprintf(stderr, \"  Send: down %d/%d         (ping)\\n\",\n\t\t\tinpkt.seqno, inpkt.fragment);\n#endif\n\n\t\tsend_packet(fd, 'p', data, sizeof(data));\n\t} else {\n\t\tsend_raw(fd, NULL, 0, RAW_HDR_CMD_PING);\n\t}\n}\n\nstatic void\nwrite_dns_error(struct query *q, int ignore_some_errors)\n/* This is called from:\n   1. handshake_waitdns() when already checked that reply fits to our\n      latest query.\n   2. tunnel_dns() when already checked that reply is for our ping or data\n      packet, but not necessarily the most recent (SERVFAIL mostly comes\n      after long delay).\n   So ignorable errors are never printed.\n*/\n{\n\tif (!q) return;\n\n\tswitch (q->rcode) {\n\tcase NOERROR:\t/* 0 */\n\t\tif (!ignore_some_errors)\n\t\t\twarnx(\"Got reply without error, but also without question and/or answer\");\n\t\tbreak;\n\tcase FORMERR:\t/* 1 */\n\t\twarnx(\"Got FORMERR as reply: server does not understand our request\");\n\t\tbreak;\n\tcase SERVFAIL:\t/* 2 */\n\t\tif (!ignore_some_errors)\n\t\t\twarnx(\"Got SERVFAIL as reply: server failed or recursion timeout\");\n\t\tbreak;\n\tcase NXDOMAIN:\t/* 3 */\n\t\twarnx(\"Got NXDOMAIN as reply: domain does not exist\");\n\t\tbreak;\n\tcase NOTIMP:\t/* 4 */\n\t\twarnx(\"Got NOTIMP as reply: server does not support our request\");\n\t\tbreak;\n\tcase REFUSED:\t/* 5 */\n\t\twarnx(\"Got REFUSED as reply\");\n\t\tbreak;\n\tdefault:\n\t\twarnx(\"Got RCODE %u as reply\", q->rcode);\n\t\tbreak;\n\t}\n}\n\nstatic int\ndns_namedec(char *outdata, int outdatalen, char *buf, int buflen)\n/* Decodes *buf to *outdata.\n * *buf WILL be changed by undotify.\n * Note: buflen must be _exactly_ strlen(buf) before undotifying.\n * (undotify of reduced-len won't copy \\0, base-X decode will decode too much.)\n * Returns #bytes usefully filled in outdata.\n */\n{\n\tsize_t outdatalenu = outdatalen;\n\n\tswitch (buf[0]) {\n\tcase 'h': /* Hostname with base32 */\n\tcase 'H':\n\t\t/* Need 1 byte H, 3 bytes \".xy\", >=1 byte data */\n\t\tif (buflen < 5)\n\t\t\treturn 0;\n\n\t\t/* this also does undotify */\n\t\treturn unpack_data(outdata, outdatalen, buf + 1, buflen - 4,\n\t\t\t\t   &base32_ops);\n\n\tcase 'i': /* Hostname++ with base64 */\n\tcase 'I':\n\t\t/* Need 1 byte I, 3 bytes \".xy\", >=1 byte data */\n\t\tif (buflen < 5)\n\t\t\treturn 0;\n\n\t\t/* this also does undotify */\n\t\treturn unpack_data(outdata, outdatalen, buf + 1, buflen - 4,\n\t\t\t\t   &base64_ops);\n\n\tcase 'j': /* Hostname++ with base64u */\n\tcase 'J':\n\t\t/* Need 1 byte J, 3 bytes \".xy\", >=1 byte data */\n\t\tif (buflen < 5)\n\t\t\treturn 0;\n\n\t\t/* this also does undotify */\n\t\treturn unpack_data(outdata, outdatalen, buf + 1, buflen - 4,\n\t\t\t\t   &base64u_ops);\n\n\tcase 'k': /* Hostname++ with base128 */\n\tcase 'K':\n\t\t/* Need 1 byte J, 3 bytes \".xy\", >=1 byte data */\n\t\tif (buflen < 5)\n\t\t\treturn 0;\n\n\t\t/* this also does undotify */\n\t\treturn unpack_data(outdata, outdatalen, buf + 1, buflen - 4,\n\t\t\t\t   &base128_ops);\n\n\tcase 't': /* plain base32(Thirty-two) from TXT */\n\tcase 'T':\n\t\tif (buflen < 2)\n\t\t\treturn 0;\n\n\t\treturn base32_ops.decode(outdata, &outdatalenu, buf + 1, buflen - 1);\n\n\tcase 's': /* plain base64(Sixty-four) from TXT */\n\tcase 'S':\n\t\tif (buflen < 2)\n\t\t\treturn 0;\n\n\t\treturn base64_ops.decode(outdata, &outdatalenu, buf + 1, buflen - 1);\n\n\tcase 'u': /* plain base64u (Underscore) from TXT */\n\tcase 'U':\n\t\tif (buflen < 2)\n\t\t\treturn 0;\n\n\t\treturn base64_ops.decode(outdata, &outdatalenu, buf + 1, buflen - 1);\n\n\tcase 'v': /* plain base128 from TXT */\n\tcase 'V':\n\t\tif (buflen < 2)\n\t\t\treturn 0;\n\n\t\treturn base128_ops.decode(outdata, &outdatalenu, buf + 1, buflen - 1);\n\n\tcase 'r': /* Raw binary from TXT */\n\tcase 'R':\n\t\t/* buflen>=1 already checked */\n\t\tbuflen--;\n\t\tbuflen = MIN(buflen, outdatalen);\n\t\tmemcpy(outdata, buf + 1, buflen);\n\t\treturn buflen;\n\n\tdefault:\n\t\twarnx(\"Received unsupported encoding\");\n\t\treturn 0;\n\t}\n\n\t/* notreached */\n\treturn 0;\n}\n\nstatic int\nread_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q)\n/* FIXME: tun_fd needed for raw handling */\n/* Returns -1 on receive error or decode error, including DNS error replies.\n   Returns 0 on replies that could be correct but are useless, and are not\n   DNS error replies.\n   Returns >0 on correct replies; value is #valid bytes in *buf.\n*/\n{\n\tstruct sockaddr_storage from;\n\tchar data[64*1024];\n\tsocklen_t addrlen;\n\tint r;\n\n\taddrlen = sizeof(from);\n\tif ((r = recvfrom(dns_fd, data, sizeof(data), 0,\n\t\t\t  (struct sockaddr*)&from, &addrlen)) < 0) {\n\t\twarn(\"recvfrom\");\n\t\treturn -1;\n\t}\n\n\tif (conn == CONN_DNS_NULL) {\n\t\tint rv;\n\t\tif (r <= 0)\n\t\t\t/* useless packet */\n\t\t\treturn 0;\n\n\t\trv = dns_decode(buf, buflen, q, QR_ANSWER, data, r);\n\t\tif (rv <= 0)\n\t\t\treturn rv;\n\n\t\tif (q->type == T_CNAME || q->type == T_TXT)\n\t\t/* CNAME can also be returned from an A question */\n\t\t{\n\t\t\t/*\n\t\t\t * buf is a hostname or txt stream that we still need to\n\t\t\t * decode to binary\n\t\t\t *\n\t\t\t * also update rv with the number of valid bytes\n\t\t\t *\n\t\t\t * data is unused here, and will certainly hold the smaller binary\n\t\t\t */\n\n\t\t\trv = dns_namedec(data, sizeof(data), buf, rv);\n\n\t\t\trv = MIN(rv, buflen);\n\t\t\tif (rv > 0)\n\t\t\t\tmemcpy(buf, data, rv);\n\n\t\t} else if (q->type == T_MX || q->type == T_SRV) {\n\t\t\t/* buf is like \"Hname.com\\0Hanother.com\\0\\0\" */\n\t\t\tint buftotal = rv;\t/* idx of last \\0 */\n\t\t\tint bufoffset = 0;\n\t\t\tint dataoffset = 0;\n\t\t\tint thispartlen, dataspace, datanew;\n\n\t\t\twhile (1) {\n\t\t\t\tthispartlen = strlen(buf);\n\t\t\t\tthispartlen = MIN(thispartlen, buftotal-bufoffset);\n\t\t\t\tdataspace = sizeof(data) - dataoffset;\n\t\t\t\tif (thispartlen <= 0 || dataspace <= 0)\n\t\t\t\t\tbreak;\n\n\t\t\t\tdatanew = dns_namedec(data + dataoffset, dataspace,\n\t\t\t\t\t\t      buf + bufoffset, thispartlen);\n\t\t\t\tif (datanew <= 0)\n\t\t\t\t\tbreak;\n\n\t\t\t\tbufoffset += thispartlen + 1;\n\t\t\t\tdataoffset += datanew;\n\t\t\t}\n\t\t\trv = dataoffset;\n\t\t\trv = MIN(rv, buflen);\n\t\t\tif (rv > 0)\n\t\t\t\tmemcpy(buf, data, rv);\n\t\t}\n\n\t\treturn rv;\n\t} else { /* CONN_RAW_UDP */\n\t\tunsigned long datalen;\n\t\tchar buf[64*1024];\n\n\t\t/* minimum length */\n\t\tif (r < RAW_HDR_LEN) return 0;\n\t\t/* should start with header */\n\t\tif (memcmp(data, raw_header, RAW_HDR_IDENT_LEN)) return 0;\n\t\t/* should be my user id */\n\t\tif (RAW_HDR_GET_USR(data) != userid) return 0;\n\n\t\tif (RAW_HDR_GET_CMD(data) == RAW_HDR_CMD_DATA ||\n\t\t    RAW_HDR_GET_CMD(data) == RAW_HDR_CMD_PING)\n\t\t\tlastdownstreamtime = time(NULL);\n\n\t\t/* should be data packet */\n\t\tif (RAW_HDR_GET_CMD(data) != RAW_HDR_CMD_DATA) return 0;\n\n\t\tr -= RAW_HDR_LEN;\n\t\tdatalen = sizeof(buf);\n\t\tif (uncompress((uint8_t*)buf, &datalen, (uint8_t*) &data[RAW_HDR_LEN], r) == Z_OK) {\n\t\t\twrite_tun(tun_fd, buf, datalen);\n\t\t}\n\n\t\t/* don't process any further */\n\t\treturn 0;\n\t}\n}\n\nstatic int\nhandshake_waitdns(int dns_fd, char *buf, int buflen, char c1, char c2, int timeout)\n/* Wait for DNS reply fitting to our latest query and returns it.\n   Returns length of reply = #bytes used in buf.\n   Returns 0 if fitting reply happens to be useless.\n   Returns -2 on (at least) DNS error that fits to our latest query,\n   error message already printed.\n   Returns -3 on timeout (given in seconds).\n   Returns -1 on other errors.\n\n   Timeout is restarted when \"wrong\" (previous/delayed) replies are received,\n   so effective timeout may be longer than specified.\n*/\n{\n\tstruct query q;\n\tint r, rv;\n\tfd_set fds;\n\tstruct timeval tv;\n\n\twhile (1) {\n\t\ttv.tv_sec = timeout;\n\t\ttv.tv_usec = 0;\n\t\tFD_ZERO(&fds);\n\t\tFD_SET(dns_fd, &fds);\n\t\tr = select(dns_fd + 1, &fds, NULL, NULL, &tv);\n\n\t\tif (r < 0)\n\t\t\treturn -1;\t/* select error */\n\t\tif (r == 0)\n\t\t\treturn -3;\t/* select timeout */\n\n\t\tq.id = 0;\n\t\tq.name[0] = '\\0';\n\t\trv = read_dns_withq(dns_fd, 0, buf, buflen, &q);\n\n\t\tif (q.id != chunkid || (q.name[0] != c1 && q.name[0] != c2)) {\n#if 0\n\t\t\tfprintf(stderr, \"Ignoring unfitting reply id %d starting with '%c'\\n\", q.id, q.name[0]);\n#endif\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* if still here: reply matches our latest query */\n\n\t\t/* Non-recursive DNS servers (such as [a-m].root-servers.net)\n\t\t   return no answer, but only additional and authority records.\n\t\t   Can't explicitly test for that here, just assume that\n\t\t   NOERROR is such situation. Only trigger on the very first\n\t\t   requests (Y or V, depending if -T given).\n\t\t */\n\t\tif (rv < 0 && q.rcode == NOERROR &&\n\t\t    (q.name[0] == 'Y' || q.name[0] == 'y' ||\n\t\t     q.name[0] == 'V' || q.name[0] == 'v')) {\n\t\t\tfprintf(stderr, \"Got empty reply. This nameserver may not be resolving recursively, use another.\\n\");\n\t\t\tfprintf(stderr, \"Try \\\"iodine [options] ns.%s %s\\\" first, it might just work.\\n\",\n\t\t\t\ttopdomain, topdomain);\n\t\t\treturn -2;\n\t\t}\n\n\t\t/* If we get an immediate SERVFAIL on the handshake query\n\t\t   we're waiting for, wait a while before sending the next.\n\t\t   SERVFAIL reliably happens during fragsize autoprobe, but\n\t\t   mostly long after we've moved along to some other queries.\n\t\t   However, some DNS relays, once they throw a SERVFAIL, will\n\t\t   for several seconds apply it immediately to _any_ new query\n\t\t   for the same topdomain. When this happens, waiting a while\n\t\t   is the only option that works.\n\t\t */\n\t\tif (rv < 0 && q.rcode == SERVFAIL)\n\t\t\tsleep(1);\n\n\t\tif (rv < 0) {\n\t\t\twrite_dns_error(&q, 1);\n\t\t\treturn -2;\n\t\t}\n\t\t/* rv either 0 or >0, return it as is. */\n\t\treturn rv;\n\t}\n\n\t/* not reached */\n\treturn -1;\n}\n\nstatic int\ntunnel_tun(int tun_fd, int dns_fd)\n{\n\tunsigned long outlen;\n\tunsigned long inlen;\n\tchar out[64*1024];\n\tchar in[64*1024];\n\tssize_t read;\n\n\tif ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)\n\t\treturn -1;\n\n\t/* We may be here only to empty the tun device; then return -1\n\t   to force continue in select loop. */\n\tif (is_sending())\n\t\treturn -1;\n\n\toutlen = sizeof(out);\n\tinlen = read;\n\tcompress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);\n\n\tmemcpy(outpkt.data, out, MIN(outlen, sizeof(outpkt.data)));\n\toutpkt.sentlen = 0;\n\toutpkt.offset = 0;\n\toutpkt.seqno = (outpkt.seqno + 1) & 7;\n\toutpkt.len = outlen;\n\toutpkt.fragment = 0;\n\toutchunkresent = 0;\n\n\tif (conn == CONN_DNS_NULL) {\n\t\tsend_chunk(dns_fd);\n\n\t\tsend_ping_soon = 0;\n\t} else {\n\t\tsend_raw_data(dns_fd);\n\t}\n\n\treturn read;\n}\n\nstatic int\ntunnel_dns(int tun_fd, int dns_fd)\n{\n\tstatic long packrecv = 0;\n\tstatic long packrecv_oos = 0;\n\tstatic long packrecv_servfail = 0;\n\tint up_ack_seqno;\n\tint up_ack_fragment;\n\tint new_down_seqno;\n\tint new_down_fragment;\n\tstruct query q;\n\tunsigned long datalen;\n\tchar buf[64*1024];\n\tint read;\n\tint send_something_now = 0;\n\n\tmemset(q.name, 0, sizeof(q.name));\n\tread = read_dns_withq(dns_fd, tun_fd, buf, sizeof(buf), &q);\n\n\tif (conn != CONN_DNS_NULL)\n\t\treturn 1;  /* everything already done */\n\n#if 0\n\tfprintf(stderr, \"\t\t\t\tRecv: id %5d name[0]='%c'\\n\",\n\t\tq.id, q.name[0]);\n#endif\n\n\t/* Don't process anything that isn't data for us; usually error\n\t   replies from fragsize probes etc. However a sequence of those,\n\t   mostly 1 sec apart, will continuously break the >=2-second select\n\t   timeout, which means we won't send a proper ping for a while.\n\t   So make select a bit faster, <1sec. */\n\tif (q.name[0] != 'P' && q.name[0] != 'p' &&\n\t    q.name[0] != userid_char && q.name[0] != userid_char2) {\n\t\tsend_ping_soon = 700;\n\t\treturn -1;\t/* nothing done */\n\t}\n\n\tif (read < 2) {\n\t\t/* Maybe SERVFAIL etc. Send ping to get things back in order,\n\t\t   but wait a bit to prevent fast ping-pong loops. */\n\n\t\tif (read < 0)\n\t\t\twrite_dns_error(&q, 0);\n\n\t\tif (read < 0 && q.rcode == SERVFAIL && lazymode &&\n\t\t    selecttimeout > 1) {\n\t\t\tif (packrecv < 500 && packrecv_servfail < 4) {\n\t\t\t\tpackrecv_servfail++;\n\t\t\t\twarnx(\"Hmm, that's %ld. Your data should still go through...\", packrecv_servfail);\n\t\t\t} else if (packrecv < 500 && packrecv_servfail == 4) {\n\t\t\t\tpackrecv_servfail++;\n\t\t\t\twarnx(\"I think %ld is too many. Setting interval to 1 to hopefully reduce SERVFAILs. But just ignore them if data still comes through. (Use -I1 next time on this network.)\", packrecv_servfail);\n\t\t\t\tselecttimeout = 1;\n\t\t\t\tsend_query_sendcnt = 0;\n\t\t\t\tsend_query_recvcnt = 0;\n\t\t\t} else if (packrecv >= 500 && packrecv_servfail > 0) {\n\t\t\t\twarnx(\"(Sorry, stopped counting; try -I1 if you experience hiccups.)\");\n\t\t\t\tpackrecv_servfail = 0;\n\t\t\t}\n\t\t}\n\n\t\t/* read == 1 happens with \"QMEM\" illegal replies, caused by\n\t\t   heavy reordering, or after short disconnections when\n\t\t   data-CMC has looped around into the \"duplicate\" values.\n\t\t   All these cases are helped by faster pinging. */\n#if 0\n\t\tif (read == 1)\n\t\t\tfprintf(stderr, \"   q=%c id %5d 1-byte illegal \\\"QMEM\\\" reply\\n\", q.name[0], q.id);\n#endif\n\n\t\tsend_ping_soon = 900;\n\t\treturn -1;\t/* nothing done */\n\t}\n\n\tif (read == 5 && !strncmp(\"BADIP\", buf, 5)) {\n\t\twarnx(\"BADIP: Server rejected sender IP address (maybe iodined -c will help), or server kicked us due to timeout. Will exit if no downstream data is received in 60 seconds.\");\n\t\treturn -1;\t/* nothing done */\n\t}\n\n\tif (send_ping_soon) {\n\t\tsend_something_now = 1;\n\t\tsend_ping_soon = 0;\n\t}\n\n\t/* Decode the data header, update seqno and frag;\n\t   already checked read>=2\n\t   Note that buf[] gets overwritten when down-pkt complete */\n\tnew_down_seqno = (buf[1] >> 5) & 7;\n\tnew_down_fragment = (buf[1] >> 1) & 15;\n\tup_ack_seqno = (buf[0] >> 4) & 7;\n\tup_ack_fragment = buf[0] & 15;\n\n#if 0\n\tfprintf(stderr, \"\t\t\t\tRecv: id %5d down %d/%d up %d/%d, %d bytes\\n\",\n\t\tq.id, new_down_seqno, new_down_fragment, up_ack_seqno,\n\t\tup_ack_fragment, read);\n#endif\n\n\t/* Downstream data traffic */\n\n\tif (read > 2 && new_down_seqno != inpkt.seqno &&\n\t    recent_seqno(inpkt.seqno, new_down_seqno)) {\n\t\t/* This is the previous seqno, or a bit earlier.\n\t\t   Probably out-of-sequence dupe due to unreliable\n\t\t   intermediary DNS. Don't get distracted, but send\n\t\t   ping quickly to get things back in order.\n\t\t   Ping will send our current seqno idea.\n\t\t   If it's really a new packet that skipped multiple seqnos\n\t\t   (why??), server will re-send and drop a few times and\n\t\t   eventually everything will work again. */\n\t\tread = 2;\n\t\tsend_ping_soon = 500;\n\t\t/* Still process upstream ack, if any */\n\t}\n\n\tif (!(packrecv & 0x1000000))\n\t\tpackrecv++;\n\tsend_query_recvcnt++;  /* overflow doesn't matter */\n\n\t/* Don't process any non-recent stuff any further.\n\t   No need to remember more than 3 ids: in practice any older replies\n\t   arrive after new/current replies, and whatever data the old replies\n\t   have, it has become useless in the mean time.\n\t   Actually, ever since iodined is replying to both the original query\n\t   and the last dupe, this hardly triggers any more.\n\t */\n\tif (q.id != chunkid && q.id != chunkid_prev && q.id != chunkid_prev2) {\n\t\tpackrecv_oos++;\n#if 0\n\t\tfprintf(stderr, \"   q=%c Packs received = %8ld  Out-of-sequence = %8ld\\n\", q.name[0], packrecv, packrecv_oos);\n#endif\n\t\tif (lazymode && packrecv < 1000 && packrecv_oos == 5) {\n\t\t\tif (selecttimeout > 1)\n\t\t\t\twarnx(\"Hmm, getting some out-of-sequence DNS replies. Setting interval to 1 (use -I1 next time on this network). If data traffic still has large hiccups, try if -L0 works better.\");\n\t\t\telse\n\t\t\t\twarnx(\"Hmm, getting some out-of-sequence DNS replies. If data traffic often has large hiccups, try running with -L0 .\");\n\t\t\tselecttimeout = 1;\n\t\t\tsend_query_sendcnt = 0;\n\t\t\tsend_query_recvcnt = 0;\n\t\t}\n\n\t\tif (send_something_now) {\n\t\t\tsend_ping(dns_fd);\n\t\t\tsend_ping_soon = 0;\n\t\t}\n\t\treturn -1;\t/* nothing done */\n\t}\n#if 0\n\tfprintf(stderr, \"   q=%c Packs received = %8ld  Out-of-sequence = %8ld\\n\", q.name[0], packrecv, packrecv_oos);\n#endif\n\n\t/* Okay, we have a recent downstream packet */\n\tlastdownstreamtime = time(NULL);\n\n\t/* In lazy mode, we shouldn't get much replies to our most-recent\n\t   query, only during heavy data transfer. Since this means the server\n\t   doesn't have any packets left, send one relatively fast (but not\n\t   too fast, to avoid runaway ping-pong loops..) */\n\tif (q.id == chunkid && lazymode) {\n\t\tif (!send_ping_soon || send_ping_soon > 900)\n\t\t\tsend_ping_soon = 900;\n\t}\n\n\tif (read == 2 && new_down_seqno != inpkt.seqno &&\n\t    !recent_seqno(inpkt.seqno, new_down_seqno)) {\n\t\t/* This is a seqno that we didn't see yet, but it has\n\t\t   no data any more. Possible since iodined will send\n\t\t   fitting packs just once and not wait for ack.\n\t\t   Real data got lost, or will arrive shortly.\n\t\t   Update our idea of the seqno, and drop any waiting\n\t\t   old pack. Send ping to get things back on track. */\n\t\tinpkt.seqno = new_down_seqno;\n\t\tinpkt.fragment = new_down_fragment;\n\t\tinpkt.len = 0;\n\t\tsend_ping_soon = 500;\n\t}\n\n\twhile (read > 2) {\n\t/* \"if\" with easy exit */\n\n\t\tif (new_down_seqno != inpkt.seqno) {\n\t\t\t/* New packet (and not dupe of recent; checked above) */\n\t\t\t/* Forget any old packet, even if incomplete */\n\t\t\tinpkt.seqno = new_down_seqno;\n\t\t\tinpkt.fragment = new_down_fragment;   /* hopefully 0 */\n\t\t\tinpkt.len = 0;\n\t\t} else if (inpkt.fragment == 0 && new_down_fragment == 0 &&\n\t\t\t   inpkt.len == 0) {\n\t\t\t/* Weird situation: we probably got a no-data reply\n\t\t\t   for this seqno (see above), and the actual data\n\t\t\t   is following now. */\n\t\t\t/* okay, nothing to do here, just so that next else-if\n\t\t\t   doesn't trigger */\n\t\t} else if (new_down_fragment <= inpkt.fragment) {\n\t\t\t/* Same packet but duplicate fragment, ignore.\n\t\t\t   If the server didn't get our ack for it, the next\n\t\t\t   ping or chunk will do that. */\n\t\t\tsend_ping_soon = 500;\n\t\t\tbreak;\n\t\t} else if (new_down_fragment > inpkt.fragment + 1) {\n\t\t\t/* Quite impossible. We missed a fragment, but the\n\t\t\t   server got our ack for it and is sending the next\n\t\t\t   fragment already. Don't handle it but let server\n\t\t\t   re-send and drop. */\n\t\t\tsend_ping_soon = 500;\n\t\t\tbreak;\n\t\t}\n\t\tinpkt.fragment = new_down_fragment;\n\n\t\tdatalen = MIN(read - 2, sizeof(inpkt.data) - inpkt.len);\n\n\t\t/* we are here only when read > 2, so datalen \"always\" >=1 */\n\n\t\t/* Skip 2 byte data header and append to packet */\n\t\tmemcpy(&inpkt.data[inpkt.len], &buf[2], datalen);\n\t\tinpkt.len += datalen;\n\n\t\tif (buf[1] & 1) { /* If last fragment flag is set */\n\t\t\t/* Uncompress packet and send to tun */\n\t\t\t/* RE-USES buf[] */\n\t\t\tdatalen = sizeof(buf);\n\t\t\tif (uncompress((uint8_t*)buf, &datalen, (uint8_t*) inpkt.data, inpkt.len) == Z_OK) {\n\t\t\t\twrite_tun(tun_fd, buf, datalen);\n\t\t\t}\n\t\t\tinpkt.len = 0;\n\t\t\t/* Keep .seqno and .fragment as is, so that we won't\n\t\t\t   reassemble from duplicate fragments */\n\t\t}\n\n\t\t/* Send anything to ack the received seqno/frag, and get more */\n\t\tif (inpkt.len == 0) {\n\t\t\t/* was last frag; wait just a trifle because our\n\t\t\t   tun will probably return TCP-ack immediately.\n\t\t\t   5msec = 200 DNSreq/sec */\n\t\t\tsend_ping_soon = 5;\n\t\t} else {\n\t\t\t/* server certainly has more data */\n\t\t\tsend_something_now = 1;\n\t\t}\n\n\t\tbreak;\n\t}\n\n\t/* NOTE: buf[] was overwritten when down-packet complete */\n\n\n\t/* Upstream data traffic */\n\n\tif (is_sending()) {\n\t\t/* already checked read>=2 */\n#if 0\n\t\tfprintf(stderr, \"Got ack for %d,%d - expecting %d,%d - id=%d cur=%d prev=%d prev2=%d\\n\",\n\t\t\tup_ack_seqno, up_ack_fragment, outpkt.seqno, outpkt.fragment,\n\t\t\tq.id, chunkid, chunkid_prev, chunkid_prev2);\n#endif\n\n\t\tif (up_ack_seqno == outpkt.seqno &&\n\t\t    up_ack_fragment == outpkt.fragment) {\n\t\t\t/* Okay, previously sent fragment has arrived */\n\n\t\t\toutpkt.offset += outpkt.sentlen;\n\t\t\tif (outpkt.offset >= outpkt.len) {\n\t\t\t\t/* Packet completed */\n\t\t\t\toutpkt.offset = 0;\n\t\t\t\toutpkt.len = 0;\n\t\t\t\toutpkt.sentlen = 0;\n\t\t\t\toutchunkresent = 0;\n\n\t\t\t\t/* Normally, server still has a query in queue,\n\t\t\t\t   but sometimes not. So send a ping.\n\t\t\t\t   (Comment this out and you'll see occasional\n\t\t\t\t   hiccups.)\n\t\t\t\t   But since the server often still has a\n\t\t\t\t   query and we can expect a TCP-ack returned\n\t\t\t\t   from our tun device quickly in many cases,\n\t\t\t\t   don't be too fast.\n\t\t\t\t   20msec still is 50 DNSreq/second... */\n\t\t\t\tif (!send_ping_soon || send_ping_soon > 20)\n\t\t\t\t\tsend_ping_soon = 20;\n\t\t\t} else {\n\t\t\t\t/* More to send */\n\t\t\t\toutpkt.fragment++;\n\t\t\t\toutchunkresent = 0;\n\t\t\t\tsend_chunk(dns_fd);\n\t\t\t\tsend_ping_soon = 0;\n\t\t\t\tsend_something_now = 0;\n\t\t\t}\n\t\t}\n\t\t/* else: Some wrong fragment has arrived, or old fragment is\n\t\t   acked again, mostly by ping responses.\n\t\t   Don't resend chunk, usually not needed; select loop will\n\t\t   re-send on timeout (1sec if is_sending()). */\n\t}\n\n\n\t/* Send ping if we didn't send anything yet */\n\tif (send_something_now) {\n\t\tsend_ping(dns_fd);\n\t\tsend_ping_soon = 0;\n\t}\n\n\treturn read;\n}\n\nint\nclient_tunnel(int tun_fd, int dns_fd)\n{\n\tstruct timeval tv;\n\tfd_set fds;\n\tint rv;\n\tint i;\n\n\trv = 0;\n\tlastdownstreamtime = time(NULL);\n\tsend_query_sendcnt = 0;  /* start counting now */\n\n\twhile (running) {\n\t\ttv.tv_sec = selecttimeout;\n\t\ttv.tv_usec = 0;\n\n\t\tif (is_sending()) {\n\t\t\t/* fast timeout for retransmits */\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t}\n\n\t\tif (send_ping_soon) {\n\t\t\ttv.tv_sec = 0;\n\t\t\ttv.tv_usec = send_ping_soon * 1000;\n\t\t}\n\n\t\tFD_ZERO(&fds);\n\t\tif (!is_sending() || outchunkresent >= 2) {\n\t\t\t/* If re-sending upstream data, chances are that\n\t\t\t   we're several seconds behind already and TCP\n\t\t\t   will start filling tun buffer with (useless)\n\t\t\t   retransmits.\n\t\t\t   Get up-to-date fast by simply dropping stuff,\n\t\t\t   that's what TCP is designed to handle. */\n\t\t\tFD_SET(tun_fd, &fds);\n\t\t}\n\t\tFD_SET(dns_fd, &fds);\n\n\t\ti = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);\n\n \t\tif (lastdownstreamtime + 60 < time(NULL)) {\n \t\t\twarnx(\"No downstream data received in 60 seconds, shutting down.\");\n \t\t\trunning = 0;\n \t\t}\n\n\t\tif (running == 0)\n\t\t\tbreak;\n\n\t\tif (i < 0)\n\t\t\terr(1, \"select\");\n\n\t\tif (i == 0) {\n\t\t\t/* timeout */\n\t\t\tif (is_sending()) {\n\t\t\t\t/* Re-send current fragment; either frag\n\t\t\t\t   or ack probably dropped somewhere.\n\t\t\t\t   But problem: no cache-miss-counter,\n\t\t\t\t   so hostname will be identical.\n\t\t\t\t   Just drop whole packet after 3 retries,\n\t\t\t\t   and TCP retransmit will solve it.\n\t\t\t\t   NOTE: tun dropping above should be\n\t\t\t\t   >=(value_here - 1) */\n\t\t\t\tif (outchunkresent < 3) {\n\t\t\t\t\toutchunkresent++;\n\t\t\t\t\tsend_chunk(dns_fd);\n\t\t\t\t} else {\n\t\t\t\t\toutpkt.offset = 0;\n\t\t\t\t\toutpkt.len = 0;\n\t\t\t\t\toutpkt.sentlen = 0;\n\t\t\t\t\toutchunkresent = 0;\n\n\t\t\t\t\tsend_ping(dns_fd);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsend_ping(dns_fd);\n\t\t\t}\n\t\t\tsend_ping_soon = 0;\n\n\t\t} else {\n\n\t\t\tif (FD_ISSET(tun_fd, &fds)) {\n\t\t\t\tif (tunnel_tun(tun_fd, dns_fd) <= 0)\n\t\t\t\t\tcontinue;\n\t\t\t\t/* Returns -1 on error OR when quickly\n\t\t\t\t   dropping data in case of DNS congestion;\n\t\t\t\t   we need to _not_ do tunnel_dns() then.\n\t\t\t\t   If chunk sent, sets send_ping_soon=0. */\n\t\t\t}\n\t\t\tif (FD_ISSET(dns_fd, &fds)) {\n\t\t\t\tif (tunnel_dns(tun_fd, dns_fd) <= 0)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn rv;\n}\n\nstatic void\nsend_login(int fd, char *login, int len)\n{\n\tchar data[19];\n\n\tmemset(data, 0, sizeof(data));\n\tdata[0] = userid;\n\tmemcpy(&data[1], login, MIN(len, 16));\n\n\tdata[17] = (rand_seed >> 8) & 0xff;\n\tdata[18] = (rand_seed >> 0) & 0xff;\n\n\trand_seed++;\n\n\tsend_packet(fd, 'l', data, sizeof(data));\n}\n\nstatic void\nsend_fragsize_probe(int fd, int fragsize)\n{\n\tchar probedata[256];\n\tchar buf[4096];\n\n\t/*\n\t * build a large query domain which is random and maximum size,\n\t * will also take up maximal space in the return packet\n\t */\n\tmemset(probedata, MAX(1, rand_seed & 0xff), sizeof(probedata));\n\tprobedata[1] = MAX(1, (rand_seed >> 8) & 0xff);\n\trand_seed++;\n\n\t/* Note: must either be same, or larger, than send_chunk() */\n\tbuild_hostname(buf + 5, sizeof(buf) - 5, probedata, sizeof(probedata),\n\t\t       topdomain, dataenc, hostname_maxlen);\n\n\tfragsize &= 2047;\n\n\tbuf[0] = 'r'; /* Probe downstream fragsize packet */\n\tbuf[1] = b32_5to8((userid << 1) | ((fragsize >> 10) & 1));\n\tbuf[2] = b32_5to8((fragsize >> 5) & 31);\n\tbuf[3] = b32_5to8(fragsize & 31);\n\tbuf[4] = 'd'; /* dummy to match send_chunk() */\n\n\tsend_query(fd, buf);\n}\n\nstatic void\nsend_set_downstream_fragsize(int fd, int fragsize)\n{\n\tchar data[5];\n\n\tdata[0] = userid;\n\tdata[1] = (fragsize & 0xff00) >> 8;\n\tdata[2] = (fragsize & 0x00ff);\n\tdata[3] = (rand_seed >> 8) & 0xff;\n\tdata[4] = (rand_seed >> 0) & 0xff;\n\n\trand_seed++;\n\n\tsend_packet(fd, 'n', data, sizeof(data));\n}\n\nstatic void\nsend_version(int fd, uint32_t version)\n{\n\tchar data[6];\n\n\tdata[0] = (version >> 24) & 0xff;\n\tdata[1] = (version >> 16) & 0xff;\n\tdata[2] = (version >> 8) & 0xff;\n\tdata[3] = (version >> 0) & 0xff;\n\n\tdata[4] = (rand_seed >> 8) & 0xff;\n\tdata[5] = (rand_seed >> 0) & 0xff;\n\n\trand_seed++;\n\n\tsend_packet(fd, 'v', data, sizeof(data));\n}\n\n/* Add lower 15 bits of rand seed as base32,\n * followed by a dot and the tunnel domain and send */\nstatic void\nsend_handshake_query(int fd, char *prefix)\n{\n\tchar buf[300];\n\tchar cmc_dot[5];\n\n\tcmc_dot[0] = b32_5to8((rand_seed >> 10) & 0x1f);\n\tcmc_dot[1] = b32_5to8((rand_seed >> 5) & 0x1f);\n\tcmc_dot[2] = b32_5to8((rand_seed) & 0x1f);\n\tcmc_dot[3] = '.';\n\tcmc_dot[4] = 0;\n\trand_seed++;\n\n\tbuf[0] = 0;\n\tstrncat(buf, prefix, 60); /* 63 - space for 3 CMC bytes */\n\tstrcat(buf, cmc_dot);\n\tstrncat(buf, topdomain, sizeof(buf) - strlen(buf) - 1);\n\tsend_query(fd, buf);\n}\n\nstatic void\nsend_raw_udp_login(int dns_fd, int seed)\n{\n\tchar buf[16];\n\tlogin_calculate(buf, 16, password, seed + 1);\n\n\tsend_raw(dns_fd, buf, sizeof(buf), RAW_HDR_CMD_LOGIN);\n}\n\nstatic void\nsend_upenctest(int fd, const char *s)\n/* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */\n{\n\tchar buf[512] = \"z___\";\n\n\tbuf[1] = b32_5to8((rand_seed >> 10) & 0x1f);\n\tbuf[2] = b32_5to8((rand_seed >> 5) & 0x1f);\n\tbuf[3] = b32_5to8((rand_seed) & 0x1f);\n\trand_seed++;\n\n\tstrncat(buf, s, 128);\n\tstrncat(buf, \".\", 2);\n\tstrncat(buf, topdomain, 512 - strlen(buf));\n\tsend_query(fd, buf);\n}\n\nstatic void\nsend_downenctest(int fd, char downenc, int variant)\n{\n\tchar prefix[4] = \"y__\";\n\tprefix[1] = tolower(downenc);\n\tprefix[2] = b32_5to8(variant);\n\n\t/* Use send_query directly if we ever send more data here. */\n\tsend_handshake_query(fd, prefix);\n}\n\nstatic void\nsend_lazy_switch(int fd)\n{\n\tchar sw_lazy[] = { 'o', b32_5to8(userid), 'i', 0 };\n\n\tif (lazymode)\n\t\tsw_lazy[2] = 'l';\n\n\tsend_handshake_query(fd, sw_lazy);\n}\n\nstatic int\nhandshake_version(int dns_fd, int *seed)\n{\n\tchar hex[] = \"0123456789abcdef\";\n\tchar hex2[] = \"0123456789ABCDEF\";\n\tchar in[4096];\n\tuint32_t payload;\n\tint i;\n\tint read;\n\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_version(dns_fd, PROTOCOL_VERSION);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'v', 'V', i+1);\n\n\t\tif (read >= 9) {\n\t\t\tpayload =  (((in[4] & 0xff) << 24) |\n\t\t\t\t\t((in[5] & 0xff) << 16) |\n\t\t\t\t\t((in[6] & 0xff) << 8) |\n\t\t\t\t\t((in[7] & 0xff)));\n\n\t\t\tif (strncmp(\"VACK\", in, 4) == 0) {\n\t\t\t\t*seed = payload;\n\t\t\t\tuserid = in[8];\n\t\t\t\tuserid_char = hex[userid & 15];\n\t\t\t\tuserid_char2 = hex2[userid & 15];\n\n\t\t\t\tfprintf(stderr, \"Version ok, both using protocol v 0x%08x. You are user #%d\\n\",\n\t\t\t\t\tPROTOCOL_VERSION, userid);\n\t\t\t\treturn 0;\n\t\t\t} else if (strncmp(\"VNAK\", in, 4) == 0) {\n\t\t\t\twarnx(\"You use protocol v 0x%08x, server uses v 0x%08x. Giving up\",\n\t\t\t\t\t\tPROTOCOL_VERSION, payload);\n\t\t\t\treturn 1;\n\t\t\t} else if (strncmp(\"VFUL\", in, 4) == 0) {\n\t\t\t\twarnx(\"Server full, all %d slots are taken. Try again later\", payload);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t} else if (read > 0)\n\t\t\twarnx(\"did not receive proper login challenge\");\n\n\t\tfprintf(stderr, \"Retrying version check...\\n\");\n\t}\n\twarnx(\"couldn't connect to server (maybe other -T options will work)\");\n\treturn 1;\n}\n\nstatic int\nhandshake_login(int dns_fd, int seed)\n{\n\tchar in[4096];\n\tchar login[16];\n\tchar server[65];\n\tchar client[65];\n\tint mtu;\n\tint i;\n\tint read;\n\n\tlogin_calculate(login, 16, password, seed);\n\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_login(dns_fd, login, 16);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'l', 'L', i+1);\n\n\t\tif (read > 0) {\n\t\t\tint netmask;\n\t\t\tif (strncmp(\"LNAK\", in, 4) == 0) {\n\t\t\t\tfprintf(stderr, \"Bad password\\n\");\n\t\t\t\treturn 1;\n\t\t\t} else if (strncmp(\"BADIP\", in, 5) == 0) {\n\t\t\t\twarnx(\"BADIP: Server rejected sender IP address (maybe iodined -c will help)\");\n\t\t\t\treturn 1;\n\t\t\t} else if (sscanf(in, \"%64[^-]-%64[^-]-%d-%d\",\n\t\t\t\tserver, client, &mtu, &netmask) == 4) {\n\n\t\t\t\tserver[64] = 0;\n\t\t\t\tclient[64] = 0;\n\t\t\t\tif (tun_setip(client, server, netmask) == 0 &&\n\t\t\t\t\ttun_setmtu(mtu) == 0) {\n\n\t\t\t\t\tfprintf(stderr, \"Server tunnel IP is %s\\n\", server);\n\t\t\t\t\treturn 0;\n\t\t\t\t} else {\n\t\t\t\t\terrx(4, \"Failed to set IP and MTU\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfprintf(stderr, \"Received bad handshake\\n\");\n\t\t\t}\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying login...\\n\");\n\t}\n\twarnx(\"couldn't login to server\");\n\treturn 1;\n}\n\nstatic int\nhandshake_raw_udp(int dns_fd, int seed)\n{\n\tstruct timeval tv;\n\tchar get_ip[] = { 'i', b32_5to8(userid), 0 };\n\tchar in[4096];\n\tfd_set fds;\n\tint i;\n\tint r;\n\tint len;\n\tint got_addr;\n\n\tmemset(&raw_serv, 0, sizeof(raw_serv));\n\tgot_addr = 0;\n\n\tfprintf(stderr, \"Requesting server address to attempt raw UDP mode (skip with -r) \");\n\tfflush(stderr);\n\tfor (i = 0; running && i < 3; i++) {\n\n\t\tsend_handshake_query(dns_fd, get_ip);\n\n\t\tlen = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1);\n\n\t\tif (len == 5 && in[0] == 'I') {\n\t\t\t/* Received IPv4 address */\n\t\t\tstruct sockaddr_in *raw4_serv = (struct sockaddr_in *) &raw_serv;\n\t\t\traw4_serv->sin_family = AF_INET;\n\t\t\tmemcpy(&raw4_serv->sin_addr, &in[1], sizeof(struct in_addr));\n\t\t\traw4_serv->sin_port = htons(53);\n\t\t\traw_serv_len = sizeof(struct sockaddr_in);\n\t\t\tgot_addr = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif (len == 17 && in[0] == 'I') {\n\t\t\t/* Received IPv6 address */\n\t\t\tstruct sockaddr_in6 *raw6_serv = (struct sockaddr_in6 *) &raw_serv;\n\t\t\traw6_serv->sin6_family = AF_INET6;\n\t\t\tmemcpy(&raw6_serv->sin6_addr, &in[1], sizeof(struct in6_addr));\n\t\t\traw6_serv->sin6_port = htons(53);\n\t\t\traw_serv_len = sizeof(struct sockaddr_in6);\n\t\t\tgot_addr = 1;\n\t\t\tbreak;\n\t\t}\n\n\t\tfprintf(stderr, \".\");\n\t\tfflush(stderr);\n\t}\n\tfprintf(stderr, \"\\n\");\n\tif (!running)\n\t\treturn 0;\n\n\tif (!got_addr) {\n\t\tfprintf(stderr, \"Failed to get raw server IP, will use DNS mode.\\n\");\n\t\treturn 0;\n\t}\n\tfprintf(stderr, \"Server is at %s, trying raw login: (skip with -r) \",\n\t\tformat_addr(&raw_serv, raw_serv_len));\n\tfflush(stderr);\n\n\t/* do login against port 53 on remote server\n\t * based on the old seed. If reply received,\n\t * switch to raw udp mode */\n\tfor (i = 0; running && i < 4; i++) {\n\t\ttv.tv_sec = i + 1;\n\t\ttv.tv_usec = 0;\n\n\t\tsend_raw_udp_login(dns_fd, seed);\n\n\t\tFD_ZERO(&fds);\n\t\tFD_SET(dns_fd, &fds);\n\n\t\tr = select(dns_fd + 1, &fds, NULL, NULL, &tv);\n\n\t\tif (r > 0) {\n\t\t\t/* recv() needed for windows, dont change to read() */\n\t\t\tlen = recv(dns_fd, in, sizeof(in), 0);\n\t\t\tif (len >= (16 + RAW_HDR_LEN)) {\n\t\t\t\tchar hash[16];\n\t\t\t\tlogin_calculate(hash, 16, password, seed - 1);\n\t\t\t\tif (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0\n\t\t\t\t\t&& RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN\n\t\t\t\t\t&& memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0) {\n\n\t\t\t\t\tfprintf(stderr, \"OK\\n\");\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfprintf(stderr, \".\");\n\t\tfflush(stderr);\n\t}\n\n\tfprintf(stderr, \"failed\\n\");\n\treturn 0;\n}\n\nstatic int\nhandshake_upenctest(int dns_fd, const char *s)\n/* NOTE: *s may be max 59 chars; must start with \"aA\" for case-swap check\n   Returns:\n   -1: case swap, no need for any further test: error printed; or Ctrl-C\n   0: not identical or error or timeout\n   1: identical string returned\n*/\n{\n\tchar in[4096];\n\tunsigned char *uin = (unsigned char *) in;\n\tconst unsigned char *us = (const unsigned char *) s;\n\tint i;\n\tint read;\n\tint slen;\n\n\tslen = strlen(s);\n\tfor (i = 0; running && i < 3; i++) {\n\n\t\tsend_upenctest(dns_fd, s);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'z', 'Z', i+1);\n\n\t\tif (read == -2)\n\t\t\treturn 0;\t/* hard error */\n\n\t\tif (read > 0 && read < slen + 4)\n\t\t\treturn 0;\t/* reply too short (chars dropped) */\n\n\t\tif (read > 0) {\n\t\t\tint k;\n#if 0\n\t\t\t/* in[56] = '@'; */\n\t\t\t/* in[56] = '_'; */\n\t\t\t/* if (in[29] == '\\344') in[29] = 'a'; */\n\t\t\tin[read] = '\\0';\n\t\t\tfprintf(stderr, \"BounceReply: >%s<\\n\", in);\n#endif\n\t\t\t/* quick check if case swapped, to give informative error msg */\n\t\t\tif (in[4] == 'A') {\n\t\t\t\tfprintf(stderr, \"DNS queries get changed to uppercase, keeping upstream codec Base32\\n\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (in[5] == 'a') {\n\t\t\t\tfprintf(stderr, \"DNS queries get changed to lowercase, keeping upstream codec Base32\\n\");\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tfor (k = 0; k < slen; k++) {\n\t\t\t\tif (in[k+4] != s[k]) {\n\t\t\t\t\t/* Definitely not reliable */\n\t\t\t\t\tif (in[k+4] >= ' ' && in[k+4] <= '~' &&\n\t\t\t\t\t    s[k] >= ' ' && s[k] <= '~') {\n\t\t\t\t\t\tfprintf(stderr, \"DNS query char '%c' gets changed into '%c'\\n\",\n\t\t\t\t\t\t\ts[k], in[k+4]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfprintf(stderr, \"DNS query char 0x%02X gets changed into 0x%02X\\n\",\n\t\t\t\t\t\t\t(unsigned int) us[k],\n\t\t\t\t\t\t\t(unsigned int) uin[k+4]);\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* if still here, then all okay */\n\t\t\treturn 1;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying upstream codec test...\\n\");\n\t}\n\n\tif (!running)\n\t\treturn -1;\n\n\t/* timeout */\n\treturn 0;\n}\n\nstatic int\nhandshake_upenc_autodetect(int dns_fd)\n/* Returns:\n   0: keep Base32\n   1: Base64 is okay\n   2: Base64u is okay\n   3: Base128 is okay\n*/\n{\n\t/* Note: max 59 chars, must start with \"aA\".\n\t   pat64: If 0129 work, assume 3-8 are okay too.\n\n\t   RFC1035 par 2.3.1 states that [A-Z0-9-] allowed, but only\n\t   [A-Z] as first, and [A-Z0-9] as last char _per label_.\n\t   Test by having '-' as last char.\n\t */\n\tconst char *pat64 = \"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ+0129-\";\n\tconst char *pat64u = \"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ_0129-\";\n\tconst char *pat128a = \"aA-Aaahhh-Drink-mal-ein-J\\344germeister-\";\n\tconst char *pat128b = \"aA-La-fl\\373te-na\\357ve-fran\\347aise-est-retir\\351-\\340-Cr\\350te\";\n\tconst char *pat128c = \"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ\";\n\tconst char *pat128d = \"aA0123456789\\274\\275\\276\\277\"\n\t\t\"\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\317\";\n\tconst char *pat128e=\"aA\"\n\t\t\t\"\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\337\"\n\t\t\t\"\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\"\n\t\t\t\"\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\";\n\tint res;\n\n\t/* Try Base128, starting very gently to not draw attention */\n\twhile (1) {\n\t\tres = handshake_upenctest(dns_fd, pat128a);\n\t\tif (res < 0) {\n\t\t\t/* DNS swaps case, msg already printed; or Ctrl-C */\n\t\t\treturn 0;\n\t\t} else if (res == 0) {\n\t\t\t/* Probably not okay, skip Base128 entirely */\n\t\t\tbreak;\n\t\t}\n\n\t\tres = handshake_upenctest(dns_fd, pat128b);\n\t\tif (res < 0)\n\t\t\treturn 0;\n\t\telse if (res == 0)\n\t\t\tbreak;\n\n\t\t/* if this works, we can test the real stuff */\n\n\t\tres = handshake_upenctest(dns_fd, pat128c);\n\t\tif (res < 0)\n\t\t\treturn 0;\n\t\telse if (res == 0)\n\t\t\tbreak;\n\n\t\tres = handshake_upenctest(dns_fd, pat128d);\n\t\tif (res < 0)\n\t\t\treturn 0;\n\t\telse if (res == 0)\n\t\t\tbreak;\n\n\t\tres = handshake_upenctest(dns_fd, pat128e);\n\t\tif (res < 0)\n\t\t\treturn 0;\n\t\telse if (res == 0)\n\t\t\tbreak;\n\n\t\t/* if still here, then base128 works completely */\n\t\treturn 3;\n\t}\n\n\t/* Try Base64 (with plus sign) */\n\tres = handshake_upenctest(dns_fd, pat64);\n\tif (res < 0) {\n\t\t/* DNS swaps case, msg already printed; or Ctrl-C */\n\t\treturn 0;\n\t} else if (res > 0) {\n\t\t/* All okay, Base64 msg will be printed later */\n\t\treturn 1;\n\t}\n\n\t/* Try Base64u (with _u_nderscore) */\n\tres = handshake_upenctest(dns_fd, pat64u);\n\tif (res < 0) {\n\t\t/* DNS swaps case, msg already printed; or Ctrl-C */\n\t\treturn 0;\n\t} else if (res > 0) {\n\t\t/* All okay, Base64u msg will be printed later */\n\t\treturn 2;\n\t}\n\n\t/* if here, then nonthing worked */\n\tfprintf(stderr, \"Keeping upstream codec Base32\\n\");\n\treturn 0;\n}\n\nstatic int\nhandshake_downenctest(int dns_fd, char trycodec)\n/* Returns:\n   0: not identical or error or timeout\n   1: identical string returned\n*/\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\tchar *s = DOWNCODECCHECK1;\n\tint slen = DOWNCODECCHECK1_LEN;\n\n\tfor (i = 0; running && i < 3; i++) {\n\n\t\tsend_downenctest(dns_fd, trycodec, 1);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', i+1);\n\n\t\tif (read == -2)\n\t\t\treturn 0;\t/* hard error */\n\n\t\tif (read > 0 && read != slen)\n\t\t\treturn 0;\t/* reply incorrect = unreliable */\n\n\t\tif (read > 0) {\n\t\t\tint k;\n\t\t\tfor (k = 0; k < slen; k++) {\n\t\t\t\tif (in[k] != s[k]) {\n\t\t\t\t\t/* Definitely not reliable */\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* if still here, then all okay */\n\t\t\treturn 1;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying downstream codec test...\\n\");\n\t}\n\n\t/* timeout */\n\treturn 0;\n}\n\nstatic char\nhandshake_downenc_autodetect(int dns_fd)\n/* Returns codec char (or ' ' if no advanced codec works) */\n{\n\tint base64ok = 0;\n\tint base64uok = 0;\n\tint base128ok = 0;\n\n\tif (do_qtype == T_NULL || do_qtype == T_PRIVATE) {\n\t\t/* no other choice than raw */\n\t\tfprintf(stderr, \"No alternative downstream codec available, using default (Raw)\\n\");\n\t\treturn ' ';\n\t}\n\n\tfprintf(stderr, \"Autodetecting downstream codec (use -O to override)\\n\");\n\n\t/* Try Base64 */\n\tif (handshake_downenctest(dns_fd, 'S'))\n\t\tbase64ok = 1;\n\telse if (running && handshake_downenctest(dns_fd, 'U'))\n\t\tbase64uok = 1;\n\n\t/* Try Base128 only if 64 gives us some perspective */\n\tif (running && (base64ok || base64uok)) {\n\t\tif (handshake_downenctest(dns_fd, 'V'))\n\t\t\tbase128ok = 1;\n\t}\n\n\t/* If 128 works, then TXT may give us Raw as well */\n\tif (running && (base128ok && do_qtype == T_TXT)) {\n\t\tif (handshake_downenctest(dns_fd, 'R'))\n\t\t\treturn 'R';\n\t}\n\n\tif (!running)\n\t\treturn ' ';\n\n\tif (base128ok)\n\t\treturn 'V';\n\tif (base64ok)\n\t\treturn 'S';\n\tif (base64uok)\n\t\treturn 'U';\n\n\tfprintf(stderr, \"No advanced downstream codecs seem to work, using default (Base32)\\n\");\n\treturn ' ';\n}\n\nstatic int\nhandshake_qtypetest(int dns_fd, int timeout)\n/* Returns:\n   0: doesn't work with this timeout\n   1: works properly\n*/\n{\n\tchar in[4096];\n\tint read;\n\tchar *s = DOWNCODECCHECK1;\n\tint slen = DOWNCODECCHECK1_LEN;\n\tint trycodec;\n\tint k;\n\n\tif (do_qtype == T_NULL || do_qtype == T_PRIVATE)\n\t\ttrycodec = 'R';\n\telse\n\t\ttrycodec = 'T';\n\n\t/* We could use 'Z' bouncing here, but 'Y' also tests that 0-255\n\t   byte values can be returned, which is needed for NULL/PRIVATE\n\t   to work. */\n\n\tsend_downenctest(dns_fd, trycodec, 1);\n\n\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', timeout);\n\n\tif (read != slen)\n\t\treturn 0;\t/* incorrect */\n\n\tfor (k = 0; k < slen; k++) {\n\t\tif (in[k] != s[k]) {\n\t\t\t/* corrupted */\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/* if still here, then all okay */\n\treturn 1;\n}\n\nstatic int\nhandshake_qtype_numcvt(int num)\n{\n\tswitch (num) {\n\tcase 0:\treturn T_NULL;\n\tcase 1:\treturn T_PRIVATE;\n\tcase 2:\treturn T_TXT;\n\tcase 3:\treturn T_SRV;\n\tcase 4:\treturn T_MX;\n\tcase 5:\treturn T_CNAME;\n\tcase 6:\treturn T_A;\n\t}\n\treturn T_UNSET;\n}\n\nstatic int\nhandshake_qtype_autodetect(int dns_fd)\n/* Returns:\n   0: okay, do_qtype set\n   1: problem, program exit\n*/\n{\n\tint highestworking = 100;\n\tint timeout;\n\tint qtypenum;\n\n\tfprintf(stderr, \"Autodetecting DNS query type (use -T to override)\");\n\tfflush(stderr);\n\n\t/* Method: try all \"interesting\" qtypes with a 1-sec timeout, then try\n\t   all \"still-interesting\" qtypes with a 2-sec timeout, etc.\n\t   \"Interesting\" means: qtypes that (are expected to) have higher\n\t   bandwidth than what we know is working already (highestworking).\n\n\t   Note that DNS relays may not immediately resolve the first (NULL)\n\t   query in 1 sec, due to long recursive lookups, so we keep trying\n\t   to see if things will start working after a while.\n\t */\n\n\tfor (timeout = 1; running && timeout <= 3; timeout++) {\n\t\tfor (qtypenum = 0; running && qtypenum < highestworking; qtypenum++) {\n\t\t\tdo_qtype = handshake_qtype_numcvt(qtypenum);\n\t\t\tif (do_qtype == T_UNSET)\n\t\t\t\tbreak;\t/* this round finished */\n\n\t\t\tfprintf(stderr, \".\");\n\t\t\tfflush(stderr);\n\n\t\t\tif (handshake_qtypetest(dns_fd, timeout)) {\n\t\t\t\t/* okay */\n\t\t\t\thighestworking = qtypenum;\n#if 0\n\t\t\t\tfprintf(stderr, \" Type %s timeout %d works\\n\",\n\t\t\t\t\tclient_get_qtype(), timeout);\n#endif\n\t\t\t\tbreak;\n\t\t\t\t/* try others with longer timeout */\n\t\t\t}\n\t\t\t/* else: try next qtype with same timeout */\n\t\t}\n\t\tif (highestworking == 0)\n\t\t\t/* good, we have NULL; abort immediately */\n\t\t\tbreak;\n\t}\n\n\tfprintf(stderr, \"\\n\");\n\n\tif (!running) {\n\t\twarnx(\"Stopped while autodetecting DNS query type (try setting manually with -T)\");\n\t\treturn 1;  /* problem */\n\t}\n\n\t/* finished */\n\tdo_qtype = handshake_qtype_numcvt(highestworking);\n\n\tif (do_qtype == T_UNSET) {\n\t\t/* also catches highestworking still 100 */\n\t\twarnx(\"No suitable DNS query type found. Are you connected to a network?\");\n\t\twarnx(\"If you expect very long roundtrip delays, use -T explicitly.\");\n\t\twarnx(\"(Also, connecting to an \\\"ancient\\\" version of iodined won't work.)\");\n\t\treturn 1;  /* problem */\n\t}\n\n\t/* \"using qtype\" message printed in handshake function */\n\treturn 0;  /* okay */\n}\n\nstatic int\nhandshake_edns0_check(int dns_fd)\n/* Returns:\n   0: EDNS0 not supported; or Ctrl-C\n   1: EDNS0 works\n*/\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\tchar *s = DOWNCODECCHECK1;\n\tint slen = DOWNCODECCHECK1_LEN;\n\tchar trycodec;\n\n\tif (do_qtype == T_NULL)\n\t\ttrycodec = 'R';\n\telse\n\t\ttrycodec = 'T';\n\n\tfor (i = 0; running && i < 3; i++) {\n\n\t\tsend_downenctest(dns_fd, trycodec, 1);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', i+1);\n\n\t\tif (read == -2)\n\t\t\treturn 0;\t/* hard error */\n\n\t\tif (read > 0 && read != slen)\n\t\t\treturn 0;\t/* reply incorrect = unreliable */\n\n\t\tif (read > 0) {\n\t\t\tint k;\n\t\t\tfor (k = 0; k < slen; k++) {\n\t\t\t\tif (in[k] != s[k]) {\n\t\t\t\t\t/* Definitely not reliable */\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* if still here, then all okay */\n\t\t\treturn 1;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying EDNS0 support test...\\n\");\n\t}\n\n\t/* timeout or Ctrl-C */\n\treturn 0;\n}\n\nstatic void\nhandshake_switch_codec(int dns_fd, int bits)\n{\n\tchar sw_codec[] = { 's', b32_5to8(userid), b32_5to8(bits), 0 };\n\tchar in[4096];\n\tint i;\n\tint read;\n\tconst struct encoder *tempenc;\n\n\tif (bits == 5)\n\t\ttempenc = &base32_ops;\n\telse if (bits == 6)\n\t\ttempenc = &base64_ops;\n\telse if (bits == 26)\t/* \"2nd\" 6 bits per byte, with underscore */\n\t\ttempenc = &base64u_ops;\n\telse if (bits == 7)\n\t\ttempenc = &base128_ops;\n\telse return;\n\n\tfprintf(stderr, \"Switching upstream to codec %s\\n\", tempenc->name);\n\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_handshake_query(dns_fd, sw_codec);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 's', 'S', i+1);\n\n\t\tif (read > 0) {\n\t\t\tif (strncmp(\"BADLEN\", in, 6) == 0) {\n\t\t\t\tfprintf(stderr, \"Server got bad message length. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADIP\", in, 5) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected sender IP address. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADCODEC\", in, 8) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected the selected codec. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t}\n\t\t\tin[read] = 0; /* zero terminate */\n\t\t\tfprintf(stderr, \"Server switched upstream to codec %s\\n\", in);\n\t\t\tdataenc = tempenc;\n\t\t\treturn;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying codec switch...\\n\");\n\t}\n\tif (!running)\n\t\treturn;\n\n\tfprintf(stderr, \"No reply from server on codec switch. \");\n\ncodec_revert:\n\tfprintf(stderr, \"Falling back to upstream codec %s\\n\", dataenc->name);\n}\n\nstatic void\nhandshake_switch_downenc(int dns_fd)\n{\n\tchar sw_downenc[] = { 'o', b32_5to8(userid), tolower(downenc), 0 };\n\tchar in[4096];\n\tint i;\n\tint read;\n\tchar *dname;\n\n\tdname = \"Base32\";\n\tif (downenc == 'S')\n\t\tdname = \"Base64\";\n\telse if (downenc == 'U')\n\t\tdname = \"Base64u\";\n\telse if (downenc == 'V')\n\t\tdname = \"Base128\";\n\telse if (downenc == 'R')\n\t\tdname = \"Raw\";\n\n\tfprintf(stderr, \"Switching downstream to codec %s\\n\", dname);\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_handshake_query(dns_fd, sw_downenc);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1);\n\n\t\tif (read > 0) {\n\t\t\tif (strncmp(\"BADLEN\", in, 6) == 0) {\n\t\t\t\tfprintf(stderr, \"Server got bad message length. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADIP\", in, 5) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected sender IP address. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADCODEC\", in, 8) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected the selected codec. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t}\n\t\t\tin[read] = 0; /* zero terminate */\n\t\t\tfprintf(stderr, \"Server switched downstream to codec %s\\n\", in);\n\t\t\treturn;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying codec switch...\\n\");\n\t}\n\tif (!running)\n\t\treturn;\n\n\tfprintf(stderr, \"No reply from server on codec switch. \");\n\ncodec_revert:\n\tfprintf(stderr, \"Falling back to downstream codec Base32\\n\");\n}\n\nstatic void\nhandshake_try_lazy(int dns_fd)\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\n\tfprintf(stderr, \"Switching to lazy mode for low-latency\\n\");\n\tfor (i = 0; running && i < 5 ;i++) {\n\n\t\tsend_lazy_switch(dns_fd);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1);\n\n\t\tif (read > 0) {\n\t\t\tif (strncmp(\"BADLEN\", in, 6) == 0) {\n\t\t\t\tfprintf(stderr, \"Server got bad message length. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADIP\", in, 5) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected sender IP address. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"BADCODEC\", in, 8) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected lazy mode. \");\n\t\t\t\tgoto codec_revert;\n\t\t\t} else if (strncmp(\"Lazy\", in, 4) == 0) {\n\t\t\t\tfprintf(stderr, \"Server switched to lazy mode\\n\");\n\t\t\t\tlazymode = 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying lazy mode switch...\\n\");\n\t}\n\tif (!running)\n\t\treturn;\n\n\tfprintf(stderr, \"No reply from server on lazy switch. \");\n\ncodec_revert:\n\tfprintf(stderr, \"Falling back to legacy mode\\n\");\n\tlazymode = 0;\n\tselecttimeout = 1;\n}\n\nstatic void\nhandshake_lazyoff(int dns_fd)\n/* Used in the middle of data transfer, timing is different and no error msgs */\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_lazy_switch(dns_fd);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', 1);\n\n\t\tif (read == 9 && strncmp(\"Immediate\", in, 9) == 0) {\n\t\t\twarnx(\"Server switched back to legacy mode.\\n\");\n\t\t\tlazymode = 0;\n\t\t\tselecttimeout = 1;\n\t\t\treturn;\n\t\t}\n\t}\n\tif (!running)\n\t\treturn;\n\n\twarnx(\"No reply from server on legacy mode switch.\\n\");\n}\n\nstatic int\nfragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize)\n/* Returns: 0: keep checking, 1: break loop (either okay or definitely wrong) */\n{\n\tint acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);\n\tint okay;\n\tint i;\n\tunsigned int v;\n\n\tif (read >= 5 && strncmp(\"BADIP\", in, 5) == 0) {\n\t\tfprintf(stderr, \"got BADIP (Try iodined -c)..\\n\");\n\t\tfflush(stderr);\n\t\treturn 0;\t\t/* maybe temporary error */\n\t}\n\n\tif (acked_fragsize != proposed_fragsize) {\n\t\t/*\n\t\t * got ack for wrong fragsize, maybe late response for\n\t\t * earlier query, or ack corrupted\n\t\t */\n\t\treturn 0;\n\t}\n\n\tif (read != proposed_fragsize) {\n\t\t/*\n\t\t * correctly acked fragsize but read too little (or too\n\t\t * much): this fragsize is definitely not reliable\n\t\t */\n\t\treturn 1;\n\t}\n\n\t/* here: read == proposed_fragsize == acked_fragsize */\n\n\t/* test: */\n\t/* in[123] = 123; */\n\n\tif ((in[2] & 0xff) != 107) {\n\t\tfprintf(stderr, \"\\n\");\n\t\twarnx(\"corruption at byte 2, this won't work. Try -O Base32, or other -T options.\");\n\t\t*max_fragsize = -1;\n\t\treturn 1;\n\t}\n\n\t/* Check for corruption */\n\tokay = 1;\n\tv = in[3] & 0xff;\n\n\tfor (i = 3; i < read; i++, v = (v + 107) & 0xff)\n\t\tif ((in[i] & 0xff) != v) {\n\t\t\tokay = 0;\n\t\t\tbreak;\n\t\t}\n\n\tif (okay) {\n\t\tfprintf(stderr, \"%d ok.. \", acked_fragsize);\n\t\tfflush(stderr);\n\t\t*max_fragsize = acked_fragsize;\n\t\treturn 1;\n\t} else {\n\t\tif (downenc != ' ' && downenc != 'T') {\n\t\t\tfprintf(stderr, \"%d corrupted at %d.. (Try -O Base32)\\n\", acked_fragsize, i);\n\t\t} else {\n\t\t\tfprintf(stderr, \"%d corrupted at %d.. \", acked_fragsize, i);\n\t\t}\n\t\tfflush(stderr);\n\t\treturn 1;\n\t}\n\n\t/* notreached */\n\treturn 1;\n}\n\n\nstatic int\nhandshake_autoprobe_fragsize(int dns_fd)\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\tint proposed_fragsize = 768;\n\tint range = 768;\n\tint max_fragsize;\n\n\tmax_fragsize = 0;\n\tfprintf(stderr, \"Autoprobing max downstream fragment size... (skip with -m fragsize)\\n\");\n\twhile (running && range > 0 && (range >= 8 || max_fragsize < 300)) {\n\t\t/* stop the slow probing early when we have enough bytes anyway */\n\t\tfor (i = 0; running && i < 3; i++) {\n\n\t\t\tsend_fragsize_probe(dns_fd, proposed_fragsize);\n\n\t\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'r', 'R', 1);\n\n\t\t\tif (read > 0) {\n\t\t\t\t/* We got a reply */\n\t\t\t\tif (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1)\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfprintf(stderr, \".\");\n\t\t\tfflush(stderr);\n\t\t}\n\t\tif (max_fragsize < 0)\n\t\t\tbreak;\n\n\t\trange >>= 1;\n\t\tif (max_fragsize == proposed_fragsize) {\n\t\t\t/* Try bigger */\n\t\t\tproposed_fragsize += range;\n\t\t} else {\n\t\t\t/* Try smaller */\n\t\t\tfprintf(stderr, \"%d not ok.. \", proposed_fragsize);\n\t\t\tfflush(stderr);\n\t\t\tproposed_fragsize -= range;\n\t\t}\n\t}\n\tif (!running) {\n\t\tfprintf(stderr, \"\\n\");\n\t\twarnx(\"stopped while autodetecting fragment size (Try setting manually with -m)\");\n\t\treturn 0;\n\t}\n\tif (max_fragsize <= 2) {\n\t\t/* Tried all the way down to 2 and found no good size.\n\t\t   But we _did_ do all handshake before this, so there must\n\t\t   be some workable connection. */\n\t\tfprintf(stderr, \"\\n\");\n\t\twarnx(\"found no accepted fragment size.\");\n\t\twarnx(\"try setting -M to 200 or lower, or try other -T or -O options.\");\n\t\treturn 0;\n\t}\n\t/* data header adds 2 bytes */\n\tfprintf(stderr, \"will use %d-2=%d\\n\", max_fragsize, max_fragsize - 2);\n\n\t/* need 1200 / 16frags = 75 bytes fragsize */\n\tif (max_fragsize < 82) {\n\t\tfprintf(stderr, \"Note: this probably won't work well.\\n\");\n\t\tfprintf(stderr, \"Try setting -M to 200 or lower, or try other DNS types (-T option).\\n\");\n\t} else if (max_fragsize < 202 &&\n\t    (do_qtype == T_NULL || do_qtype == T_PRIVATE || do_qtype == T_TXT ||\n\t     do_qtype == T_SRV || do_qtype == T_MX)) {\n\t\tfprintf(stderr, \"Note: this isn't very much.\\n\");\n\t\tfprintf(stderr, \"Try setting -M to 200 or lower, or try other DNS types (-T option).\\n\");\n\t}\n\n\treturn max_fragsize - 2;\n}\n\nstatic void\nhandshake_set_fragsize(int dns_fd, int fragsize)\n{\n\tchar in[4096];\n\tint i;\n\tint read;\n\n\tfprintf(stderr, \"Setting downstream fragment size to max %d...\\n\", fragsize);\n\tfor (i = 0; running && i < 5; i++) {\n\n\t\tsend_set_downstream_fragsize(dns_fd, fragsize);\n\n\t\tread = handshake_waitdns(dns_fd, in, sizeof(in), 'n', 'N', i+1);\n\n\t\tif (read > 0) {\n\n\t\t\tif (strncmp(\"BADFRAG\", in, 7) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected fragsize. Keeping default.\");\n\t\t\t\treturn;\n\t\t\t} else if (strncmp(\"BADIP\", in, 5) == 0) {\n\t\t\t\tfprintf(stderr, \"Server rejected sender IP address.\\n\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* The server returns the accepted fragsize:\n\t\t\taccepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff) */\n\t\t\treturn;\n\t\t}\n\n\t\tfprintf(stderr, \"Retrying set fragsize...\\n\");\n\t}\n\tif (!running)\n\t\treturn;\n\n\tfprintf(stderr, \"No reply from server when setting fragsize. Keeping default.\\n\");\n}\n\nint\nclient_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize)\n{\n\tint seed;\n\tint upcodec;\n\tint r;\n\n\tdnsc_use_edns0 = 0;\n\n\t/* qtype message printed in handshake function */\n\tif (do_qtype == T_UNSET) {\n\t\tr = handshake_qtype_autodetect(dns_fd);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\t}\n\n\tfprintf(stderr, \"Using DNS type %s queries\\n\", client_get_qtype());\n\n\tr = handshake_version(dns_fd, &seed);\n\tif (r) {\n\t\treturn r;\n\t}\n\n\tr = handshake_login(dns_fd, seed);\n\tif (r) {\n\t\treturn r;\n\t}\n\n\tif (raw_mode && handshake_raw_udp(dns_fd, seed)) {\n\t\tconn = CONN_RAW_UDP;\n\t\tselecttimeout = 20;\n\t} else {\n\t\tif (raw_mode == 0) {\n\t\t\tfprintf(stderr, \"Skipping raw mode\\n\");\n\t\t}\n\n\t\tdnsc_use_edns0 = 1;\n\t\tif (handshake_edns0_check(dns_fd) && running) {\n\t\t\tfprintf(stderr, \"Using EDNS0 extension\\n\");\n\t\t} else if (!running) {\n\t\t\treturn -1;\n\t\t} else {\n\t\t\tfprintf(stderr, \"DNS relay does not support EDNS0 extension\\n\");\n\t\t\tdnsc_use_edns0 = 0;\n\t\t}\n\n\t\tupcodec = handshake_upenc_autodetect(dns_fd);\n\t\tif (!running)\n\t\t\treturn -1;\n\n\t\tif (upcodec == 1) {\n\t\t\thandshake_switch_codec(dns_fd, 6);\n\t\t} else if (upcodec == 2) {\n\t\t\thandshake_switch_codec(dns_fd, 26);\n\t\t} else if (upcodec == 3) {\n\t\t\thandshake_switch_codec(dns_fd, 7);\n\t\t}\n\t\tif (!running)\n\t\t\treturn -1;\n\n\t\tif (downenc == ' ') {\n\t\t\tdownenc = handshake_downenc_autodetect(dns_fd);\n\t\t}\n\t\tif (!running)\n\t\t\treturn -1;\n\n\t\tif (downenc != ' ') {\n\t\t\thandshake_switch_downenc(dns_fd);\n\t\t}\n\t\tif (!running)\n\t\t\treturn -1;\n\n\t\tif (lazymode) {\n\t\t\thandshake_try_lazy(dns_fd);\n\t\t}\n\t\tif (!running)\n\t\t\treturn -1;\n\n\t\tif (autodetect_frag_size) {\n\t\t\tfragsize = handshake_autoprobe_fragsize(dns_fd);\n\t\t\tif (!fragsize) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\n\t\thandshake_set_fragsize(dns_fd, fragsize);\n\t\tif (!running)\n\t\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n"
  },
  {
    "path": "src/client.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __CLIENT_H__\n#define __CLIENT_H__\n\nvoid client_init(void);\nvoid client_stop(void);\n\nenum connection client_get_conn(void);\nconst char *client_get_raw_addr(void);\n\nvoid client_set_nameserver(struct sockaddr_storage *, int);\nvoid client_set_topdomain(const char *cp);\nvoid client_set_password(const char *cp);\nint client_set_qtype(char *qtype);\nchar *client_get_qtype(void);\nvoid client_set_downenc(char *encoding);\nvoid client_set_selecttimeout(int select_timeout);\nvoid client_set_lazymode(int lazy_mode);\nvoid client_set_hostname_maxlen(int i);\n\nint client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size,\n\t\t     int fragsize);\nint client_tunnel(int tun_fd, int dns_fd);\n\n#endif\n"
  },
  {
    "path": "src/common.c",
    "content": "/* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n * Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <time.h>\n#include <sys/types.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <unistd.h>\n#include <string.h>\n#include <ctype.h>\n#include <fcntl.h>\n#include <errno.h>\n\n#ifdef WINDOWS32\n#include <winsock2.h>\n#include <conio.h>\n#else\n#include <arpa/nameser.h>\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n#include <termios.h>\n#include <err.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <syslog.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#endif\n\n#ifdef HAVE_SETCON\n# include <selinux/selinux.h>\n#endif\n\n#include \"common.h\"\n\n/* The raw header used when not using DNS protocol */\nconst unsigned char raw_header[RAW_HDR_LEN] = { 0x10, 0xd1, 0x9e, 0x00 };\n\n/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */\n#if !defined(ANDROID) && !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__) && !defined(__HAIKU__)\nstatic int daemon(int nochdir, int noclose)\n{\n \tint fd, i;\n\n \tswitch (fork()) {\n \t\tcase 0:\n \t\t\tbreak;\n \t\tcase -1:\n \t\t\treturn -1;\n \t\tdefault:\n \t\t\t_exit(0);\n \t}\n\n \tif (!nochdir) {\n \t\tchdir(\"/\");\n \t}\n\n \tif (setsid() < 0) {\n \t\treturn -1;\n \t}\n\n \tif (!noclose) {\n \t\tif ((fd = open(\"/dev/null\", O_RDWR)) >= 0) {\n \t\t\tfor (i = 0; i < 3; i++) {\n \t\t\t\tdup2(fd, i);\n \t\t\t}\n \t\t\tif (fd > 2) {\n \t\t\t\tclose(fd);\n \t\t\t}\n \t\t}\n \t}\n\treturn 0;\n}\n#endif\n\n#if defined(__BEOS__) && !defined(__HAIKU__)\nint setgroups(int count, int *groups)\n{\n\t/* errno = ENOSYS; */\n\treturn -1;\n}\n#endif\n\n#ifndef WINDOWS32\nvoid\ncheck_superuser(void)\n{\n\tif (geteuid() != 0) {\n\t\twarnx(\"Run as root and you'll be happy.\");\n\t\texit(-1);\n\t}\n}\n#endif\n\nchar *\nformat_addr(struct sockaddr_storage *sockaddr, int sockaddr_len)\n{\n\tstatic char dst[INET6_ADDRSTRLEN + 1];\n\n\tmemset(dst, 0, sizeof(dst));\n\tif (sockaddr->ss_family == AF_INET && sockaddr_len >= sizeof(struct sockaddr_in)) {\n\t\tgetnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST);\n\t} else if (sockaddr->ss_family == AF_INET6 && sockaddr_len >= sizeof(struct sockaddr_in6)) {\n\t\tstruct sockaddr_in6 *addr = (struct sockaddr_in6 *) sockaddr;\n\t\tif (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {\n\t\t\tstruct in_addr ia;\n\t\t\t/* Get mapped v4 addr from last 32bit field */\n\t\t\tmemcpy(&ia.s_addr, &addr->sin6_addr.s6_addr[12], sizeof(ia));\n\t\t\tstrcpy(dst, inet_ntoa(ia));\n\t\t} else {\n\t\t\tgetnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST);\n\t\t}\n\t} else {\n\t\tdst[0] = '?';\n\t}\n\treturn dst;\n}\n\nint\nget_addr(char *host, int port, int addr_family, int flags, struct sockaddr_storage *out)\n{\n\tstruct addrinfo hints, *addr;\n\tint res;\n\tchar portnum[8];\n\tint addrlen;\n\n\tmemset(portnum, 0, sizeof(portnum));\n\tsnprintf(portnum, sizeof(portnum) - 1, \"%d\", port);\n\n\tmemset(&hints, 0, sizeof(hints));\n\thints.ai_family = addr_family;\n#if defined(WINDOWS32) || defined(OPENBSD)\n\t/* AI_ADDRCONFIG misbehaves on windows, and does not exist in OpenBSD */\n\thints.ai_flags = flags;\n#else\n\thints.ai_flags = AI_ADDRCONFIG | flags;\n#endif\n\thints.ai_socktype = SOCK_DGRAM;\n\thints.ai_protocol = IPPROTO_UDP;\n\n\tres = getaddrinfo(host, portnum, &hints, &addr);\n\tif (res != 0) {\n\t\treturn -1;\n\t}\n\t\n\taddrlen = addr->ai_addrlen;\n\t/* Grab first result */\n\tmemcpy(out, addr->ai_addr, addr->ai_addrlen);\n\tfreeaddrinfo(addr);\n\treturn addrlen;\n}\n\nint\nopen_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len)\n{\n\treturn open_dns_opt(sockaddr, sockaddr_len, -1);\n}\n\nint\nopen_dns_opt(struct sockaddr_storage *sockaddr, size_t sockaddr_len, int v6only)\n{\n\tint flag;\n\tint fd;\n\n\tif ((fd = socket(sockaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {\n\t\terr(1, \"socket\");\n\t}\n\n\tflag = 1;\n#ifdef SO_REUSEPORT\n\tsetsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));\n#endif\n\tsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));\n\n#ifndef WINDOWS32\n\tfd_set_close_on_exec(fd);\n#endif\n\n\tif (sockaddr->ss_family == AF_INET6 && v6only >= 0) {\n\t\tsetsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*) &v6only, sizeof(v6only));\n\t}\n\n#ifdef IP_OPT_DONT_FRAG\n\t/* Set dont-fragment ip header flag */\n\tflag = DONT_FRAG_VALUE;\n\tsetsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));\n#endif\n\n\tif (bind(fd, (struct sockaddr*) sockaddr, sockaddr_len) < 0)\n\t\terr(1, \"bind() to %s\", format_addr(sockaddr, sockaddr_len));\n\n\tfprintf(stderr, \"Opened IPv%d UDP socket\\n\", sockaddr->ss_family == AF_INET6 ? 6 : 4);\n\n\treturn fd;\n}\n\nint\nopen_dns_from_host(char *host, int port, int addr_family, int flags)\n{\n\tstruct sockaddr_storage addr;\n\tint addrlen;\n\n\taddrlen = get_addr(host, port, addr_family, flags, &addr);\n\tif (addrlen < 0)\n\t\treturn addrlen;\n\n\treturn open_dns(&addr, addrlen);\n}\n\nvoid\nclose_dns(int fd)\n{\n\tclose(fd);\n}\n\nvoid\ndo_chroot(char *newroot)\n{\n#if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))\n\tif (chroot(newroot) != 0 || chdir(\"/\") != 0)\n\t\terr(1, \"%s\", newroot);\n\n\tif (seteuid(geteuid()) != 0 || setuid(getuid()) != 0) {\n\t\terr(1, \"set[e]uid()\");\n\t}\n#else\n\twarnx(\"chroot not available\");\n#endif\n}\n\nvoid\ndo_setcon(char *context)\n{\n#ifdef HAVE_SETCON\n\tif (-1 == setcon(context))\n\t\terr(1, \"%s\", context);\n#else\n\twarnx(\"No SELinux support built in\");\n#endif\n}\n\nvoid\ndo_pidfile(char *pidfile)\n{\n#ifndef WINDOWS32\n\tFILE *file;\n\n\tif ((file = fopen(pidfile, \"w\")) == NULL) {\n\t\tsyslog(LOG_ERR, \"Cannot write pidfile to %s, exiting\", pidfile);\n\t\terr(1, \"do_pidfile: Can not write pidfile to %s\", pidfile);\n\t} else {\n\t\tfprintf(file, \"%d\\n\", (int)getpid());\n\t\tfclose(file);\n\t}\n#else\n\tfprintf(stderr, \"Windows version does not support pid file\\n\");\n#endif\n}\n\nvoid\ndo_detach(void)\n{\n#ifndef WINDOWS32\n\tfprintf(stderr, \"Detaching from terminal...\\n\");\n\tdaemon(0, 0);\n\tumask(0);\n\talarm(0);\n#else\n\tfprintf(stderr, \"Windows version does not support detaching\\n\");\n#endif\n}\n\nvoid\nread_password(char *buf, size_t len)\n{\n\tchar pwd[80] = {0};\n#ifndef WINDOWS32\n\tstruct termios old;\n\tstruct termios tp;\n\n\ttcgetattr(0, &tp);\n\told = tp;\n\n\ttp.c_lflag &= (~ECHO);\n\ttcsetattr(0, TCSANOW, &tp);\n#else\n\tint i;\n#endif\n\n\tfprintf(stderr, \"Enter tunnel password: \");\n\tfflush(stderr);\n#ifndef WINDOWS32\n\tfscanf(stdin, \"%79[^\\n]\", pwd);\n#else\n\tfor (i = 0; i < sizeof(pwd); i++) {\n\t\tpwd[i] = getch();\n\t\tif (pwd[i] == '\\r' || pwd[i] == '\\n') {\n\t\t\tpwd[i] = 0;\n\t\t\tbreak;\n\t\t} else if (pwd[i] == '\\b') {\n\t\t\ti--; \t\t\t/* Remove the \\b char */\n\t\t\tif (i >=0) i--; \t/* If not first char, remove one more */\n\t\t}\n\t}\n#endif\n\tfprintf(stderr, \"\\n\");\n\n#ifndef WINDOWS32\n\ttcsetattr(0, TCSANOW, &old);\n#endif\n\n\tstrncpy(buf, pwd, len);\n\tbuf[len-1] = '\\0';\n}\n\nint\ncheck_topdomain(char *str, int allow_wildcard, char **errormsg)\n{\n\tint i;\n\tint dots = 0;\n\tint chunklen = 0;\n\n\tif (strlen(str) < 3) {\n\t\tif (errormsg) *errormsg = \"Too short (< 3)\";\n\t\treturn 1;\n\t}\n\tif (strlen(str) > 128) {\n\t\tif (errormsg) *errormsg = \"Too long (> 128)\";\n\t\treturn 1;\n\t}\n\n\tif (str[0] == '.') {\n\t\tif (errormsg) *errormsg = \"Starts with a dot\";\n\t\treturn 1;\n\t}\n\n\tfor (i = 0; i < strlen(str); i++) {\n\t\tif (str[i] == '.') {\n\t\t\tdots++;\n\t\t\tif (chunklen == 0) {\n\t\t\t\tif (errormsg) *errormsg = \"Consecutive dots\";\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif (chunklen > 63) {\n\t\t\t\tif (errormsg) *errormsg = \"Too long domain part (> 63)\";\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tchunklen = 0;\n\t\t} else {\n\t\t\tchunklen++;\n\t\t}\n\t\tif ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') ||\n\t\t\t\tisdigit(str[i]) || str[i] == '-' || str[i] == '.') {\n\t\t\tcontinue;\n\t\t} else if (allow_wildcard && str[i] == '*') {\n\t\t\t/* First char allowed to be wildcard, if followed by dot */\n\t\t\tif (i == 0) {\n\t\t\t\tif (str[i+1] == '.') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (errormsg) *errormsg = \"Wildcard (*) must be followed by dot\";\n\t\t\t\treturn 1;\n\t\t\t} else {\n\t\t\t\tif (errormsg) *errormsg = \"Wildcard (*) only allowed as first char\";\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t} else {\n\t\t\tif (errormsg) *errormsg = \"Contains illegal character (allowed: [a-zA-Z0-9-.])\";\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif (dots == 0) {\n\t\tif (errormsg) *errormsg = \"No dots\";\n\t\treturn 1;\n\t}\n\tif (chunklen == 0) {\n\t\tif (errormsg) *errormsg = \"Ends with a dot\";\n\t\treturn 1;\n\t}\n\tif (chunklen > 63) {\n\t\tif (errormsg) *errormsg = \"Too long domain part (> 63)\";\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint\nquery_datalen(const char *qname, const char *topdomain)\n{\n\t/* Return number of data bytes embedded in DNS query name,\n\t * or -1 if domains do not match.\n\t */\n\tint qpos = strlen(qname);\n\tint tpos = strlen(topdomain);\n\tif (tpos < 3 || qpos < tpos) {\n\t\t/* Domain or query name too short */\n\t\treturn -1;\n\t}\n\t/* Backward string compare */\n\tqpos--;\n\ttpos--;\n\twhile (qpos >= 0) {\n\t\tif (topdomain[tpos] == '*') {\n\t\t\t/* Wild match, is first in topdomain */\n\t\t\tif (qname[qpos] == '*') {\n\t\t\t\t/* Don't match against stars in query name */\n\t\t\t\treturn -1;\n\t\t\t} else if (qpos == 0 || qname[qpos-1] == '.') {\n\t\t\t\t/* Reached start of query name or chunk separator */\n\t\t\t\treturn qpos;\n\t\t\t}\n\t\t\tqpos--;\n\t\t} else if (tolower(qname[qpos]) == tolower(topdomain[tpos])) {\n\t\t\t/* Matching char, exclude wildcard in query name */\n\t\t\tif (tpos == 0) {\n\t\t\t\t/* Fully matched domain */\n\t\t\t\tif (qpos == 0 || qname[qpos-1] == '.') {\n\t\t\t\t\t/* Start of name or has dot before matching topdomain */\n\t\t\t\t\treturn qpos;\n\t\t\t\t}\n\t\t\t\t/* Query name has longer chunk than topdomain */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\ttpos--;\n\t\t\tqpos--;\n\t\t} else {\n\t\t\treturn -1;\n\t\t}\n\t}\n\treturn -1;\n}\n\n#if defined(WINDOWS32) || defined(ANDROID)\n#ifndef ANDROID\nint\ninet_aton(const char *cp, struct in_addr *inp)\n{\n inp->s_addr = inet_addr(cp);\n return inp->s_addr != INADDR_ANY;\n}\n#endif\n\nvoid\nvwarn(const char *fmt, va_list list)\n{\n\tif (fmt) vfprintf(stderr, fmt, list);\n#ifndef ANDROID\n\tif (errno == 0) {\n\t\tfprintf(stderr, \": WSA error %d\\n\", WSAGetLastError());\n\t} else {\n\t\tfprintf(stderr, \": %s\\n\", strerror(errno));\n\t}\n#endif\n}\n\nvoid\nwarn(const char *fmt, ...)\n{\n\tva_list list;\n\n\tva_start(list, fmt);\n\tvwarn(fmt, list);\n\tva_end(list);\n}\n\nvoid\nerr(int eval, const char *fmt, ...)\n{\n\tva_list list;\n\n\tva_start(list, fmt);\n\tvwarn(fmt, list);\n\tva_end(list);\n\texit(eval);\n}\n\nvoid\nvwarnx(const char *fmt, va_list list)\n{\n\tif (fmt) vfprintf(stderr, fmt, list);\n\tfprintf(stderr, \"\\n\");\n}\n\nvoid\nwarnx(const char *fmt, ...)\n{\n\tva_list list;\n\n\tva_start(list, fmt);\n\tvwarnx(fmt, list);\n\tva_end(list);\n}\n\nvoid\nerrx(int eval, const char *fmt, ...)\n{\n\tva_list list;\n\n\tva_start(list, fmt);\n\tvwarnx(fmt, list);\n\tva_end(list);\n\texit(eval);\n}\n#endif\n\n\nint recent_seqno(int ourseqno, int gotseqno)\n/* Return 1 if we've seen gotseqno recently (current or up to 3 back).\n   Return 0 if gotseqno is new (or very old).\n*/\n{\n\tint i;\n\tfor (i = 0; i < 4; i++, ourseqno--) {\n\t\tif (ourseqno < 0)\n\t\t\tourseqno = 7;\n\t\tif (gotseqno == ourseqno)\n\t\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n#ifndef WINDOWS32\n/* Set FD_CLOEXEC flag on file descriptor.\n * This stops it from being inherited by system() calls.\n */\nvoid\nfd_set_close_on_exec(int fd)\n{\n\tint flags;\n\n\tflags = fcntl(fd, F_GETFD);\n\tif (flags == -1)\n\t\terr(4, \"Failed to get fd flags\");\n\tflags |= FD_CLOEXEC;\n\tif (fcntl(fd, F_SETFD, flags) == -1)\n\t\terr(4, \"Failed to set fd flags\");\n}\n#endif\n\n"
  },
  {
    "path": "src/common.h",
    "content": "/*\n * Copyright (c) 2006-2015 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __COMMON_H__\n#define __COMMON_H__\n\n/* Last byte of raw header is the command */\n#define RAW_HDR_LEN 4\n#define RAW_HDR_IDENT_LEN 3\n#define RAW_HDR_CMD 3\n#define RAW_HDR_CMD_LOGIN 0x10\n#define RAW_HDR_CMD_DATA  0x20\n#define RAW_HDR_CMD_PING  0x30\n\n#define RAW_HDR_CMD_MASK  0xF0\n#define RAW_HDR_USR_MASK  0x0F\n#define RAW_HDR_GET_CMD(x) ((x)[RAW_HDR_CMD] & RAW_HDR_CMD_MASK)\n#define RAW_HDR_GET_USR(x) ((x)[RAW_HDR_CMD] & RAW_HDR_USR_MASK)\nextern const unsigned char raw_header[RAW_HDR_LEN];\n\n#include <stdarg.h>\n#ifdef WINDOWS32\n#include \"windows.h\"\n#else\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <err.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#endif\n\n#define DNS_PORT 53\n\n#ifndef MIN\n#define MIN(a,b) ((a)<(b)?(a):(b))\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a)>(b)?(a):(b))\n#endif\n\n#define QUERY_NAME_SIZE 256\n\n#if defined IP_MTU_DISCOVER\n  /* Linux */\n# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER\n# define DONT_FRAG_VALUE IP_PMTUDISC_DO\n#elif defined IP_DONTFRAG\n  /* FreeBSD */\n# define IP_OPT_DONT_FRAG IP_DONTFRAG\n# define DONT_FRAG_VALUE 1\n#elif defined IP_DONTFRAGMENT\n  /* Winsock2 */\n# define IP_OPT_DONT_FRAG IP_DONTFRAGMENT\n# define DONT_FRAG_VALUE 1\n#endif\n\n#define T_PRIVATE 65399\n/* Undefined RR type; \"private use\" range, see\n * http://www.bind9.net/dns-parameters */\n#define T_UNSET 65432\n/* Unused RR type, never actually sent */\n\nstruct packet\n{\n\tint len;\t\t/* Total packet length */\n\tint sentlen;\t\t/* Length of chunk currently transmitted */\n\tint offset;\t\t/* Current offset */\n\tchar data[64*1024];\t/* The data */\n\tchar seqno;\t\t/* The packet sequence number */\n\tchar fragment;\t\t/* Fragment index */\n};\n\nstruct query {\n\tchar name[QUERY_NAME_SIZE];\n\tunsigned short type;\n\tunsigned short rcode;\n\tunsigned short id;\n\tstruct sockaddr_storage destination;\n\tsocklen_t dest_len;\n\tstruct sockaddr_storage from;\n\tsocklen_t fromlen;\n\tunsigned short id2;\n\tstruct sockaddr_storage from2;\n\tsocklen_t fromlen2;\n};\n\nenum connection {\n\tCONN_RAW_UDP = 0,\n\tCONN_DNS_NULL,\n\tCONN_MAX\n};\n\n#ifdef WINDOWS32\nstatic inline void check_superuser(void)\n{\n}\n#else\nvoid check_superuser(void);\n#endif\nchar *format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len);\nint get_addr(char *, int, int, int, struct sockaddr_storage *);\nint open_dns(struct sockaddr_storage *, size_t);\nint open_dns_opt(struct sockaddr_storage *sockaddr, size_t sockaddr_len,\n\t\t int v6only);\nint open_dns_from_host(char *host, int port, int addr_family, int flags);\nvoid close_dns(int);\n\nvoid do_chroot(char *);\nvoid do_setcon(char *);\nvoid do_detach(void);\nvoid do_pidfile(char *);\n\nvoid read_password(char*, size_t);\n\nint check_topdomain(char *, int, char **);\n\nint query_datalen(const char *qname, const char *topdomain);\n\n#if defined(WINDOWS32) || defined(ANDROID)\n#ifndef ANDROID\nint inet_aton(const char *cp, struct in_addr *inp);\n#endif\n\nvoid vwarn(const char *fmt, va_list list);\nvoid warn(const char *fmt, ...);\nvoid err(int eval, const char *fmt, ...);\nvoid vwarnx(const char *fmt, va_list list);\nvoid warnx(const char *fmt, ...);\nvoid errx(int eval, const char *fmt, ...);\n#endif\n\nint recent_seqno(int , int);\n\n#ifndef WINDOWS32\nvoid fd_set_close_on_exec(int fd);\n#endif\n\n#endif\n"
  },
  {
    "path": "src/dns.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <time.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <strings.h>\n#include <ctype.h>\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#else\n#include <arpa/nameser.h>\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <err.h>\n#ifdef ANDROID\n#include \"android_dns.h\"\n#endif\n#endif\n\n\n#include \"dns.h\"\n#include \"encoding.h\"\n#include \"read.h\"\n\nint dnsc_use_edns0 = 1;\n\n#define CHECKLEN(x) if (buflen < (x) + (size_t)(p-buf))  return 0\n\nint dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr,\n\t       const char *data, size_t datalen)\n{\n\tHEADER *header;\n\tshort name;\n\tchar *p;\n\tint len;\n\tint ancnt;\n\n\tif (buflen < sizeof(HEADER))\n\t\treturn 0;\n\n\tmemset(buf, 0, buflen);\n\n\theader = (HEADER*)buf;\n\n\theader->id = htons(q->id);\n\theader->qr = (qr == QR_ANSWER);\n\theader->opcode = 0;\n\theader->aa = (qr == QR_ANSWER);\n\theader->tc = 0;\n\theader->rd = (qr == QR_QUERY);\n\theader->ra = 0;\n\n\tp = buf + sizeof(HEADER);\n\n\tswitch (qr) {\n\tcase QR_ANSWER:\n\t\theader->qdcount = htons(1);\n\n\t\tname = 0xc000 | ((p - buf) & 0x3fff);\n\n\t\t/* Question section */\n\t\tputname(&p, buflen - (p - buf), q->name);\n\n\t\tCHECKLEN(4);\n\t\tputshort(&p, q->type);\n\t\tputshort(&p, C_IN);\n\n\t\t/* Answer section */\n\n\t\tif (q->type == T_CNAME || q->type == T_A) {\n\t\t\t/* data is expected to be like\n\t\t\t * \"Hblabla.host.name.com\\0\" */\n\n\t\t\tchar *startp;\n\t\t\tint namelen;\n\n\t\t\tCHECKLEN(10);\n\t\t\tputshort(&p, name);\n\t\t\tif (q->type == T_A)\n\t\t\t\t/* answer CNAME to A question */\n\t\t\t\tputshort(&p, T_CNAME);\n\t\t\telse\n\t\t\t\tputshort(&p, q->type);\n\t\t\tputshort(&p, C_IN);\n\t\t\tputlong(&p, 0);\t\t/* TTL */\n\n\t\t\tstartp = p;\n\t\t\tp += 2;\t\t\t/* skip 2 bytes length */\n\t\t\tputname(&p, buflen - (p - buf), data);\n\t\t\tCHECKLEN(0);\n\t\t\tnamelen = p - startp;\n\t\t\tnamelen -= 2;\n\t\t\tputshort(&startp, namelen);\n\t\t\tancnt = 1;\n\t\t} else if (q->type == T_MX || q->type == T_SRV) {\n\t\t\t/* Data is expected to be like\n\t\t\t   \"Hblabla.host.name.com\\0Hanother.com\\0\\0\"\n\t\t\t   For SRV, see RFC2782.\n\t\t\t */\n\n\t\t\tconst char *mxdata = data;\n\t\t\tchar *startp;\n\t\t\tint namelen;\n\n\t\t\tancnt = 1;\n\t\t\twhile (1) {\n\t\t\t\tCHECKLEN(10);\n\t\t\t\tputshort(&p, name);\n\t\t\t\tputshort(&p, q->type);\n\t\t\t\tputshort(&p, C_IN);\n\t\t\t\tputlong(&p, 0);\t/* TTL */\n\n\t\t\t\tstartp = p;\n\t\t\t\tp += 2; /* skip 2 bytes length */\n\t\t\t\tCHECKLEN(2);\n\t\t\t\tputshort(&p, 10 * ancnt); /* preference */\n\n\t\t\t\tif (q->type == T_SRV) {\n\t\t\t\t\t/* weight, port (5060 = SIP) */\n\t\t\t\t\tCHECKLEN(4);\n\t\t\t\t\tputshort(&p, 10);\n\t\t\t\t\tputshort(&p, 5060);\n\t\t\t\t}\n\n\t\t\t\tputname(&p, buflen - (p - buf), mxdata);\n\t\t\t\tCHECKLEN(0);\n\t\t\t\tnamelen = p - startp;\n\t\t\t\tnamelen -= 2;\n\t\t\t\tputshort(&startp, namelen);\n\n\t\t\t\tmxdata = mxdata + strlen(mxdata) + 1;\n\t\t\t\tif (*mxdata == '\\0')\n\t\t\t\t\tbreak;\n\n\t\t\t\tancnt++;\n\t\t\t}\n\t\t} else if (q->type == T_TXT) {\n\t\t\t/* TXT has binary or base-X data */\n\t\t\tchar *startp;\n\t\t\tint txtlen;\n\n\t\t\tCHECKLEN(10);\n\t\t\tputshort(&p, name);\n\t\t\tputshort(&p, q->type);\n\t\t\tputshort(&p, C_IN);\n\t\t\tputlong(&p, 0); /* TTL */\n\n\t\t\tstartp = p;\n\t\t\tp += 2; /* skip 2 bytes length */\n\t\t\tputtxtbin(&p, buflen - (p - buf), data, datalen);\n\t\t\tCHECKLEN(0);\n\t\t\ttxtlen = p - startp;\n\t\t\ttxtlen -= 2;\n\t\t\tputshort(&startp, txtlen);\n\t\t\tancnt = 1;\n\t\t} else {\n\t\t\t/* NULL has raw binary data */\n\t\t\tCHECKLEN(10);\n\t\t\tputshort(&p, name);\n\t\t\tputshort(&p, q->type);\n\t\t\tputshort(&p, C_IN);\n\t\t\tputlong(&p, 0);\t/* TTL */\n\n\t\t\tdatalen = MIN(datalen, buflen - (p - buf));\n\t\t\tCHECKLEN(2);\n\t\t\tputshort(&p, datalen);\n\t\t\tCHECKLEN(datalen);\n\t\t\tputdata(&p, data, datalen);\n\t\t\tCHECKLEN(0);\n\t\t\tancnt = 1;\n\t\t}\n\t\theader->ancount = htons(ancnt);\n\t\tbreak;\n\tcase QR_QUERY:\n\t\t/* Note that iodined also uses this for forward queries */\n\n\t\theader->qdcount = htons(1);\n\n\t\tdatalen = MIN(datalen, buflen - (p - buf));\n\t\tputname(&p, datalen, data);\n\n\t\tCHECKLEN(4);\n\t\tputshort(&p, q->type);\n\t\tputshort(&p, C_IN);\n\n\t\t/* EDNS0 to advertise maximum response length\n\t\t   (even CNAME/A/MX, 255+255+header would be >512) */\n\t\tif (dnsc_use_edns0) {\n\t\t\theader->arcount = htons(1);\n\t\t\tCHECKLEN(11);\n\t\t\tputbyte(&p, 0x00);    /* Root */\n\t\t\tputshort(&p, 0x0029); /* OPT */\n\t\t\tputshort(&p, 0x1000); /* Payload size: 4096 */\n\t\t\tputshort(&p, 0x0000); /* Higher bits/edns version */\n\t\t\tputshort(&p, 0x8000); /* Z */\n\t\t\tputshort(&p, 0x0000); /* Data length */\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tlen = p - buf;\n\n\treturn len;\n}\n\n/* Only used when iodined gets an NS type query */\n/* Mostly same as dns_encode_a_response() below */\nint dns_encode_ns_response(char *buf, size_t buflen, struct query *q,\n\t\t\t   char *topdomain)\n{\n\tHEADER *header;\n\tint len;\n\tshort name;\n\tshort topname;\n\tshort nsname;\n\tchar *ipp;\n\tint domain_len;\n\tchar *p;\n\n\tif (buflen < sizeof(HEADER))\n\t\treturn 0;\n\n\tmemset(buf, 0, buflen);\n\n\theader = (HEADER*)buf;\n\n\theader->id = htons(q->id);\n\theader->qr = 1;\n\theader->opcode = 0;\n\theader->aa = 1;\n\theader->tc = 0;\n\theader->rd = 0;\n\theader->ra = 0;\n\n\tp = buf + sizeof(HEADER);\n\n\theader->qdcount = htons(1);\n\theader->ancount = htons(1);\n\n\t/* pointer to start of name */\n\tname = 0xc000 | ((p - buf) & 0x3fff);\n\n\tdomain_len = strlen(q->name) - strlen(topdomain);\n\tif (domain_len < 0 || domain_len == 1)\n\t\treturn -1;\n\tif (strcasecmp(q->name + domain_len, topdomain))\n\t\treturn -1;\n\tif (domain_len >= 1 && q->name[domain_len - 1] != '.')\n\t\treturn -1;\n\n\t/* pointer to start of topdomain; instead of dots at the end\n\t   we have length-bytes in front, so total length is the same */\n\ttopname = 0xc000 | ((p - buf + domain_len) & 0x3fff);\n\n\t/* Query section */\n\tputname(&p, buflen - (p - buf), q->name);\t/* Name */\n\tCHECKLEN(4);\n\tputshort(&p, q->type);\t\t\t/* Type */\n\tputshort(&p, C_IN);\t\t\t/* Class */\n\n\t/* Answer section */\n\tCHECKLEN(12);\n\tputshort(&p, name);\t\t\t/* Name */\n\tputshort(&p, q->type);\t\t\t/* Type */\n\tputshort(&p, C_IN);\t\t\t/* Class */\n\tputlong(&p, 3600);\t\t\t/* TTL */\n\tputshort(&p, 5);\t\t\t/* Data length */\n\n\t/* pointer to ns.topdomain */\n\tnsname = 0xc000 | ((p - buf) & 0x3fff);\n\tCHECKLEN(5);\n\tputbyte(&p, 2);\n\tputbyte(&p, 'n');\n\tputbyte(&p, 's');\n\tputshort(&p, topname);\t\t\t/* Name Server */\n\n\t/* Do we have an IPv4 address to send? */\n\tif (q->destination.ss_family == AF_INET) {\n\t\tstruct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;\n\n\t\t/* One additional record coming */\n\t\theader->arcount = htons(1);\n\n\t\t/* Additional data (A-record of NS server) */\n\t\tCHECKLEN(12);\n\t\tputshort(&p, nsname);\t\t/* Name Server */\n\t\tputshort(&p, T_A);\t\t/* Type */\n\t\tputshort(&p, C_IN);\t\t/* Class */\n\t\tputlong(&p, 3600);\t\t/* TTL */\n\t\tputshort(&p, 4);\t\t/* Data length */\n\n\t\t/* ugly hack to output IP address */\n\t\tipp = (char *) &dest->sin_addr.s_addr;\n\t\tCHECKLEN(4);\n\t\tputbyte(&p, *(ipp++));\n\t\tputbyte(&p, *(ipp++));\n\t\tputbyte(&p, *(ipp++));\n\t\tputbyte(&p, *ipp);\n\t}\n\n\tlen = p - buf;\n\treturn len;\n}\n\n/* Only used when iodined gets an A type query for ns.topdomain or\n * www.topdomain . Mostly same as dns_encode_ns_response() above */\nint dns_encode_a_response(char *buf, size_t buflen, struct query *q)\n{\n\tstruct sockaddr_in *dest = (struct sockaddr_in *) &q->destination;\n\tHEADER *header;\n\tint len;\n\tshort name;\n\tchar *ipp;\n\tchar *p;\n\n\t/* Check if we have an IPv4 address to send */\n\tif (q->destination.ss_family != AF_INET)\n\t\treturn -1;\n\n\tif (buflen < sizeof(HEADER))\n\t\treturn 0;\n\n\tmemset(buf, 0, buflen);\n\n\theader = (HEADER*)buf;\n\n\theader->id = htons(q->id);\n\theader->qr = 1;\n\theader->opcode = 0;\n\theader->aa = 1;\n\theader->tc = 0;\n\theader->rd = 0;\n\theader->ra = 0;\n\n\tp = buf + sizeof(HEADER);\n\n\theader->qdcount = htons(1);\n\theader->ancount = htons(1);\n\n\t/* pointer to start of name */\n\tname = 0xc000 | ((p - buf) & 0x3fff);\n\n\t/* Query section */\n\tputname(&p, buflen - (p - buf), q->name); /* Name */\n\tCHECKLEN(4);\n\tputshort(&p, q->type);\t/* Type */\n\tputshort(&p, C_IN);\t/* Class */\n\n\t/* Answer section */\n\tCHECKLEN(12);\n\tputshort(&p, name);\t/* Name */\n\tputshort(&p, q->type);\t/* Type */\n\tputshort(&p, C_IN);\t/* Class */\n\tputlong(&p, 3600);\t/* TTL */\n\tputshort(&p, 4);\t/* Data length */\n\n\t/* ugly hack to output IP address */\n\tipp = (char *) &dest->sin_addr.s_addr;\n\tCHECKLEN(4);\n\tputbyte(&p, *(ipp++));\n\tputbyte(&p, *(ipp++));\n\tputbyte(&p, *(ipp++));\n\tputbyte(&p, *ipp);\n\n\tlen = p - buf;\n\treturn len;\n}\n\nint dns_encode_nxdomain(char *buf, size_t buflen, struct query *q, const char *zone)\n{\n\tchar rnamebuf[256];\n\tchar nsbuf[256];\n\tHEADER *header;\n\tchar *soa_start;\n\tchar *p;\n\n\tif (buflen < sizeof(HEADER))\n\t\treturn 0;\n\n\tmemset(buf, 0, buflen);\n\theader = (HEADER*)buf;\n\n\theader->id = htons(q->id);\n\theader->qr = 1;\t\t// response\n\theader->opcode = 0;\n\theader->aa = 1;\t\t// authoritative\n\theader->tc = 0;\n\theader->rd = 0;\n\theader->ra = 0;\n\theader->rcode = 3;\t// NXDOMAIN\n\n\theader->qdcount = htons(1);\n\theader->ancount = htons(0);\n\theader->nscount = htons(1); // We'll include SOA\n\theader->arcount = htons(0);\n\n\tp = buf + sizeof(HEADER);\n\n\t// Question section\n\tputname(&p, buflen - (p - buf), q->name);\n\tCHECKLEN(4);\n\tputshort(&p, q->type);\n\tputshort(&p, C_IN);\n\n\t// Authority section (SOA)\n\tCHECKLEN(10);\n\tputname(&p, buflen - (p - buf), zone); // zone name (owner of SOA)\n\tputshort(&p, T_SOA);\n\tputshort(&p, C_IN);\n\tputlong(&p, 60); // TTL\n\n\tsoa_start = p;\n\tp += 2; // skip rdlength (to be filled later)\n\n\t// Primary NS and responsible mailbox\n\tsnprintf(nsbuf, sizeof(nsbuf), \"ns.%s\", zone);\n\tputname(&p, buflen - (p - buf), nsbuf);\n\tsnprintf(rnamebuf, sizeof(rnamebuf), \"hostmaster.%s\", zone);\n\tputname(&p, buflen - (p - buf), rnamebuf);\n\n\t// SOA fields: serial, refresh, retry, expire, minimum\n\tputlong(&p, 1);\t\t// serial\n\tputlong(&p, 3600);\t// refresh\n\tputlong(&p, 1800);\t// retry\n\tputlong(&p, 604800);\t// expire\n\tputlong(&p, 60);\t// minimum\n\n\tint soalen = p - soa_start - 2;\n\tputshort(&soa_start, soalen); // fill in rdlength\n\n\treturn p - buf;\n}\n\n#undef CHECKLEN\n\nunsigned short dns_get_id(char *packet, size_t packetlen)\n{\n\tHEADER *header;\n\theader = (HEADER*)packet;\n\n\tif (packetlen < sizeof(HEADER))\n\t\treturn 0;\n\n\treturn ntohs(header->id);\n}\n\n#define CHECKLEN(x) if (packetlen < (x) + (size_t)(data-packet))  return 0\n\nint dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet,\n\t       size_t packetlen)\n{\n\tchar name[QUERY_NAME_SIZE];\n\tchar rdata[4*1024];\n\tHEADER *header;\n\tshort qdcount;\n\tshort ancount;\n\tuint32_t ttl;\n\tunsigned short class;\n\tunsigned short type;\n\tchar *data;\n\tunsigned short rlen;\n\tint id;\n\tint rv;\n\n\tq->id2 = 0;\n\trv = 0;\n\theader = (HEADER*)packet;\n\n\t/* Reject short packets */\n\tif (packetlen < sizeof(HEADER))\n\t\treturn 0;\n\n\tif (header->qr != qr) {\n\t\twarnx(\"header->qr does not match the requested qr\");\n\t\treturn -1;\n\t}\n\n\tdata = packet + sizeof(HEADER);\n\tqdcount = ntohs(header->qdcount);\n\tancount = ntohs(header->ancount);\n\n\tid = ntohs(header->id);\n\tid = id & 0xFFFF; /* Kill any sign extension */\n\n\trlen = 0;\n\n\tif (q != NULL)\n\t\tq->rcode = header->rcode;\n\n\tswitch (qr) {\n\tcase QR_ANSWER:\n\t\tif (qdcount < 1) {\n\t\t\t/* We need a question */\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (q != NULL)\n\t\t\tq->id = id;\n\n\t\t/* Read name even if no answer, to give better error message */\n\t\treadname(packet, packetlen, &data, name, sizeof(name));\n\t\tCHECKLEN(4);\n\t\treadshort(packet, &data, &type);\n\t\treadshort(packet, &data, &class);\n\n\t\t/* if CHECKLEN okay, then we're sure to have a proper name */\n\t\tif (q != NULL) {\n\t\t\t/* We only need the first char to check it */\n\t\t\tq->name[0] = name[0];\n\t\t\tq->name[1] = '\\0';\n\t\t}\n\n\t\tif (ancount < 1) {\n\t\t\t/* DNS errors like NXDOMAIN have ancount=0 and\n\t\t\t   stop here. CNAME may also have A; MX/SRV may have\n\t\t\t   multiple results. */\n\t\t\treturn -1;\n\t\t}\n\n\t\t/* Here type is still the question type */\n\t\tif (type == T_NULL || type == T_PRIVATE) {\n\t\t\t/* Assume that first answer is what we wanted */\n\t\t\treadname(packet, packetlen, &data, name, sizeof(name));\n\t\t\tCHECKLEN(10);\n\t\t\treadshort(packet, &data, &type);\n\t\t\treadshort(packet, &data, &class);\n\t\t\treadlong(packet, &data, &ttl);\n\t\t\treadshort(packet, &data, &rlen);\n\n\t\t\trv = MIN(rlen, sizeof(rdata));\n\t\t\trv = readdata(packet, &data, rdata, rv);\n\t\t\tif (rv >= 2 && buf) {\n\t\t\t\trv = MIN(rv, buflen);\n\t\t\t\tmemcpy(buf, rdata, rv);\n\t\t\t} else {\n\t\t\t\trv = 0;\n\t\t\t}\n\t\t}\n\t\telse if ((type == T_A || type == T_CNAME) && buf) {\n\t\t\t/* Assume that first answer is what we wanted */\n\t\t\treadname(packet, packetlen, &data, name, sizeof(name));\n\t\t\tCHECKLEN(10);\n\t\t\treadshort(packet, &data, &type);\n\t\t\treadshort(packet, &data, &class);\n\t\t\treadlong(packet, &data, &ttl);\n\t\t\treadshort(packet, &data, &rlen);\n\n\t\t\tif (type == T_CNAME) {\n\t\t\t\t/* For tunnels, query type A has CNAME type answer */\n\t\t\t\tmemset(name, 0, sizeof(name));\n\t\t\t\treadname(packet, packetlen, &data, name, sizeof(name) - 1);\n\t\t\t\tname[sizeof(name)-1] = '\\0';\n\t\t\t\tstrncpy(buf, name, buflen);\n\t\t\t\tbuf[buflen - 1] = '\\0';\n\t\t\t\trv = strlen(buf);\n\t\t\t}\n\t\t\tif (type == T_A) {\n\t\t\t\t/* Answer type A includes only 4 bytes.\n\t\t\t\t   Not used for tunneling. */\n\t\t\t\trv = MIN(rlen, sizeof(rdata));\n\t\t\t\trv = readdata(packet, &data, rdata, rv);\n\t\t\t\tif (rv >= 2 && buf) {\n\t\t\t\t\trv = MIN(rv, buflen);\n\t\t\t\t\tmemcpy(buf, rdata, rv);\n\t\t\t\t} else {\n\t\t\t\t\trv = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((type == T_MX || type == T_SRV) && buf) {\n\t\t\t/* We support 250 records, 250*(255+header) ~= 64kB.\n\t\t\t   Only exact 10-multiples are accepted, and gaps in\n\t\t\t   numbering are not jumped over (->truncated).\n\t\t\t   Hopefully DNS servers won't mess around too much.\n\t\t\t */\n\t\t\tchar names[250][QUERY_NAME_SIZE];\n\t\t\tchar *rdatastart;\n\t\t\tunsigned short pref;\n\t\t\tint i;\n\t\t\tint offset;\n\n\t\t\tmemset(names, 0, sizeof(names));\n\n\t\t\tfor (i = 0; i < ancount; i++) {\n\t\t\t\treadname(packet, packetlen, &data, name, sizeof(name));\n\t\t\t\tCHECKLEN(12);\n\t\t\t\treadshort(packet, &data, &type);\n\t\t\t\treadshort(packet, &data, &class);\n\t\t\t\treadlong(packet, &data, &ttl);\n\t\t\t\treadshort(packet, &data, &rlen);\n\t\t\t\trdatastart = data;\n\t\t\t\treadshort(packet, &data, &pref);\n\n\t\t\t\tif (type == T_SRV) {\n\t\t\t\t\t/* skip weight, port */\n\t\t\t\t\tdata += 4;\n\t\t\t\t\tCHECKLEN(0);\n\t\t\t\t}\n\n\t\t\t\tif (pref % 10 == 0 && pref >= 10 &&\n\t\t\t\t    pref < 2500) {\n\t\t\t\t\treadname(packet, packetlen, &data,\n\t\t\t\t\t\t names[pref / 10 - 1],\n\t\t\t\t\t\t QUERY_NAME_SIZE - 1);\n\t\t\t\t\tnames[pref / 10 - 1]\n\t\t\t\t\t\t[QUERY_NAME_SIZE-1] = '\\0';\n\t\t\t\t}\n\n\t\t\t\t/* always trust rlen, not name encoding */\n\t\t\t\tdata = rdatastart + rlen;\n\t\t\t\tCHECKLEN(0);\n\t\t\t}\n\n\t\t\t/* output is like Hname10.com\\0Hname20.com\\0\\0 */\n\t\t\toffset = 0;\n\t\t\ti = 0;\n\t\t\twhile (names[i][0] != '\\0') {\n\t\t\t\tint l = MIN(strlen(names[i]), buflen-offset-2);\n\t\t\t\tif (l <= 0)\n\t\t\t\t\tbreak;\n\t\t\t\tmemcpy(buf + offset, names[i], l);\n\t\t\t\toffset += l;\n\t\t\t\t*(buf + offset) = '\\0';\n\t\t\t\toffset++;\n\t\t\t\ti++;\n\t\t\t}\n\t\t\t*(buf + offset) = '\\0';\n\t\t\trv = offset;\n\t\t}\n\t\telse if (type == T_TXT && buf) {\n\t\t\t/* Assume that first answer is what we wanted */\n\t\t\treadname(packet, packetlen, &data, name, sizeof(name));\n\t\t\tCHECKLEN(10);\n\t\t\treadshort(packet, &data, &type);\n\t\t\treadshort(packet, &data, &class);\n\t\t\treadlong(packet, &data, &ttl);\n\t\t\treadshort(packet, &data, &rlen);\n\n\t\t\trv = readtxtbin(packet, &data, rlen, rdata,\n\t\t\t\t        sizeof(rdata));\n\t\t\tif (rv >= 1) {\n\t\t\t\trv = MIN(rv, buflen);\n\t\t\t\tmemcpy(buf, rdata, rv);\n\t\t\t} else {\n\t\t\t\trv = 0;\n\t\t\t}\n\t\t}\n\n\t\t/* Here type is the answer type (note A->CNAME) */\n\t\tif (q != NULL)\n\t\t\tq->type = type;\n\t\tbreak;\n\tcase QR_QUERY:\n\t\tif (qdcount < 1) {\n\t\t\twarnx(\"no question section in name query\");\n\t\t\treturn -1;\n\t\t}\n\n\t\tmemset(name, 0, sizeof(name));\n\t\treadname(packet, packetlen, &data, name, sizeof(name) - 1);\n\t\tname[sizeof(name)-1] = '\\0';\n\t\tCHECKLEN(4);\n\t\treadshort(packet, &data, &type);\n\t\treadshort(packet, &data, &class);\n\n\t\tif (q == NULL) {\n\t\t\trv = 0;\n\t\t\tbreak;\n\t\t}\n\n\t\tstrncpy(q->name, name, sizeof(q->name));\n\t\tq->name[sizeof(q->name) - 1] = '\\0';\n\t\tq->type = type;\n\t\tq->id = id;\n\n\t\trv = strlen(q->name);\n\t\tbreak;\n\t}\n\n\treturn rv;\n}\n\n"
  },
  {
    "path": "src/dns.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __DNS_H__\n#define __DNS_H__\n\n#include \"common.h\"\n\ntypedef enum {\n\tQR_QUERY = 0,\n\tQR_ANSWER = 1\n} qr_t;\n\nextern int dnsc_use_edns0;\n\nint dns_encode(char *, size_t, struct query *, qr_t, const char *, size_t);\nint dns_encode_ns_response(char *buf, size_t buflen, struct query *q,\n\t\t\t   char *topdomain);\nint dns_encode_a_response(char *buf, size_t buflen, struct query *q);\nint dns_encode_nxdomain(char *buf, size_t buflen, struct query *q, const char *zone);\nunsigned short dns_get_id(char *packet, size_t packetlen);\nint dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);\n\n#endif /* _DNS_H_ */\n"
  },
  {
    "path": "src/encoding.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <string.h>\n#include \"common.h\"\n#include \"encoding.h\"\n\nint build_hostname(char *buf, size_t buflen, const char *data,\n\t\t   const size_t datalen, const char *topdomain,\n\t\t   const struct encoder *encoder, int maxlen)\n{\n\tsize_t space;\n\tchar *b;\n\n\tspace = MIN((size_t)maxlen, buflen) - strlen(topdomain) - 8;\n\t/* 8 = 5 max header length + 1 dot before topdomain + 2 safety */\n\n\tif (!encoder->places_dots)\n\t\tspace -= (space / 57); /* space for dots */\n\n\tmemset(buf, 0, buflen);\n\n\tencoder->encode(buf, &space, data, datalen);\n\n\tif (!encoder->places_dots)\n\t\tinline_dotify(buf, buflen);\n\n\tb = buf;\n\tb += strlen(buf);\n\n\t/* move b back one step to see if the dot is there */\n\tb--;\n\tif (*b != '.')\n\t\t*++b = '.';\n\tb++;\n\t/* move b ahead of the string so we can copy to it */\n\n\tstrncpy(b, topdomain, strlen(topdomain)+1);\n\n\treturn space;\n}\n\nint unpack_data(char *buf, size_t buflen, char *data, size_t datalen,\n\t\tconst struct encoder *enc)\n{\n\tif (!enc->eats_dots)\n\t\tdatalen = inline_undotify(data, datalen);\n\treturn enc->decode(buf, &buflen, data, datalen);\n}\n\nint inline_dotify(char *buf, size_t buflen)\n{\n\tunsigned dots;\n\tunsigned pos;\n\tunsigned total;\n\tchar *reader, *writer;\n\n\ttotal = strlen(buf);\n\tdots = total / 57;\n\n\twriter = buf;\n\twriter += total;\n\twriter += dots;\n\n\ttotal += dots;\n\tif (strlen(buf) + dots > buflen) {\n\t\twriter = buf;\n\t\twriter += buflen;\n\t\ttotal = buflen;\n\t}\n\n\treader = writer - dots;\n\tpos = (unsigned) (reader - buf) + 1;\n\n\twhile (dots) {\n\t\t*writer-- = *reader--;\n\t\tpos--;\n\t\tif (pos % 57 == 0) {\n\t\t\t*writer-- = '.';\n\t\t\tdots--;\n\t\t}\n\t}\n\n\t/* return new length of string */\n\treturn total;\n}\n\nint inline_undotify(char *buf, size_t len)\n{\n\tunsigned pos;\n\tunsigned dots;\n\tchar *reader, *writer;\n\n\twriter = buf;\n\treader = writer;\n\n\tpos = 0;\n\tdots = 0;\n\n\twhile (pos < len) {\n\t\tif (*reader == '.') {\n\t\t\treader++;\n\t\t\tpos++;\n\t\t\tdots++;\n\t\t\tcontinue;\n\t\t}\n\t\t*writer++ = *reader++;\n\t\tpos++;\n\t}\n\n\t/* return new length of string */\n\treturn len - dots;\n}\n"
  },
  {
    "path": "src/encoding.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman\n * 2006-2009 Bjorn Andersson\n * Copyright (c) 2017 Ralf Ramsauer\n *\n * Authors:\n *   Bjorn Andersson <flex@kryo.se>\n *   Erok Ekman <yarrick@kryo.se>,\n *   Ralf Ramsauer <ralf@ramses-pyramidenbau.de>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef _ENCODING_H_\n#define _ENCODING_H_\n\n#include <stdbool.h>\n\n/* All-0, all-1, 01010101, 10101010: each 4 times to make sure the pattern\n   spreads across multiple encoded chars -> 16 bytes total.\n   Followed by 32 bytes from my /dev/random; should be enough.\n */\n#define DOWNCODECCHECK1 \\\n\t\"\\000\\000\\000\\000\\377\\377\\377\\377\\125\\125\\125\\125\\252\\252\\252\\252\" \\\n\t\"\\201\\143\\310\\322\\307\\174\\262\\027\\137\\117\\316\\311\\111\\055\\122\\041\" \\\n\t\"\\141\\251\\161\\040\\045\\263\\006\\163\\346\\330\\104\\060\\171\\120\\127\\277\"\n#define DOWNCODECCHECK1_LEN  48\n\nstruct encoder {\n\tconst char name[8];\n\tint (*encode)(char *dst, size_t *dstlen, const void *src, size_t srclen);\n\tint (*decode)(void *dst, size_t *dstlen, const char *src, size_t srclen);\n\n\tconst bool places_dots;\n\tconst bool eats_dots;\n\n\tconst int blocksize_raw;\n\tconst int blocksize_encoded;\n};\n\nint build_hostname(char *, size_t, const char *, const size_t, const char *,\n\t\t   const struct encoder *, int);\nint unpack_data(char *, size_t, char *, size_t, const struct encoder *);\nint inline_dotify(char *, size_t);\nint inline_undotify(char *, size_t);\n\nextern const struct encoder base32_ops;\nextern const struct encoder base64_ops;\nextern const struct encoder base64u_ops;\nextern const struct encoder base128_ops;\n\nint b32_5to8(int);\nint b32_8to5(int);\n\n#endif\n"
  },
  {
    "path": "src/fw_query.c",
    "content": "/*\n * Copyright (c) 2008-2014 Erik Ekman <yarrick@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <string.h>\n#include \"fw_query.h\"\n\nstatic struct fw_query fwq[FW_QUERY_CACHE_SIZE];\nstatic int fwq_ix;\n\nvoid fw_query_init(void)\n{\n\tmemset(fwq, 0, sizeof(struct fw_query) * FW_QUERY_CACHE_SIZE);\n\tfwq_ix = 0;\n}\n\nvoid fw_query_put(struct fw_query *fw_query)\n{\n\tmemcpy(&(fwq[fwq_ix]), fw_query, sizeof(struct fw_query));\n\n\t++fwq_ix;\n\tif (fwq_ix >= FW_QUERY_CACHE_SIZE)\n\t\tfwq_ix = 0;\n}\n\nvoid fw_query_get(unsigned short query_id, struct fw_query **fw_query)\n{\n\tint i;\n\n\t*fw_query = NULL;\n\tfor (i = 0; i < FW_QUERY_CACHE_SIZE; i++) {\n\t\tif (fwq[i].id == query_id) {\n\t\t\t*fw_query = &(fwq[i]);\n\t\t\treturn;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/fw_query.h",
    "content": "/*\n * Copyright (c) 2008-2014 Erik Ekman <yarrick@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __FW_QUERY_H__\n#define __FW_QUERY_H__\n\n#include <sys/types.h>\n#ifdef WINDOWS32\n#include \"windows.h\"\n#include <winsock2.h>\n#else\n#include <sys/socket.h>\n#endif\n\n#define FW_QUERY_CACHE_SIZE 16\n\nstruct fw_query {\n\tstruct sockaddr_storage addr;\n\tint addrlen;\n\tunsigned short id;\n};\n\nvoid fw_query_init(void);\nvoid fw_query_put(struct fw_query *fw_query);\nvoid fw_query_get(unsigned short query_id, struct fw_query **fw_query);\n\n#endif /*__FW_QUERY_H__*/\n\n"
  },
  {
    "path": "src/iodine.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/param.h>\n#include <sys/time.h>\n#include <fcntl.h>\n#include <time.h>\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#include <winsock2.h>\n#else\n#include <grp.h>\n#include <pwd.h>\n#include <netdb.h>\n#endif\n\n#include \"common.h\"\n#include \"tun.h\"\n#include \"client.h\"\n#include \"util.h\"\n\n#ifdef WINDOWS32\nWORD req_version = MAKEWORD(2, 2);\nWSADATA wsa_data;\n#endif\n\n#if !defined(BSD) && !defined(__GLIBC__)\nstatic char *__progname;\n#else\nextern char *__progname;\n#endif\n\n#define PASSWORD_ENV_VAR \"IODINE_PASS\"\n\nstatic void\nsighandler(int sig)\n{\n\tclient_stop();\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n/* mark as no return to help some compilers to avoid warnings\n * about use of uninitialized variables */\nstatic inline void usage(void) __attribute__((noreturn));\nstatic inline void help(FILE * stream, bool verbose) __attribute__((noreturn));\n#endif\n\nstatic void help(FILE *stream, bool verbose)\n{\n\tfprintf(stream,\n\t\t\"iodine IP over DNS tunneling client\\n\\n\"\n\t\t\"Usage: %s [-46fhrv] [-u user] [-t chrootdir] [-d device] [-P password]\\n\"\n\t\t\"              [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec]\\n\"\n\t\t\"              [-z context] [-F pidfile] [nameserver] topdomain\\n\", __progname);\n\n\tif (!verbose)\n\t\texit(2);\n\n\tfprintf(stream,\n\t\t\"\\nOptions to try if connection doesn't work:\\n\"\n\t\t\"  -4 to connect only to IPv4\\n\"\n\t\t\"  -6 to connect only to IPv6\\n\"\n\t\t\"  -T force dns type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\\n\"\n\t\t\"  -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\\n\"\n\t\t\"     Base128, or (only for TXT:) Raw  (default: autodetect)\\n\"\n\t\t\"  -I max interval between requests (default 4 sec) to prevent DNS timeouts\\n\"\n\t\t\"  -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\\n\"\n\t\t\"  -m max size of downstream fragments (default: autodetect)\\n\"\n\t\t\"  -M max size of upstream hostnames (~100-255, default: 255)\\n\"\n\t\t\"  -r to skip raw UDP mode attempt\\n\"\n\t\t\"  -P password used for authentication (max 32 chars will be used)\\n\\n\"\n\t\t\"Other options:\\n\"\n\t\t\"  -v to print version info and exit\\n\"\n\t\t\"  -h to print this help and exit\\n\"\n\t\t\"  -f to keep running in foreground\\n\"\n\t\t\"  -u name to drop privileges and run as user 'name'\\n\"\n\t\t\"  -t dir to chroot to directory dir\\n\"\n\t\t\"  -d device to set tunnel device name\\n\"\n\t\t\"  -z context, to apply specified SELinux context after initialization\\n\"\n\t\t\"  -F pidfile to write pid to a file\\n\\n\"\n\t\t\"nameserver is the IP number/hostname of the relaying nameserver. If absent,\\n\"\n\t\t\"           /etc/resolv.conf is used\\n\"\n\t\t\"topdomain is the FQDN that is delegated to the tunnel endpoint.\\n\");\n\n\texit(0);\n}\n\nstatic inline void usage(void)\n{\n\thelp(stderr, false);\n}\n\nstatic void version(void)\n{\n\tfprintf(stderr, \"iodine IP over DNS tunneling client\\n\"\n\t\t\t\"Git version: %s\\n\", GITREVISION);\n\n\texit(0);\n}\n\nint main(int argc, char **argv)\n{\n\tchar *nameserv_host;\n\tchar *topdomain;\n\tchar *errormsg;\n#ifndef WINDOWS32\n\tstruct passwd *pw;\n#endif\n\tchar *username;\n\tchar password[33];\n\tint foreground;\n\tchar *newroot;\n\tchar *context;\n\tchar *device;\n\tchar *pidfile;\n\tint choice;\n\tint tun_fd;\n\tint dns_fd;\n\tint max_downstream_frag_size;\n\tint autodetect_frag_size;\n\tint retval;\n\tint raw_mode;\n\tint lazymode;\n\tint selecttimeout;\n\tint hostname_maxlen;\n#ifdef OPENBSD\n\tint rtable = 0;\n#endif\n\tstruct sockaddr_storage nameservaddr;\n\tint nameservaddr_len;\n\tint nameserv_family;\n\n\tnameserv_host = NULL;\n\ttopdomain = NULL;\n\terrormsg = NULL;\n#ifndef WINDOWS32\n\tpw = NULL;\n#endif\n\tusername = NULL;\n\tmemset(password, 0, 33);\n\tsrand(time(NULL));\n\tforeground = 0;\n\tnewroot = NULL;\n\tcontext = NULL;\n\tdevice = NULL;\n\tpidfile = NULL;\n\n\tautodetect_frag_size = 1;\n\tmax_downstream_frag_size = 3072;\n\tretval = 0;\n\traw_mode = 1;\n\tlazymode = 1;\n\tselecttimeout = 4;\n\thostname_maxlen = 0xFF;\n\tnameserv_family = AF_UNSPEC;\n\n#ifdef WINDOWS32\n\tWSAStartup(req_version, &wsa_data);\n#endif\n\n\tsrand((unsigned) time(NULL));\n\tclient_init();\n\n#if !defined(BSD) && !defined(__GLIBC__)\n\t__progname = strrchr(argv[0], '/');\n\tif (__progname == NULL)\n\t\t__progname = argv[0];\n\telse\n\t\t__progname++;\n#endif\n\n\twhile ((choice = getopt(argc, argv, \"46vfhru:t:d:R:P:m:M:F:T:O:L:I:\")) != -1) {\n\t\tswitch(choice) {\n\t\tcase '4':\n\t\t\tnameserv_family = AF_INET;\n\t\t\tbreak;\n\t\tcase '6':\n\t\t\tnameserv_family = AF_INET6;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tversion();\n\t\t\t/* NOTREACHED */\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\t\thelp(stdout, true);\n\t\t\t/* NOTREACHED */\n\t\t\tbreak;\n\t\tcase 'r':\n\t\t\traw_mode = 0;\n\t\t\tbreak;\n\t\tcase 'u':\n\t\t\tusername = optarg;\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\tnewroot = optarg;\n\t\t\tbreak;\n\t\tcase 'd':\n\t\t\tdevice = optarg;\n\t\t\tbreak;\n#ifdef OPENBSD\n\t\tcase 'R':\n\t\t\trtable = atoi(optarg);\n\t\t\tbreak;\n#endif\n\t\tcase 'P':\n\t\t\tstrncpy(password, optarg, sizeof(password));\n\t\t\tpassword[sizeof(password)-1] = 0;\n\n\t\t\t/* XXX: find better way of cleaning up ps(1) */\n\t\t\tmemset(optarg, 0, strlen(optarg));\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tautodetect_frag_size = 0;\n\t\t\tmax_downstream_frag_size = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'M':\n\t\t\thostname_maxlen = atoi(optarg);\n\t\t\tif (hostname_maxlen > 255)\n\t\t\t\thostname_maxlen = 255;\n\t\t\tif (hostname_maxlen < 10)\n\t\t\t\thostname_maxlen = 10;\n\t\t\tbreak;\n\t\tcase 'z':\n\t\t\tcontext = optarg;\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tpidfile = optarg;\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tif (client_set_qtype(optarg))\n\t\t\t\terrx(5, \"Invalid query type '%s'\", optarg);\n\t\t\tbreak;\n\t\tcase 'O':       /* not -D, is Debug in server */\n\t\t\tclient_set_downenc(optarg);\n\t\t\tbreak;\n\t\tcase 'L':\n\t\t\tlazymode = atoi(optarg);\n\t\t\tif (lazymode > 1)\n\t\t\t\tlazymode = 1;\n\t\t\tif (lazymode < 0)\n\t\t\t\tlazymode = 0;\n\t\t\tif (!lazymode)\n\t\t\t\tselecttimeout = 1;\n\t\t\tbreak;\n\t\tcase 'I':\n\t\t\tselecttimeout = atoi(optarg);\n\t\t\tif (selecttimeout < 1)\n\t\t\t\tselecttimeout = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\t/* NOTREACHED */\n\t\t}\n\t}\n\n\tcheck_superuser();\n\n\targc -= optind;\n\targv += optind;\n\n\tswitch (argc) {\n\tcase 1:\n\t\tnameserv_host = get_resolvconf_addr();\n\t\ttopdomain = strdup(argv[0]);\n\t\tbreak;\n\tcase 2:\n\t\tnameserv_host = argv[0];\n\t\ttopdomain = strdup(argv[1]);\n\t\tbreak;\n\tdefault:\n\t\tusage();\n\t\t/* NOTREACHED */\n\t}\n\n\tif (max_downstream_frag_size < 1 || max_downstream_frag_size > 0xffff) {\n\t\twarnx(\"Use a max frag size between 1 and 65535 bytes.\\n\");\n\t\tusage();\n\t\t/* NOTREACHED */\n\t}\n\n\tif (nameserv_host) {\n\t\tnameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr);\n\t\tif (nameservaddr_len < 0) {\n\t\t\terrx(1, \"Cannot lookup nameserver '%s': %s \",\n\t\t\t\tnameserv_host, gai_strerror(nameservaddr_len));\n\t\t}\n\t\tclient_set_nameserver(&nameservaddr, nameservaddr_len);\n\t} else {\n\t\twarnx(\"No nameserver found - not connected to any network?\\n\");\n\t\tusage();\n\t\t/* NOTREACHED */\n\t}\n\n\tif (check_topdomain(topdomain, 0, &errormsg)) {\n\t\twarnx(\"Invalid topdomain: %s\", errormsg);\n\t\tusage();\n\t\t/* NOTREACHED */\n\t}\n\n\tclient_set_selecttimeout(selecttimeout);\n\tclient_set_lazymode(lazymode);\n\tclient_set_topdomain(topdomain);\n\tclient_set_hostname_maxlen(hostname_maxlen);\n\n\tif (username != NULL) {\n#ifndef WINDOWS32\n\t\tif ((pw = getpwnam(username)) == NULL) {\n\t\t\twarnx(\"User %s does not exist!\\n\", username);\n\t\t\tusage();\n\t\t\t/* NOTREACHED */\n\t\t}\n#endif\n\t}\n\n\tif (strlen(password) == 0) {\n\t\tif (NULL != getenv(PASSWORD_ENV_VAR))\n\t\t\tsnprintf(password, sizeof(password), \"%s\", getenv(PASSWORD_ENV_VAR));\n\t\telse\n\t\t\tread_password(password, sizeof(password));\n\t}\n\n\tclient_set_password(password);\n\n\tif ((tun_fd = open_tun(device)) == -1) {\n\t\tretval = 1;\n\t\tgoto cleanup1;\n\t}\n\tif ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {\n\t\tretval = 1;\n\t\tgoto cleanup2;\n\t}\n#ifdef OPENBSD\n\tif (rtable > 0)\n\t\tsocket_setrtable(dns_fd, rtable);\n#endif\n\n\tsignal(SIGINT, sighandler);\n\tsignal(SIGTERM, sighandler);\n\n\tfprintf(stderr, \"Sending DNS queries for %s to %s\\n\",\n\t\ttopdomain, format_addr(&nameservaddr, nameservaddr_len));\n\n\tif (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {\n\t\tretval = 1;\n\t\tgoto cleanup2;\n\t}\n\n\tif (client_get_conn() == CONN_RAW_UDP) {\n\t\tfprintf(stderr, \"Sending raw traffic directly to %s\\n\", client_get_raw_addr());\n\t}\n\n\tfprintf(stderr, \"Connection setup complete, transmitting data.\\n\");\n\n\tif (foreground == 0)\n\t\tdo_detach();\n\n\tif (pidfile != NULL)\n\t\tdo_pidfile(pidfile);\n\n\tif (newroot != NULL)\n\t\tdo_chroot(newroot);\n\n\tif (username != NULL) {\n#ifndef WINDOWS32\n\t\tgid_t gids[1];\n\t\tgids[0] = pw->pw_gid;\n\t\tif (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {\n\t\t\twarnx(\"Could not switch to user %s!\\n\", username);\n\t\t\tusage();\n\t\t\t/* NOTREACHED */\n\t\t}\n#endif\n\t}\n\n\tif (context != NULL)\n\t\tdo_setcon(context);\n\n\tclient_tunnel(tun_fd, dns_fd);\n\ncleanup2:\n\tclose_dns(dns_fd);\n\tclose_tun(tun_fd);\ncleanup1:\n\n\treturn retval;\n}\n\n"
  },
  {
    "path": "src/iodined.c",
    "content": "/*\n * Copyright (c) 2006-2015 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <signal.h>\n#include <unistd.h>\n#include <sys/param.h>\n#include <sys/time.h>\n#include <fcntl.h>\n#include <time.h>\n#include <zlib.h>\n\n#include \"common.h\"\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#include <winsock2.h>\n#else\n#include <arpa/nameser.h>\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n#define _XPG4_2\n#include <netinet/in_systm.h>\n#include <netinet/ip.h>\n#include <grp.h>\n#include <sys/uio.h>\n#include <pwd.h>\n#include <netdb.h>\n#include <syslog.h>\n#endif\n\n#include \"dns.h\"\n#include \"encoding.h\"\n#include \"user.h\"\n#include \"login.h\"\n#include \"tun.h\"\n#include \"fw_query.h\"\n#include \"version.h\"\n\n#ifdef HAVE_SYSTEMD\n# include <systemd/sd-daemon.h>\n#endif\n\n#ifdef WINDOWS32\nWORD req_version = MAKEWORD(2, 2);\nWSADATA wsa_data;\n#endif\n\n#define PASSWORD_ENV_VAR \"IODINED_PASS\"\n\n#if defined IP_RECVDSTADDR\n# define DSTADDR_SOCKOPT IP_RECVDSTADDR\n# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x))\n#elif defined IP_PKTINFO\n# define DSTADDR_SOCKOPT IP_PKTINFO\n# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))\n#endif\n\n#ifndef IPV6_RECVPKTINFO\n#define IPV6_RECVPKTINFO IPV6_PKTINFO\n#endif\n\nstatic int running = 1;\nstatic char *topdomain;\nstatic char password[33];\nstatic int created_users;\n\nstatic int check_ip;\nstatic int my_mtu;\nstatic in_addr_t my_ip;\nstatic int netmask;\n\nstatic in_addr_t ns_ip;\n\nstatic int bind_port;\nstatic int debug;\n\n#if !defined(BSD) && !defined(__GLIBC__)\nstatic char *__progname;\n#else\nextern char *__progname;\n#endif\n\n/* Struct with IPv4 and IPv6 file descriptors.\n * Need to be passed on down to tunneling code since we can get a\n * packet on one fd meant for a user on the other.\n */\nstruct dnsfd {\n\tint v4fd;\n\tint v6fd;\n};\n\nstatic int read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q);\nstatic void write_dns(int fd, struct query *q, const char *data, int datalen, char downenc);\nstatic void handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid);\n\nstatic int\nget_dns_fd(struct dnsfd *fds, struct sockaddr_storage *addr)\n{\n\tif (addr->ss_family == AF_INET6) {\n\t\treturn fds->v6fd;\n\t}\n\treturn fds->v4fd;\n}\n\n/* Ask opendns.com DNS service for external ip */\nstatic int\nget_external_ip(struct in_addr *ip)\n{\n\tstatic const char target[] = \"myip.opendns.com\";\n\tstruct query query;\n\tint attempt;\n\tint res;\n\tint fd;\n\tint out_len = 0;\n\tmemset(&query, 0, sizeof(query));\n\n\tquery.type = T_A;\n\tres = get_addr(\"resolver1.opendns.com\", 53, AF_INET, 0, &query.destination);\n\tif (res < 0) return 1;\n\tquery.dest_len = res;\n\n\tfd = open_dns_from_host(NULL, 0, AF_INET, AI_PASSIVE);\n\tif (fd < 0) return 2;\n\n\tfor (attempt = 0; attempt < 3; attempt++) {\n\t\tchar buf[64*1024];\n\t\tint buflen;\n\t\tfd_set fds;\n\t\tstruct timeval tv;\n\n\t\tif (attempt) fprintf(stderr, \"Retrying external IP lookup\\n\");\n\t\tquery.id = rand();\n\t\tbuflen = sizeof(buf);\n\t\tbuflen = dns_encode(buf, buflen, &query, QR_QUERY, target, strlen(target));\n\t\tif (buflen < 0) continue;\n\n\t\tsendto(fd, buf, buflen, 0, (struct sockaddr*)&query.destination, query.dest_len);\n\n\t\ttv.tv_sec = 1 + attempt;\n\t\ttv.tv_usec = 0;\n\t\tFD_ZERO(&fds);\n\t\tFD_SET(fd, &fds);\n\t\tres = select(fd + 1, &fds, NULL, NULL, &tv);\n\t\tif (res > 0) {\n\t\t\tbuflen = sizeof(buf);\n\t\t\tbuflen = recv(fd, buf, buflen, 0);\n\t\t\tif (buflen > 0) {\n\t\t\t\tout_len = dns_decode((char *)ip, sizeof(struct in_addr), &query, QR_ANSWER, buf, buflen);\n\t\t\t\tif (out_len > 0) break;\n\t\t\t}\n\t\t}\n\t}\n\n\tclose_dns(fd);\n\treturn (out_len != sizeof(struct in_addr));\n}\n\nstatic void\nsigint(int sig)\n{\n\trunning = 0;\n}\n\n/* This will not check that user has passed login challenge */\nstatic int check_user_and_ip(int userid, struct query *q)\n{\n\t/* Note: duplicate in handle_raw_login() except IP-address check */\n\n\tif (userid < 0 || userid >= created_users) {\n\t\treturn 1;\n\t}\n\tif (!users[userid].active || users[userid].disabled) {\n\t\treturn 1;\n\t}\n\tif (users[userid].last_pkt + 60 < time(NULL)) {\n\t\treturn 1;\n\t}\n\n\t/* return early if IP checking is disabled */\n\tif (!check_ip) {\n\t\treturn 0;\n\t}\n\n\tif (q->from.ss_family != users[userid].host.ss_family) {\n\t\treturn 1;\n\t}\n\t/* Check IPv4 */\n\tif (q->from.ss_family == AF_INET) {\n\t\tstruct sockaddr_in *expected, *received;\n\n\t\texpected = (struct sockaddr_in *) &(users[userid].host);\n\t\treceived = (struct sockaddr_in *) &(q->from);\n\t\treturn memcmp(&(expected->sin_addr), &(received->sin_addr), sizeof(struct in_addr));\n\t}\n\t/* Check IPv6 */\n\tif (q->from.ss_family == AF_INET6) {\n\t\tstruct sockaddr_in6 *expected, *received;\n\n\t\texpected = (struct sockaddr_in6 *) &(users[userid].host);\n\t\treceived = (struct sockaddr_in6 *) &(q->from);\n\t\treturn memcmp(&(expected->sin6_addr), &(received->sin6_addr), sizeof(struct in6_addr));\n\t}\n\t/* Unknown address family */\n\treturn 1;\n}\n\n/* This checks that user has passed normal (non-raw) login challenge */\nstatic int check_authenticated_user_and_ip(int userid, struct query *q)\n{\n\tint res = check_user_and_ip(userid, q);\n\tif (res)\n\t\treturn res;\n\n\tif (!users[userid].authenticated)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic int check_authenticated_user_and_ip_and_options(int userid, struct query *q)\n{\n\tint res = check_authenticated_user_and_ip(userid, q);\n\tif (res || check_ip)\n\t\treturn res;\n\n\tif (users[userid].options_locked)\n\t\treturn 1;\n\n\treturn 0;\n}\n\nstatic void send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)\n{\n\tchar packet[4096];\n\tint len;\n\n\tlen = MIN(sizeof(packet) - RAW_HDR_LEN, buflen);\n\n\tmemcpy(packet, raw_header, RAW_HDR_LEN);\n\tif (len) {\n\t\tmemcpy(&packet[RAW_HDR_LEN], buf, len);\n\t}\n\n\tlen += RAW_HDR_LEN;\n\tpacket[RAW_HDR_CMD] = cmd | (user & 0x0F);\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX-raw: client %s, cmd %d, %d bytes\\n\",\n\t\t\tformat_addr(&q->from, q->fromlen), cmd, len);\n\t}\n\n\tsendto(fd, packet, len, 0, (struct sockaddr *) &q->from, q->fromlen);\n}\n\n\nstatic void start_new_outpacket(int userid, char *data, int datalen)\n/* Copies data to .outpacket and resets all counters.\n   data is expected to be compressed already. */\n{\n\tdatalen = MIN(datalen, sizeof(users[userid].outpacket.data));\n\tmemcpy(users[userid].outpacket.data, data, datalen);\n\tusers[userid].outpacket.len = datalen;\n\tusers[userid].outpacket.offset = 0;\n\tusers[userid].outpacket.sentlen = 0;\n\tusers[userid].outpacket.seqno = (users[userid].outpacket.seqno + 1) & 7;\n\tusers[userid].outpacket.fragment = 0;\n\tusers[userid].outfragresent = 0;\n}\n\n#ifdef OUTPACKETQ_LEN\n\nstatic int save_to_outpacketq(int userid, char *data, int datalen)\n/* Find space in outpacket-queue and store data (expected compressed already).\n   Returns: 1 = okay, 0 = no space. */\n{\n\tint fill;\n\n\tif (users[userid].outpacketq_filled >= OUTPACKETQ_LEN)\n\t\t/* no space */\n\t\treturn 0;\n\n\tfill = users[userid].outpacketq_nexttouse +\n\t       users[userid].outpacketq_filled;\n\tif (fill >= OUTPACKETQ_LEN)\n\t\tfill -= OUTPACKETQ_LEN;\n\n\tdatalen = MIN(datalen, sizeof(users[userid].outpacketq[fill].data));\n\tmemcpy(users[userid].outpacketq[fill].data, data, datalen);\n\tusers[userid].outpacketq[fill].len = datalen;\n\n\tusers[userid].outpacketq_filled++;\n\n\tif (debug >= 3)\n\t\tfprintf(stderr, \"    Qstore, now %d\\n\",\n\t\t\tusers[userid].outpacketq_filled);\n\n\treturn 1;\n}\n\nstatic int get_from_outpacketq(int userid)\n/* Starts new outpacket from queue, if any.\n   Returns: 1 = okay, 0 = no packets were waiting. */\n{\n\tint use;\n\n\tif (users[userid].outpacketq_filled <= 0)\n\t\t/* no packets */\n\t\treturn 0;\n\n\tuse = users[userid].outpacketq_nexttouse;\n\n\tstart_new_outpacket(userid, users[userid].outpacketq[use].data,\n\t\t\t    users[userid].outpacketq[use].len);\n\n\tuse++;\n\tif (use >= OUTPACKETQ_LEN)\n\t\tuse = 0;\n\tusers[userid].outpacketq_nexttouse = use;\n\tusers[userid].outpacketq_filled--;\n\n\tif (debug >= 3)\n\t\tfprintf(stderr, \"    Qget, now %d\\n\",\n\t\t\tusers[userid].outpacketq_filled);\n\n\treturn 1;\n}\n\n#endif /* OUTPACKETQ_LEN */\n\n#ifdef DNSCACHE_LEN\n\n/* On the DNS cache:\n\n   This cache is implemented to better handle the aggressively impatient DNS\n   servers that very quickly re-send requests when we choose to not\n   immediately answer them in lazy mode. This cache works much better than\n   pruning(=dropping) the improper requests, since the DNS server will\n   actually get an answer instead of silence.\n\n   Because of the CMC in both ping and upstream data, unwanted cache hits\n   are prevented. Data-CMC is only 36 counts, so our cache length should\n   not exceed 36/2=18 packets. (This quick rule assumes all packets are\n   otherwise equal, which they arent: up/downstream seq/frag, tcp sequence\n   number, and of course data.)\n*/\n\nstatic void save_to_dnscache(int userid, struct query *q, char *answer, int answerlen)\n/* Store answer in our little DNS cache. */\n{\n\tint fill;\n\n\tif (answerlen > sizeof(users[userid].dnscache_answer[fill]))\n\t\treturn;  /* can't store this */\n\n\tfill = users[userid].dnscache_lastfilled + 1;\n\tif (fill >= DNSCACHE_LEN)\n\t\tfill = 0;\n\n\tmemcpy(&(users[userid].dnscache_q[fill]), q, sizeof(struct query));\n\tmemcpy(users[userid].dnscache_answer[fill], answer, answerlen);\n\tusers[userid].dnscache_answerlen[fill] = answerlen;\n\n\tusers[userid].dnscache_lastfilled = fill;\n}\n\nstatic int answer_from_dnscache(int dns_fd, int userid, struct query *q)\n/* Checks cache and sends repeated answer if we alreay saw this query recently.\n   Returns: 1 = answer sent, drop this query, 0 = no answer sent, this is\n   a new query. */\n{\n\tint i;\n\tint use;\n\n\tfor (i = 0; i < DNSCACHE_LEN ; i++) {\n\t\t/* Try cache most-recent-first */\n\t\tuse = users[userid].dnscache_lastfilled - i;\n\t\tif (use < 0)\n\t\t\tuse += DNSCACHE_LEN;\n\n\t\tif (users[userid].dnscache_q[use].id == 0)\n\t\t\tcontinue;\n\t\tif (users[userid].dnscache_answerlen[use] <= 0)\n\t\t\tcontinue;\n\n\t\tif (users[userid].dnscache_q[use].type != q->type ||\n\t\t    strcmp(users[userid].dnscache_q[use].name, q->name))\n\t\t\tcontinue;\n\n\t\t/* okay, match */\n\t\tif (debug >= 1)\n\t\t\tfprintf(stderr, \"OUT  user %d %s from dnscache\\n\", userid, q->name);\n\n\t\twrite_dns(dns_fd, q, users[userid].dnscache_answer[use],\n\t\t\t  users[userid].dnscache_answerlen[use],\n\t\t\t  users[userid].downenc);\n\n\t\tq->id = 0;\t/* this query was used */\n\t\treturn 1;\n\t}\n\n\t/* here only when no match found */\n\treturn 0;\n}\n\n#endif /* DNSCACHE_LEN */\n\nstatic inline void save_to_qmem(unsigned char *qmem_cmc,\n\t\t\t\tunsigned short *qmem_type, int qmem_len,\n\t\t\t\tint *qmem_lastfilled,\n\t\t\t\tunsigned char *cmc_to_add,\n\t\t\t\tunsigned short type_to_add)\n/* Remember query to check for duplicates */\n{\n\tint fill;\n\n\tfill = *qmem_lastfilled + 1;\n\tif (fill >= qmem_len)\n\t\tfill = 0;\n\n\tmemcpy(qmem_cmc + fill * 4, cmc_to_add, 4);\n\tqmem_type[fill] = type_to_add;\n\t*qmem_lastfilled = fill;\n}\n\nstatic inline void save_to_qmem_pingordata(int userid, struct query *q)\n{\n\t/* Our CMC is a bit more than the \"official\" CMC; we store 4 bytes\n\t   just because we can, and because it may prevent some false matches.\n\t   For ping, we save the 4 decoded bytes: userid + seq/frag + CMC.\n\t   For data, we save the 4 _un_decoded chars in lowercase: seq/frag's\n\t   + 1 char CMC; that last char is non-Base32.\n\t */\n\n\tchar cmc[8];\n\tint i;\n\n\tif (q->name[0] == 'P' || q->name[0] == 'p') {\n\t\t/* Ping packet */\n\n\t\tsize_t cmcsize = sizeof(cmc);\n\t\tchar *cp = strchr(q->name, '.');\n\n\t\tif (cp == NULL)\n\t\t\treturn;  /* illegal hostname; shouldn't happen */\n\n\t\t/* We already unpacked in handle_null_request(), but that's\n\t\t   lost now... Note: b32 directly, we want no undotify here! */\n\t\ti = base32_ops.decode(cmc, &cmcsize, q->name + 1, (cp - q->name) - 1);\n\n\t\tif (i < 4)\n\t\t\treturn;\t /* illegal ping; shouldn't happen */\n\n\t\tsave_to_qmem(users[userid].qmemping_cmc,\n\t\t\t     users[userid].qmemping_type, QMEMPING_LEN,\n\t\t\t     &users[userid].qmemping_lastfilled,\n\t\t\t     (void *) cmc, q->type);\n\t} else {\n\t\t/* Data packet, hopefully not illegal */\n\t\tif (strlen(q->name) < 5)\n\t\t\treturn;\n\n\t\t/* We store CMC in lowercase; if routing via multiple parallel\n\t\t   DNS servers, one may do case-switch and another may not,\n\t\t   and we still want to detect duplicates.\n\t\t   Data-header is always base32, so case-swap won't hurt.\n\t\t */\n\t\tfor (i = 0; i < 4; i++)\n\t\t\tif (q->name[i+1] >= 'A' && q->name[i+1] <= 'Z')\n\t\t\t\tcmc[i] = q->name[i+1] + ('a' - 'A');\n\t\t\telse\n\t\t\t\tcmc[i] = q->name[i+1];\n\n\t\tsave_to_qmem(users[userid].qmemdata_cmc,\n\t\t\t     users[userid].qmemdata_type, QMEMDATA_LEN,\n\t\t\t     &users[userid].qmemdata_lastfilled,\n\t\t\t     (void *) cmc, q->type);\n\t}\n}\n\nstatic int answer_from_qmem(int dns_fd, struct query *q,\n\t\t\t    unsigned char *qmem_cmc, unsigned short *qmem_type,\n\t\t\t    int qmem_len, unsigned char *cmc_to_check)\n/* Checks query memory and sends an (illegal) answer if this is a duplicate.\n   Returns: 1 = answer sent, drop this query, 0 = no answer sent, this is\n   not a duplicate. */\n{\n\tint i;\n\n\tfor (i = 0; i < qmem_len ; i++) {\n\n\t\tif (qmem_type[i] == T_UNSET)\n\t\t\tcontinue;\n\t\tif (qmem_type[i] != q->type)\n\t\t\tcontinue;\n\t\tif (memcmp(qmem_cmc + i * 4, cmc_to_check, 4))\n\t\t\tcontinue;\n\n\t\t/* okay, match */\n\t\tif (debug >= 1)\n\t\t\tfprintf(stderr, \"OUT  from qmem for %s == duplicate, sending illegal reply\\n\", q->name);\n\n\t\twrite_dns(dns_fd, q, \"x\", 1, 'T');\n\n\t\tq->id = 0;\t/* this query was used */\n\t\treturn 1;\n\t}\n\n\t/* here only when no match found */\n\treturn 0;\n}\n\n/* Quick helper function to keep handle_null_request() clean */\nstatic inline int answer_from_qmem_data(int dns_fd, int userid,\n\t\t\t\t\tstruct query *q)\n{\n\tchar cmc[4];\n\tint i;\n\n\tfor (i = 0; i < 4; i++)\n\t\tif (q->name[i+1] >= 'A' && q->name[i+1] <= 'Z')\n\t\t\tcmc[i] = q->name[i+1] + ('a' - 'A');\n\t\telse\n\t\t\tcmc[i] = q->name[i+1];\n\n\treturn answer_from_qmem(dns_fd, q, users[userid].qmemdata_cmc,\n\t\t\t\tusers[userid].qmemdata_type, QMEMDATA_LEN,\n\t\t\t\t(void *) cmc);\n}\n\n/* Sends current fragment to user, or dataless packet if there is no\n   current fragment available (-> normal \"quiet\" ping reply).\n   Does not update anything, except:\n   - discards q always (query is used)\n   - forgets entire users[userid].outpacket if it was sent in one go,\n     and then tries to get new packet from outpacket-queue\n   Returns: 1 = can call us again immediately, new packet from queue;\n   0 = don't call us again for now.\n*/\nstatic int send_chunk_or_dataless(int dns_fd, int userid, struct query *q)\n{\n\tchar pkt[4096];\n\tint datalen = 0;\n\tint last = 0;\n\n\t/* If re-sent too many times, drop entire packet */\n\tif (users[userid].outpacket.len > 0 &&\n\t    users[userid].outfragresent > 5) {\n\t\tusers[userid].outpacket.len = 0;\n\t\tusers[userid].outpacket.offset = 0;\n\t\tusers[userid].outpacket.sentlen = 0;\n\t\tusers[userid].outfragresent = 0;\n\n#ifdef OUTPACKETQ_LEN\n\t\t/* Maybe more in queue, use immediately */\n\t\tget_from_outpacketq(userid);\n#endif\n\t}\n\n\tif (users[userid].outpacket.len > 0) {\n\t\tdatalen = MIN(users[userid].fragsize, users[userid].outpacket.len - users[userid].outpacket.offset);\n\t\tdatalen = MIN(datalen, sizeof(pkt)-2);\n\n\t\tmemcpy(&pkt[2], users[userid].outpacket.data + users[userid].outpacket.offset, datalen);\n\t\tusers[userid].outpacket.sentlen = datalen;\n\t\tlast = (users[userid].outpacket.len == users[userid].outpacket.offset + datalen);\n\n\t\tusers[userid].outfragresent++;\n\t}\n\n\t/* Build downstream data header (see doc/proto_xxxxxxxx.txt) */\n\n\t/* First byte is 1 bit compression flag, 3 bits upstream seqno, 4 bits upstream fragment */\n\tpkt[0] = (1<<7) | ((users[userid].inpacket.seqno & 7) << 4) |\n\t\t(users[userid].inpacket.fragment & 15);\n\t/* Second byte is 3 bits downstream seqno, 4 bits downstream fragment, 1 bit last flag */\n\tpkt[1] = ((users[userid].outpacket.seqno & 7) << 5) |\n\t\t((users[userid].outpacket.fragment & 15) << 1) | (last & 1);\n\n\tif (debug >= 1) {\n\t\tfprintf(stderr, \"OUT  pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\\n\",\n\t\t\tusers[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15,\n\t\t\tlast, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid);\n\t}\n\twrite_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc);\n\n\tif (q->id2 != 0) {\n\t\tq->id = q->id2;\n\t\tq->fromlen = q->fromlen2;\n\t\tmemcpy(&(q->from), &(q->from2), q->fromlen2);\n\t\tif (debug >= 1)\n\t\t\tfprintf(stderr, \"OUT  again to last duplicate\\n\");\n\t\twrite_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc);\n\t}\n\n\tsave_to_qmem_pingordata(userid, q);\n\n#ifdef DNSCACHE_LEN\n\tsave_to_dnscache(userid, q, pkt, datalen + 2);\n#endif\n\n\tq->id = 0;\t\t\t/* this query is used */\n\n\tif (datalen > 0 && datalen == users[userid].outpacket.len) {\n\t\t/* Whole packet was sent in one chunk, dont wait for ack */\n\t\tusers[userid].outpacket.len = 0;\n\t\tusers[userid].outpacket.offset = 0;\n\t\tusers[userid].outpacket.sentlen = 0;\n\t\tusers[userid].outfragresent = 0;\n\n#ifdef OUTPACKETQ_LEN\n\t\t/* Maybe more in queue, prepare for next time */\n\t\tif (get_from_outpacketq(userid) == 1) {\n\t\t\tif (debug >= 3)\n\t\t\t\tfprintf(stderr, \"    Chunk & fromqueue: callagain\\n\");\n\t\t\treturn 1;\t/* call us again */\n\t\t}\n#endif\n\t}\n\n\treturn 0;\t/* don't call us again */\n}\n\nstatic int tunnel_tun(int tun_fd, struct dnsfd *dns_fds)\n{\n\tunsigned long outlen;\n\tstruct ip *header;\n\tchar out[64*1024];\n\tchar in[64*1024];\n\tint userid;\n\tint read;\n\n\tif ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)\n\t\treturn 0;\n\n\t/* find target ip in packet, in is padded with 4 bytes TUN header */\n\theader = (struct ip*) (in + 4);\n\tuserid = find_user_by_ip(header->ip_dst.s_addr);\n\tif (userid < 0)\n\t\treturn 0;\n\n\toutlen = sizeof(out);\n\tcompress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);\n\n\tif (users[userid].conn == CONN_DNS_NULL) {\n#ifdef OUTPACKETQ_LEN\n\t\t/* If a packet is being sent, try storing the new one in the queue.\n\t\t   If the queue is full, drop the packet. TCP will hopefully notice\n\t\t   and reduce the packet rate. */\n\t\tif (users[userid].outpacket.len > 0) {\n\t\t\tsave_to_outpacketq(userid, out, outlen);\n\t\t\treturn 0;\n\t\t}\n#endif\n\n\t\tstart_new_outpacket(userid, out, outlen);\n\n\t\t/* Start sending immediately if query is waiting */\n\t\tif (users[userid].q_sendrealsoon.id != 0) {\n\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[userid].q_sendrealsoon.from);\n\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon);\n\t\t} else if (users[userid].q.id != 0) {\n\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[userid].q.from);\n\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q);\n\t\t}\n\n\t\treturn outlen;\n\t} else { /* CONN_RAW_UDP */\n\t\tint dns_fd = get_dns_fd(dns_fds, &users[userid].q.from);\n\t\tsend_raw(dns_fd, out, outlen, userid, RAW_HDR_CMD_DATA, &users[userid].q);\n\t\treturn outlen;\n\t}\n}\n\ntypedef enum {\n\tVERSION_ACK,\n\tVERSION_NACK,\n\tVERSION_FULL\n} version_ack_t;\n\nstatic void send_version_response(int fd, version_ack_t ack, uint32_t payload,\n\t\t\t\t  int userid, struct query *q)\n{\n\tchar out[9];\n\n\tswitch (ack) {\n\tcase VERSION_ACK:\n\t\tstrncpy(out, \"VACK\", sizeof(out));\n\t\tbreak;\n\tcase VERSION_NACK:\n\t\tstrncpy(out, \"VNAK\", sizeof(out));\n\t\tbreak;\n\tcase VERSION_FULL:\n\t\tstrncpy(out, \"VFUL\", sizeof(out));\n\t\tbreak;\n\t}\n\n\tout[4] = ((payload >> 24) & 0xff);\n\tout[5] = ((payload >> 16) & 0xff);\n\tout[6] = ((payload >> 8) & 0xff);\n\tout[7] = ((payload) & 0xff);\n\tout[8] = userid & 0xff;\n\n\twrite_dns(fd, q, out, sizeof(out), users[userid].downenc);\n}\n\n/* Process acks from downstream fragments.\n   After this, .offset and .fragment are updated (if ack correct),\n   or .len is set to zero when all is done.\n*/\nstatic void process_downstream_ack(int userid, int down_seq, int down_frag)\n{\n\tif (users[userid].outpacket.len <= 0)\n\t\t/* No packet to apply acks to */\n\t\treturn;\n\n\tif (users[userid].outpacket.seqno != down_seq ||\n\t    users[userid].outpacket.fragment != down_frag)\n\t\t/* Not the ack we're waiting for; probably duplicate of old\n\t\t   ack, happens a lot with ping packets */\n\t\treturn;\n\n\t/* Received proper ack */\n\tusers[userid].outpacket.offset += users[userid].outpacket.sentlen;\n\tusers[userid].outpacket.sentlen = 0;\n\tusers[userid].outpacket.fragment++;\n\tusers[userid].outfragresent = 0;\n\n\t/* Is packet done? */\n\tif (users[userid].outpacket.offset >= users[userid].outpacket.len) {\n\t\tusers[userid].outpacket.len = 0;\n\t\tusers[userid].outpacket.offset = 0;\n\t\tusers[userid].outpacket.fragment--;\t/* unneeded ++ above */\n\t\t/* ^keep last seqno/frag, are always returned on pings */\n\t\t/* users[userid].outfragresent = 0; already above */\n\n#ifdef OUTPACKETQ_LEN\n\t\t/* Possibly get new packet from queue */\n\t\tget_from_outpacketq(userid);\n#endif\n\t}\n}\n\nstatic void\nhandle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query *q, int domain_len)\n{\n\tstruct in_addr tempip;\n\tchar in[512];\n\tchar logindata[16];\n\tchar out[64*1024];\n\tchar unpacked[64*1024];\n\tchar *tmp[2];\n\tint userid;\n\tint read;\n\n\tuserid = -1;\n\n\t/* Everything here needs at least two chars in the name */\n\tif (domain_len < 2)\n\t\treturn;\n\n\tmemcpy(in, q->name, MIN(domain_len, sizeof(in)));\n\n\tif (in[0] == 'V' || in[0] == 'v') {\n\t\tint version = 0;\n\n\t\tread = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops);\n\t\t/* Version greeting, compare and send ack/nak */\n\t\tif (read > 4) {\n\t\t\t/* Received V + 32bits version */\n\t\t\tversion = (((unpacked[0] & 0xff) << 24) |\n\t\t\t\t\t   ((unpacked[1] & 0xff) << 16) |\n\t\t\t\t\t   ((unpacked[2] & 0xff) << 8) |\n\t\t\t\t\t   ((unpacked[3] & 0xff)));\n\t\t}\n\n\t\tif (version == PROTOCOL_VERSION) {\n\t\t\tuserid = find_available_user();\n\t\t\tif (userid >= 0) {\n\t\t\t\tint i;\n\n\t\t\t\tusers[userid].seed = rand();\n\t\t\t\t/* Store remote IP number */\n\t\t\t\tmemcpy(&(users[userid].host), &(q->from), q->fromlen);\n\t\t\t\tusers[userid].hostlen = q->fromlen;\n\n\t\t\t\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\t\t\t\tusers[userid].encoder = &base32_ops;\n\t\t\t\tusers[userid].downenc = 'T';\n\t\t\t\tsend_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q);\n\t\t\t\tsyslog(LOG_INFO, \"accepted version for user #%d from %s\",\n\t\t\t\t\tuserid, format_addr(&q->from, q->fromlen));\n\t\t\t\tusers[userid].q.id = 0;\n\t\t\t\tusers[userid].q.id2 = 0;\n\t\t\t\tusers[userid].q_sendrealsoon.id = 0;\n\t\t\t\tusers[userid].q_sendrealsoon.id2 = 0;\n\t\t\t\tusers[userid].q_sendrealsoon_new = 0;\n\t\t\t\tusers[userid].outpacket.len = 0;\n\t\t\t\tusers[userid].outpacket.offset = 0;\n\t\t\t\tusers[userid].outpacket.sentlen = 0;\n\t\t\t\tusers[userid].outpacket.seqno = 0;\n\t\t\t\tusers[userid].outpacket.fragment = 0;\n\t\t\t\tusers[userid].outfragresent = 0;\n\t\t\t\tusers[userid].inpacket.len = 0;\n\t\t\t\tusers[userid].inpacket.offset = 0;\n\t\t\t\tusers[userid].inpacket.seqno = 0;\n\t\t\t\tusers[userid].inpacket.fragment = 0;\n\t\t\t\tusers[userid].fragsize = 100; /* very safe */\n\t\t\t\tusers[userid].conn = CONN_DNS_NULL;\n\t\t\t\tusers[userid].lazy = 0;\n#ifdef OUTPACKETQ_LEN\n\t\t\t\tusers[userid].outpacketq_nexttouse = 0;\n\t\t\t\tusers[userid].outpacketq_filled = 0;\n#endif\n#ifdef DNSCACHE_LEN\n\t\t\t\t{\n\t\t\t\t\tfor (i = 0; i < DNSCACHE_LEN; i++) {\n\t\t\t\t\t\tusers[userid].dnscache_q[i].id = 0;\n\t\t\t\t\t\tusers[userid].dnscache_answerlen[i] = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tusers[userid].dnscache_lastfilled = 0;\n#endif\n\t\t\t\tfor (i = 0; i < QMEMPING_LEN; i++)\n\t\t\t\t\tusers[userid].qmemping_type[i] = T_UNSET;\n\t\t\t\tusers[userid].qmemping_lastfilled = 0;\n\t\t\t\tfor (i = 0; i < QMEMDATA_LEN; i++)\n\t\t\t\t\tusers[userid].qmemdata_type[i] = T_UNSET;\n\t\t\t\tusers[userid].qmemdata_lastfilled = 0;\n\t\t\t} else {\n\t\t\t\t/* No space for another user */\n\t\t\t\tsend_version_response(dns_fd, VERSION_FULL, created_users, 0, q);\n\t\t\t\tsyslog(LOG_INFO, \"dropped user from %s, server full\",\n\t\t\t\t\tformat_addr(&q->from, q->fromlen));\n\t\t\t}\n\t\t} else {\n\t\t\tsend_version_response(dns_fd, VERSION_NACK, PROTOCOL_VERSION, 0, q);\n\t\t\tsyslog(LOG_INFO, \"dropped user from %s, sent bad version %08X\",\n\t\t\t\tformat_addr(&q->from, q->fromlen), version);\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'L' || in[0] == 'l') {\n\t\tread = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops);\n\t\tif (read < 17) {\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\t/* Login phase, handle auth */\n\t\tuserid = unpacked[0];\n\n\t\tif (check_user_and_ip(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\tsyslog(LOG_WARNING, \"dropped login request from user #%d from unexpected source %s\",\n\t\t\t\tuserid, format_addr(&q->from, q->fromlen));\n\t\t\treturn;\n\t\t} else {\n\t\t\tusers[userid].last_pkt = time(NULL);\n\t\t\tlogin_calculate(logindata, 16, password, users[userid].seed);\n\n\t\t\tif (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {\n\t\t\t\t/* Store login ok */\n\t\t\t\tusers[userid].authenticated = 1;\n\n\t\t\t\t/* Send ip/mtu/netmask info */\n\t\t\t\ttempip.s_addr = my_ip;\n\t\t\t\ttmp[0] = strdup(inet_ntoa(tempip));\n\t\t\t\ttempip.s_addr = users[userid].tun_ip;\n\t\t\t\ttmp[1] = strdup(inet_ntoa(tempip));\n\n\t\t\t\tread = snprintf(out, sizeof(out), \"%s-%s-%d-%d\",\n\t\t\t\t\t\ttmp[0], tmp[1], my_mtu, netmask);\n\n\t\t\t\twrite_dns(dns_fd, q, out, read, users[userid].downenc);\n\t\t\t\tq->id = 0;\n\t\t\t\tsyslog(LOG_NOTICE, \"accepted password from user #%d, given IP %s\", userid, tmp[1]);\n\n\t\t\t\tfree(tmp[1]);\n\t\t\t\tfree(tmp[0]);\n\t\t\t} else {\n\t\t\t\twrite_dns(dns_fd, q, \"LNAK\", 4, 'T');\n\t\t\t\tsyslog(LOG_WARNING, \"rejected login request from user #%d from %s, bad password\",\n\t\t\t\t\tuserid, format_addr(&q->from, q->fromlen));\n\t\t\t}\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'I' || in[0] == 'i') {\n\t\t/* Request for IP number */\n\t\tchar reply[17];\n\t\tint length;\n\n\t\tuserid = b32_8to5(in[1]);\n\t\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n\t\treply[0] = 'I';\n\t\tif (q->from.ss_family == AF_INET) {\n\t\t\tif (ns_ip != INADDR_ANY) {\n\t\t\t\t/* If set, use assigned external ip (-n option) */\n\t\t\t\tmemcpy(&reply[1], &ns_ip, sizeof(ns_ip));\n\t\t\t} else {\n\t\t\t\t/* otherwise return destination ip from packet */\n\t\t\t\tstruct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;\n\t\t\t\tmemcpy(&reply[1], &addr->sin_addr, sizeof(struct in_addr));\n\t\t\t}\n\t\t\tlength = 1 + sizeof(struct in_addr);\n\t\t} else {\n\t\t\tstruct sockaddr_in6 *addr = (struct sockaddr_in6 *) &q->destination;\n\t\t\tmemcpy(&reply[1], &addr->sin6_addr, sizeof(struct in6_addr));\n\t\t\tlength = 1 + sizeof(struct in6_addr);\n\t\t}\n\n\t\twrite_dns(dns_fd, q, reply, length, 'T');\n\t} else if (in[0] == 'Z' || in[0] == 'z') {\n\t\t/* Check for case conservation and chars not allowed according to RFC */\n\n\t\t/* Reply with received hostname as data */\n\t\t/* No userid here, reply with lowest-grade downenc */\n\t\twrite_dns(dns_fd, q, in, domain_len, 'T');\n\t\treturn;\n\t} else if (in[0] == 'S' || in[0] == 's') {\n\t\tint codec;\n\t\tconst struct encoder *enc;\n\n\t\tif (domain_len < 3) { /* len at least 3, example: \"S15\" */\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\tuserid = b32_8to5(in[1]);\n\n\t\tif (check_authenticated_user_and_ip_and_options(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n\t\tcodec = b32_8to5(in[2]);\n\n\t\tswitch (codec) {\n\t\tcase 5: /* 5 bits per byte = base32 */\n\t\t\tenc = &base32_ops;\n\t\t\tuser_switch_codec(userid, enc);\n\t\t\twrite_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 6: /* 6 bits per byte = base64 */\n\t\t\tenc = &base64_ops;\n\t\t\tuser_switch_codec(userid, enc);\n\t\t\twrite_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 26: /* \"2nd\" 6 bits per byte = base64u, with underscore */\n\t\t\tenc = &base64u_ops;\n\t\t\tuser_switch_codec(userid, enc);\n\t\t\twrite_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 7: /* 7 bits per byte = base128 */\n\t\t\tenc = &base128_ops;\n\t\t\tuser_switch_codec(userid, enc);\n\t\t\twrite_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\twrite_dns(dns_fd, q, \"BADCODEC\", 8, users[userid].downenc);\n\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'O' || in[0] == 'o') {\n\t\tif (domain_len < 3) { /* len at least 3, example: \"O1T\" */\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\tuserid = b32_8to5(in[1]);\n\n\t\tif (check_authenticated_user_and_ip_and_options(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n\t\tswitch (in[2]) {\n\t\tcase 'T':\n\t\tcase 't':\n\t\t\tusers[userid].downenc = 'T';\n\t\t\twrite_dns(dns_fd, q, \"Base32\", 6, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'S':\n\t\tcase 's':\n\t\t\tusers[userid].downenc = 'S';\n\t\t\twrite_dns(dns_fd, q, \"Base64\", 6, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'U':\n\t\tcase 'u':\n\t\t\tusers[userid].downenc = 'U';\n\t\t\twrite_dns(dns_fd, q, \"Base64u\", 7, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'V':\n\t\tcase 'v':\n\t\t\tusers[userid].downenc = 'V';\n\t\t\twrite_dns(dns_fd, q, \"Base128\", 7, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'R':\n\t\tcase 'r':\n\t\t\tusers[userid].downenc = 'R';\n\t\t\twrite_dns(dns_fd, q, \"Raw\", 3, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'L':\n\t\tcase 'l':\n\t\t\tusers[userid].lazy = 1;\n\t\t\twrite_dns(dns_fd, q, \"Lazy\", 4, users[userid].downenc);\n\t\t\tbreak;\n\t\tcase 'I':\n\t\tcase 'i':\n\t\t\tusers[userid].lazy = 0;\n\t\t\twrite_dns(dns_fd, q, \"Immediate\", 9, users[userid].downenc);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\twrite_dns(dns_fd, q, \"BADCODEC\", 8, users[userid].downenc);\n\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'Y' || in[0] == 'y') {\n\t\tint i;\n\t\tchar *datap;\n\t\tint datalen;\n\n\t\tif (domain_len < 6) { /* len at least 6, example: \"YTxCMC\" */\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\ti = b32_8to5(in[2]);\t/* check variant */\n\n\t\tswitch (i) {\n\t\tcase 1:\n\t\t\tdatap = DOWNCODECCHECK1;\n\t\t\tdatalen = DOWNCODECCHECK1_LEN;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (in[1]) {\n\t\tcase 'T':\n\t\tcase 't':\n\t\t\tif (q->type == T_TXT ||\n\t\t\t    q->type == T_SRV || q->type == T_MX ||\n\t\t\t    q->type == T_CNAME || q->type == T_A) {\n\t\t\t\twrite_dns(dns_fd, q, datap, datalen, 'T');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'S':\n\t\tcase 's':\n\t\t\tif (q->type == T_TXT ||\n\t\t\t    q->type == T_SRV || q->type == T_MX ||\n\t\t\t    q->type == T_CNAME || q->type == T_A) {\n\t\t\t\twrite_dns(dns_fd, q, datap, datalen, 'S');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'U':\n\t\tcase 'u':\n\t\t\tif (q->type == T_TXT ||\n\t\t\t    q->type == T_SRV || q->type == T_MX ||\n\t\t\t    q->type == T_CNAME || q->type == T_A) {\n\t\t\t\twrite_dns(dns_fd, q, datap, datalen, 'U');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'V':\n\t\tcase 'v':\n\t\t\tif (q->type == T_TXT ||\n\t\t\t    q->type == T_SRV || q->type == T_MX ||\n\t\t\t    q->type == T_CNAME || q->type == T_A) {\n\t\t\t\twrite_dns(dns_fd, q, datap, datalen, 'V');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'R':\n\t\tcase 'r':\n\t\t\tif (q->type == T_NULL || q->type == T_TXT) {\n\t\t\t\twrite_dns(dns_fd, q, datap, datalen, 'R');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t/* if still here, then codec not available */\n\t\twrite_dns(dns_fd, q, \"BADCODEC\", 8, 'T');\n\t\treturn;\n\n\t} else if (in[0] == 'R' || in[0] == 'r') {\n\t\tint req_frag_size;\n\n\t\tif (domain_len < 16) {  /* we'd better have some chars for data... */\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\t/* Downstream fragsize probe packet */\n\t\tuserid = (b32_8to5(in[1]) >> 1) & 15;\n\t\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n\t\treq_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31);\n\t\tif (req_frag_size < 2 || req_frag_size > 2047) {\n\t\t\twrite_dns(dns_fd, q, \"BADFRAG\", 7, users[userid].downenc);\n\t\t} else {\n\t\t\tchar buf[2048];\n\t\t\tint i;\n\t\t\tunsigned int v = ((unsigned int) rand()) & 0xff ;\n\n\t\t\tmemset(buf, 0, sizeof(buf));\n\t\t\tbuf[0] = (req_frag_size >> 8) & 0xff;\n\t\t\tbuf[1] = req_frag_size & 0xff;\n\t\t\t/* make checkable pseudo-random sequence */\n\t\t\tbuf[2] = 107;\n\t\t\tfor (i = 3; i < 2048; i++, v = (v + 107) & 0xff)\n\t\t\t\tbuf[i] = v;\n\t\t\twrite_dns(dns_fd, q, buf, req_frag_size, users[userid].downenc);\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'N' || in[0] == 'n') {\n\t\tint max_frag_size;\n\n\t\tread = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops);\n\n\t\tif (read < 3) {\n\t\t\twrite_dns(dns_fd, q, \"BADLEN\", 6, 'T');\n\t\t\treturn;\n\t\t}\n\n\t\t/* Downstream fragsize packet */\n\t\tuserid = unpacked[0];\n\t\tif (check_authenticated_user_and_ip_and_options(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n\t\tmax_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff);\n\t\tif (max_frag_size < 2) {\n\t\t\twrite_dns(dns_fd, q, \"BADFRAG\", 7, users[userid].downenc);\n\t\t} else {\n\t\t\tusers[userid].fragsize = max_frag_size;\n\t\t\tusers[userid].options_locked = 1;\n\t\t\twrite_dns(dns_fd, q, &unpacked[1], 2, users[userid].downenc);\n\t\t}\n\t\treturn;\n\t} else if (in[0] == 'P' || in[0] == 'p') {\n\t\tint dn_seq;\n\t\tint dn_frag;\n\t\tint didsend = 0;\n\n\t\t/* We can't handle id=0, that's \"no packet\" to us. So drop\n\t\t   request completely. Note that DNS servers rewrite the id.\n\t\t   We'll drop 1 in 64k times. If DNS server retransmits with\n\t\t   different id, then all okay.\n\t\t   Else client won't retransmit, and we'll just keep the\n\t\t   previous ping in cache, no problem either. */\n\t\tif (q->id == 0)\n\t\t\treturn;\n\n\t\tread = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops);\n\t\tif (read < 4)\n\t\t\treturn;\n\n\t\t/* Ping packet, store userid */\n\t\tuserid = unpacked[0];\n\t\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n#ifdef DNSCACHE_LEN\n\t\t/* Check if cached */\n\t\tif (answer_from_dnscache(dns_fd, userid, q))\n\t\t\treturn;\n#endif\n\n\t\t/* Check if duplicate (and not in full dnscache any more) */\n\t\tif (answer_from_qmem(dns_fd, q, users[userid].qmemping_cmc,\n\t\t\t\t     users[userid].qmemping_type, QMEMPING_LEN,\n\t\t\t\t     (void *) unpacked))\n\t\t\treturn;\n\n\t\t/* Check if duplicate of waiting queries; impatient DNS relays\n\t\t   like to re-try early and often (with _different_ .id!)  */\n\t\tif (users[userid].q.id != 0 &&\n\t\t    q->type == users[userid].q.type &&\n\t\t    !strcmp(q->name, users[userid].q.name) &&\n\t\t    users[userid].lazy) {\n\t\t\t/* We have this ping already, and it's waiting to be\n\t\t\t   answered. Always keep the last duplicate, since the\n\t\t\t   relay may have forgotten its first version already.\n\t\t\t   Our answer will go to both.\n\t\t\t   (If we already sent an answer, qmem/cache will\n\t\t\t   have triggered.) */\n\t\t\tif (debug >= 2) {\n\t\t\t\tfprintf(stderr, \"PING pkt from user %d = dupe from impatient DNS server, remembering\\n\",\n\t\t\t\t\tuserid);\n\t\t\t}\n\t\t\tusers[userid].q.id2 = q->id;\n\t\t\tusers[userid].q.fromlen2 = q->fromlen;\n\t\t\tmemcpy(&(users[userid].q.from2), &(q->from), q->fromlen);\n\t\t\treturn;\n\t\t}\n\n\t\tif (users[userid].q_sendrealsoon.id != 0 &&\n\t\t    q->type == users[userid].q_sendrealsoon.type &&\n\t\t    !strcmp(q->name, users[userid].q_sendrealsoon.name)) {\n\t\t\t/* Outer select loop will send answer immediately,\n\t\t\t   to both queries. */\n\t\t\tif (debug >= 2) {\n\t\t\t\tfprintf(stderr, \"PING pkt from user %d = dupe from impatient DNS server, remembering\\n\",\n\t\t\t\t\tuserid);\n\t\t\t}\n\t\t\tusers[userid].q_sendrealsoon.id2 = q->id;\n\t\t\tusers[userid].q_sendrealsoon.fromlen2 = q->fromlen;\n\t\t\tmemcpy(&(users[userid].q_sendrealsoon.from2),\n\t\t\t       &(q->from), q->fromlen);\n\t\t\treturn;\n\t\t}\n\n\t\tdn_seq = unpacked[1] >> 4;\n\t\tdn_frag = unpacked[1] & 15;\n\n\t\tif (debug >= 1) {\n\t\t\tfprintf(stderr, \"PING pkt from user %d, ack for downstream %d/%d\\n\",\n\t\t\t\tuserid, dn_seq, dn_frag);\n\t\t}\n\n\t\tprocess_downstream_ack(userid, dn_seq, dn_frag);\n\n\t\tif (debug >= 3) {\n\t\t\tfprintf(stderr, \"PINGret (if any) will ack upstream %d/%d\\n\",\n\t\t\t\tusers[userid].inpacket.seqno, users[userid].inpacket.fragment);\n\t\t}\n\n\t\t/* If there is a query that must be returned real soon, do it.\n\t\t   May contain new downstream data if the ping had a new ack.\n\t\t   Otherwise, may also be re-sending old data. */\n\t\tif (users[userid].q_sendrealsoon.id != 0) {\n\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon);\n\t\t}\n\n\t\t/* We need to store a new query, so if there still is an\n\t\t   earlier query waiting, always send a reply to finish it.\n\t\t   May contain new downstream data if the ping had a new ack.\n\t\t   Otherwise, may also be re-sending old data.\n\t\t   (This is duplicate data if we had q_sendrealsoon above.) */\n\t\tif (users[userid].q.id != 0) {\n\t\t\tdidsend = 1;\n\t\t\tif (send_chunk_or_dataless(dns_fd, userid, &users[userid].q) == 1)\n\t\t\t\t/* new packet from queue, send immediately */\n\t\t\t\tdidsend = 0;\n\t\t}\n\n\t\t/* Save new query and time info */\n\t\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\t\tusers[userid].last_pkt = time(NULL);\n\n\t\t/* If anything waiting and we didn't already send above, send\n\t\t   it now. And always send immediately if we're not lazy\n\t\t   (then above won't have sent at all). */\n\t\tif ((!didsend && users[userid].outpacket.len > 0) ||\n\t\t    !users[userid].lazy)\n\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q);\n\n\t} else if ((in[0] >= '0' && in[0] <= '9')\n\t\t\t|| (in[0] >= 'a' && in[0] <= 'f')\n\t\t\t|| (in[0] >= 'A' && in[0] <= 'F')) {\n\t\tint up_seq, up_frag, dn_seq, dn_frag, lastfrag;\n\t\tint upstream_ok = 1;\n\t\tint didsend = 0;\n\t\tint code = -1;\n\n\t\t/* Need 5char header + >=1 char data */\n\t\tif (domain_len < 6)\n\t\t\treturn;\n\n\t\t/* We can't handle id=0, that's \"no packet\" to us. So drop\n\t\t   request completely. Note that DNS servers rewrite the id.\n\t\t   We'll drop 1 in 64k times. If DNS server retransmits with\n\t\t   different id, then all okay.\n\t\t   Else client doesn't get our ack, and will retransmit in\n\t\t   1 second. */\n\t\tif (q->id == 0)\n\t\t\treturn;\n\n\t\tif ((in[0] >= '0' && in[0] <= '9'))\n\t\t\tcode = in[0] - '0';\n\t\tif ((in[0] >= 'a' && in[0] <= 'f'))\n\t\t\tcode = in[0] - 'a' + 10;\n\t\tif ((in[0] >= 'A' && in[0] <= 'F'))\n\t\t\tcode = in[0] - 'A' + 10;\n\n\t\tuserid = code;\n\t\t/* Check user and sending ip number */\n\t\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\t\twrite_dns(dns_fd, q, \"BADIP\", 5, 'T');\n\t\t\treturn; /* illegal id */\n\t\t}\n\n#ifdef DNSCACHE_LEN\n\t\t/* Check if cached */\n\t\tif (answer_from_dnscache(dns_fd, userid, q))\n\t\t\treturn;\n#endif\n\n\t\t/* Check if duplicate (and not in full dnscache any more) */\n\t\tif (answer_from_qmem_data(dns_fd, userid, q))\n\t\t\treturn;\n\n\t\t/* Check if duplicate of waiting queries; impatient DNS relays\n\t\t   like to re-try early and often (with _different_ .id!)  */\n\t\tif (users[userid].q.id != 0 &&\n\t\t    q->type == users[userid].q.type &&\n\t\t    !strcmp(q->name, users[userid].q.name) &&\n\t\t    users[userid].lazy) {\n\t\t\t/* We have this packet already, and it's waiting to be\n\t\t\t   answered. Always keep the last duplicate, since the\n\t\t\t   relay may have forgotten its first version already.\n\t\t\t   Our answer will go to both.\n\t\t\t   (If we already sent an answer, qmem/cache will\n\t\t\t   have triggered.) */\n\t\t\tif (debug >= 2) {\n\t\t\t\tfprintf(stderr, \"IN   pkt from user %d = dupe from impatient DNS server, remembering\\n\",\n\t\t\t\t\tuserid);\n\t\t\t}\n\t\t\tusers[userid].q.id2 = q->id;\n\t\t\tusers[userid].q.fromlen2 = q->fromlen;\n\t\t\tmemcpy(&(users[userid].q.from2), &(q->from), q->fromlen);\n\t\t\treturn;\n\t\t}\n\n\t\tif (users[userid].q_sendrealsoon.id != 0 &&\n\t\t    q->type == users[userid].q_sendrealsoon.type &&\n\t\t    !strcmp(q->name, users[userid].q_sendrealsoon.name)) {\n\t\t\t/* Outer select loop will send answer immediately,\n\t\t\t   to both queries. */\n\t\t\tif (debug >= 2) {\n\t\t\t\tfprintf(stderr, \"IN   pkt from user %d = dupe from impatient DNS server, remembering\\n\",\n\t\t\t\t\tuserid);\n\t\t\t}\n\t\t\tusers[userid].q_sendrealsoon.id2 = q->id;\n\t\t\tusers[userid].q_sendrealsoon.fromlen2 = q->fromlen;\n\t\t\tmemcpy(&(users[userid].q_sendrealsoon.from2),\n\t\t\t       &(q->from), q->fromlen);\n\t\t\treturn;\n\t\t}\n\n\n\t\t/* Decode data header */\n\t\tup_seq = (b32_8to5(in[1]) >> 2) & 7;\n\t\tup_frag = ((b32_8to5(in[1]) & 3) << 2) | ((b32_8to5(in[2]) >> 3) & 3);\n\t\tdn_seq = (b32_8to5(in[2]) & 7);\n\t\tdn_frag = b32_8to5(in[3]) >> 1;\n\t\tlastfrag = b32_8to5(in[3]) & 1;\n\n\t\tprocess_downstream_ack(userid, dn_seq, dn_frag);\n\n\t\tif (up_seq == users[userid].inpacket.seqno &&\n\t\t\tup_frag <= users[userid].inpacket.fragment) {\n\t\t\t/* Got repeated old packet _with data_, probably\n\t\t\t   because client didn't receive our ack. So re-send\n\t\t\t   our ack(+data) immediately to keep things flowing\n\t\t\t   fast.\n\t\t\t   If it's a _really_ old frag, it's a nameserver\n\t\t\t   that tries again, and sending our current (non-\n\t\t\t   matching) fragno won't be a problem. */\n\t\t\tif (debug >= 1) {\n\t\t\t\tfprintf(stderr, \"IN   pkt seq# %d, frag %d, dropped duplicate frag\\n\",\n\t\t\t\t\tup_seq, up_frag);\n\t\t\t}\n\t\t\tupstream_ok = 0;\n\t\t}\n\t\telse if (up_seq != users[userid].inpacket.seqno &&\n\t\t\t recent_seqno(users[userid].inpacket.seqno, up_seq)) {\n\t\t\t/* Duplicate of recent upstream data packet; probably\n\t\t\t   need to answer this to keep DNS server happy */\n\t\t\tif (debug >= 1) {\n\t\t\t\tfprintf(stderr, \"IN   pkt seq# %d, frag %d, dropped duplicate recent seqno\\n\",\n\t\t\t\t\tup_seq, up_frag);\n \t\t\t}\n\t\t\tupstream_ok = 0;\n\t\t}\n\t\telse if (up_seq != users[userid].inpacket.seqno) {\n\t\t\t/* Really new packet has arrived, no recent duplicate */\n\t\t\t/* Forget any old packet, even if incomplete */\n\t\t\tusers[userid].inpacket.seqno = up_seq;\n\t\t\tusers[userid].inpacket.fragment = up_frag;\n\t\t\tusers[userid].inpacket.len = 0;\n\t\t\tusers[userid].inpacket.offset = 0;\n\t\t} else {\n\t\t\t/* seq is same, frag is higher; don't care about\n\t\t\t   missing fragments, TCP checksum will fail */\n  \t\t\tusers[userid].inpacket.fragment = up_frag;\n\t\t}\n\n\t\tif (debug >= 3) {\n\t\t\tfprintf(stderr, \"INpack with upstream %d/%d, we are going to ack upstream %d/%d\\n\",\n\t\t\t\tup_seq, up_frag,\n\t\t\t\tusers[userid].inpacket.seqno, users[userid].inpacket.fragment);\n\t\t}\n\n\t\tif (upstream_ok) {\n\t\t\t/* decode with this user's encoding */\n\t\t\tread = unpack_data(unpacked, sizeof(unpacked), &(in[5]), domain_len - 5,\n\t\t\t\t\t   users[userid].encoder);\n\n\t\t\t/* copy to packet buffer, update length */\n\t\t\tread = MIN(read, sizeof(users[userid].inpacket.data) - users[userid].inpacket.offset);\n\t\t\tmemcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);\n\t\t\tusers[userid].inpacket.len += read;\n\t\t\tusers[userid].inpacket.offset += read;\n\n\t\t\tif (debug >= 1) {\n\t\t\t\tfprintf(stderr, \"IN   pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\\n\",\n\t\t\t\t\tup_seq, up_frag, lastfrag, read, users[userid].inpacket.len, userid);\n\t\t\t}\n\t\t}\n\n\t\tif (upstream_ok && lastfrag) { /* packet is complete */\n\t\t\thandle_full_packet(tun_fd, dns_fds, userid);\n\t\t}\n\n\t\t/* If there is a query that must be returned real soon, do it.\n\t\t   Includes an ack of the just received upstream fragment,\n\t\t   may contain new data. */\n\t\tif (users[userid].q_sendrealsoon.id != 0) {\n\t\t\tdidsend = 1;\n\t\t\tif (send_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon) == 1)\n\t\t\t\t/* new packet from queue, send immediately */\n\t\t\t\tdidsend = 0;\n\t\t}\n\n\t\t/* If we already have an earlier query waiting, we need to\n\t\t   get rid of it to store the new query.\n\t\t   - If we have new data waiting and not yet sent above,\n\t\t     send immediately.\n\t\t   - If this wasn't the last upstream fragment, then we expect\n\t\t     more, so ack immediately if we didn't already.\n\t\t   - If we are in non-lazy mode, there should be no query\n\t\t     waiting, but if there is, send immediately.\n\t\t   - In all other cases (mostly the last-fragment cases),\n\t\t     we can afford to wait just a tiny little while for the\n\t\t     TCP ack to arrive from our tun. Note that this works best\n\t\t     when there is only one client.\n\t\t */\n\t\tif (users[userid].q.id != 0) {\n\t\t\tif ((users[userid].outpacket.len > 0 && !didsend) ||\n\t\t\t    (upstream_ok && !lastfrag && !didsend) ||\n\t\t\t    (!upstream_ok && !didsend) ||\n\t\t\t    !users[userid].lazy) {\n\t\t\t\tdidsend = 1;\n\t\t\t\tif (send_chunk_or_dataless(dns_fd, userid, &users[userid].q) == 1)\n\t\t\t\t\t/* new packet from queue, send immediately */\n\t\t\t\t\tdidsend = 0;\n\t\t\t} else {\n\t\t\t\tmemcpy(&(users[userid].q_sendrealsoon),\n\t\t\t\t       &(users[userid].q),\n\t\t\t\t       sizeof(struct query));\n\t\t\t\tusers[userid].q_sendrealsoon_new = 1;\n\t\t\t\tusers[userid].q.id = 0;  /* used */\n\t\t\t\tdidsend = 1;\n\t\t\t}\n\t\t}\n\n\t\t/* Save new query and time info */\n\t\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\t\tusers[userid].last_pkt = time(NULL);\n\n\t\t/* If we still need to ack this upstream frag, do it to keep\n\t\t   upstream flowing.\n\t\t   - If we have new data waiting and not yet sent above,\n\t\t     send immediately.\n\t\t   - If this wasn't the last upstream fragment, then we expect\n\t\t     more, so ack immediately if we didn't already or are\n\t\t     in non-lazy mode.\n\t\t   - If this was the last fragment, and we didn't ack already\n\t\t     or are in non-lazy mode, send the ack after just a tiny\n\t\t     little while so that the TCP ack may have arrived from\n\t\t     our tun device.\n\t\t   - In all other cases, don't send anything now.\n\t\t*/\n\t\tif (users[userid].outpacket.len > 0 && !didsend)\n\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q);\n\t\telse if (!didsend || !users[userid].lazy) {\n\t\t\tif (upstream_ok && lastfrag) {\n\t\t\t\tmemcpy(&(users[userid].q_sendrealsoon),\n\t\t\t\t       &(users[userid].q),\n\t\t\t\t       sizeof(struct query));\n\t\t\t\tusers[userid].q_sendrealsoon_new = 1;\n\t\t\t\tusers[userid].q.id = 0;  /* used */\n\t\t\t} else {\n\t\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q);\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic void\nhandle_ns_request(int dns_fd, struct query *q, int topdomain_offset)\n/* Mostly identical to handle_a_request() below */\n{\n\tchar buf[64*1024];\n\tint len;\n\t/* Use possibly dynamic top domain in reply */\n\tchar *resp_domain = q->name + topdomain_offset;\n\n\tif (ns_ip != INADDR_ANY) {\n\t\t/* If ns_ip set, overwrite destination addr with it.\n\t\t * Destination addr will be sent as additional record (A, IN) */\n\t\tstruct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;\n\t\taddr->sin_family = AF_INET;\n\t\tmemcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));\n\t\tq->dest_len = sizeof(*addr);\n\t}\n\n\tlen = dns_encode_ns_response(buf, sizeof(buf), q, resp_domain);\n\tif (len < 1) {\n\t\twarnx(\"dns_encode_ns_response doesn't fit\");\n\t\treturn;\n\t}\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: client %s, type %d, name %s, %d bytes NS reply\\n\",\n\t\t\tformat_addr(&q->from, q->fromlen), q->type, q->name, len);\n\t}\n\tif (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {\n\t\twarn(\"ns reply send error\");\n\t}\n}\n\nstatic void\nhandle_a_request(int dns_fd, struct query *q, int fakeip)\n/* Mostly identical to handle_ns_request() above */\n{\n\tchar buf[64*1024];\n\tint len;\n\n\tif (fakeip) {\n\t\tin_addr_t ip = inet_addr(\"127.0.0.1\");\n\t\tstruct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;\n\t\taddr->sin_family = AF_INET;\n\t\tmemcpy(&addr->sin_addr, &ip, sizeof(ip));\n\t\tq->dest_len = sizeof(*addr);\n\t} else if (ns_ip != INADDR_ANY) {\n\t\t/* If ns_ip set, overwrite destination addr with it.\n\t\t * Destination addr will be sent as additional record (A, IN) */\n\t\tstruct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;\n\t\taddr->sin_family = AF_INET;\n\t\tmemcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip));\n\t\tq->dest_len = sizeof(*addr);\n\t}\n\n\t/* Give up if no IPv4 address known (when A request received over IPv6\n\t * and destination was not overwritten above) */\n\tif (q->destination.ss_family != AF_INET)\n\t\treturn;\n\n\tlen = dns_encode_a_response(buf, sizeof(buf), q);\n\tif (len < 1) {\n\t\twarnx(\"dns_encode_a_response doesn't fit\");\n\t\treturn;\n\t}\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: client %s, type %d, name %s, %d bytes A reply\\n\",\n\t\t\tformat_addr(&q->from, q->fromlen), q->type, q->name, len);\n\t}\n\tif (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {\n\t\twarn(\"a reply send error\");\n\t}\n}\n\nstatic void\nhandle_underscore_request(int dns_fd, struct query *q, const char *topdomain)\n{\n\tchar buf[64*1024];\n\tint len;\n\n\tlen = dns_encode_nxdomain(buf, sizeof(buf), q, topdomain);\n\tif (len < 1) {\n\t\twarnx(\"dns_encode_nxdomain doesn't fit\");\n\t\treturn;\n\t}\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: client %s, type %d, name %s, %d bytes NXDOMAIN reply\\n\",\n\t\t\tformat_addr(&q->from, q->fromlen), q->type, q->name, len);\n\t}\n\tif (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {\n\t\twarn(\"nxdomain reply send error\");\n\t}\n}\n\nstatic void\nforward_query(int bind_fd, struct query *q)\n{\n\tchar buf[64*1024];\n\tint len;\n\tstruct fw_query fwq;\n\tstruct sockaddr_in *myaddr;\n\tin_addr_t newaddr;\n\n\tlen = dns_encode(buf, sizeof(buf), q, QR_QUERY, q->name, strlen(q->name));\n\tif (len < 1) {\n\t\twarnx(\"dns_encode doesn't fit\");\n\t\treturn;\n\t}\n\n\t/* Store sockaddr for q->id */\n\tmemcpy(&(fwq.addr), &(q->from), q->fromlen);\n\tfwq.addrlen = q->fromlen;\n\tfwq.id = q->id;\n\tfw_query_put(&fwq);\n\n\tnewaddr = inet_addr(\"127.0.0.1\");\n\tmyaddr = (struct sockaddr_in *) &(q->from);\n\tmemcpy(&(myaddr->sin_addr), &newaddr, sizeof(in_addr_t));\n\tmyaddr->sin_port = htons(bind_port);\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: NS reply \\n\");\n\t}\n\n\tif (sendto(bind_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {\n\t\twarn(\"forward query error\");\n\t}\n}\n\nstatic int\ntunnel_bind(int bind_fd, struct dnsfd *dns_fds)\n{\n\tchar packet[64*1024];\n\tstruct sockaddr_storage from;\n\tsocklen_t fromlen;\n\tstruct fw_query *query;\n\tunsigned short id;\n\tint dns_fd;\n\tint r;\n\n\tfromlen = sizeof(struct sockaddr);\n\tr = recvfrom(bind_fd, packet, sizeof(packet), 0,\n\t\t(struct sockaddr*)&from, &fromlen);\n\n\tif (r <= 0)\n\t\treturn 0;\n\n\tid = dns_get_id(packet, r);\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"RX: Got response on query %u from DNS\\n\", (id & 0xFFFF));\n\t}\n\n\t/* Get sockaddr from id */\n\tfw_query_get(id, &query);\n\tif (!query) {\n\t\tif (debug >= 2) {\n\t\t\tfprintf(stderr, \"Lost sender of id %u, dropping reply\\n\", (id & 0xFFFF));\n\t\t}\n\t\treturn 0;\n\t}\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: client %s id %u, %d bytes\\n\",\n\t\t\tformat_addr(&query->addr, query->addrlen), (id & 0xffff), r);\n\t}\n\n\tdns_fd = get_dns_fd(dns_fds, &query->addr);\n\tif (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr),\n\t\tquery->addrlen) <= 0) {\n\t\twarn(\"forward reply error\");\n\t}\n\n\treturn 0;\n}\n\nstatic int\ntunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd)\n{\n\tstruct query q;\n\tint read;\n\tint domain_len;\n\n\tif ((read = read_dns(dns_fd, dns_fds, tun_fd, &q)) <= 0)\n\t\treturn 0;\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"RX: client %s, type %d, name %s\\n\",\n\t\t\tformat_addr(&q.from, q.fromlen), q.type, q.name);\n\t}\n\n\tdomain_len = query_datalen(q.name, topdomain);\n\tif (domain_len >= 0) {\n\t\t/* This is a query we can handle */\n\n\t\t/* Handle A-type query for ns.topdomain, possibly caused\n\t\t   by our proper response to any NS request */\n\t\tif (domain_len == 3 && q.type == T_A &&\n\t\t    (q.name[0] == 'n' || q.name[0] == 'N') &&\n\t\t    (q.name[1] == 's' || q.name[1] == 'S') &&\n\t\t     q.name[2] == '.') {\n\t\t\thandle_a_request(dns_fd, &q, 0);\n\t\t\treturn 0;\n\t\t}\n\n\t\t/* Handle A-type query for www.topdomain, for anyone that's\n\t\t   poking around */\n\t\tif (domain_len == 4 && q.type == T_A &&\n\t\t    (q.name[0] == 'w' || q.name[0] == 'W') &&\n\t\t    (q.name[1] == 'w' || q.name[1] == 'W') &&\n\t\t    (q.name[2] == 'w' || q.name[2] == 'W') &&\n\t\t     q.name[3] == '.') {\n\t\t\thandle_a_request(dns_fd, &q, 1);\n\t\t\treturn 0;\n\t\t}\n\n\t\t/* Handle A-type query for _.***.topdomain. It happens when\n\t\t *\n\t\t * https://datatracker.ietf.org/doc/html/rfc7816 (qname minimisation)\n\t\t * https://github.com/isc-projects/bind9/commit/ae52c2117eba9fa0778125f4e10834d673ab811b\n\t\t * */\n\t\tif (q.type == T_A &&\n\t\t    (q.name[0] == '_') &&\n\t\t     q.name[1] == '.') {\n\t\t\thandle_underscore_request(dns_fd, &q, topdomain);\n\t\t\treturn 0;\n\t\t}\n\n\t\tswitch (q.type) {\n\t\tcase T_NULL:\n\t\tcase T_PRIVATE:\n\t\tcase T_CNAME:\n\t\tcase T_A:\n\t\tcase T_MX:\n\t\tcase T_SRV:\n\t\tcase T_TXT:\n\t\t\t/* encoding is \"transparent\" here */\n\t\t\thandle_null_request(tun_fd, dns_fd, dns_fds, &q, domain_len);\n\t\t\tbreak;\n\t\tcase T_NS:\n\t\t\thandle_ns_request(dns_fd, &q, domain_len);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\t/* Forward query to other port ? */\n\t\tif (bind_fd) {\n\t\t\tforward_query(bind_fd, &q);\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic int\ntunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time)\n{\n\tstruct timeval tv;\n\tfd_set fds;\n\tint i;\n\tint userid;\n\ttime_t last_action = time(NULL);\n\n\twhile (running) {\n\t\tint maxfd;\n\t\ttv.tv_sec = 10;\t\t\t/* doesn't really matter */\n\t\ttv.tv_usec = 0;\n\n\t\t/* Adjust timeout if there is anything to send realsoon.\n\t\t   Clients won't be sending new data until we send our ack,\n\t\t   so don't keep them waiting long. This only triggers at\n\t\t   final upstream fragments, which is about once per eight\n\t\t   requests during heavy upstream traffic.\n\t\t   20msec: ~8 packs every 1/50sec = ~400 DNSreq/sec,\n\t\t   or ~1200bytes every 1/50sec = ~0.5 Mbit/sec upstream */\n\t\tfor (userid = 0; userid < created_users; userid++) {\n\t\t\tif (users[userid].active && !users[userid].disabled &&\n\t\t\t    users[userid].last_pkt + 60 > time(NULL)) {\n\t\t\t\tusers[userid].q_sendrealsoon_new = 0;\n\t\t\t\tif (users[userid].q_sendrealsoon.id != 0) {\n\t\t\t\t\ttv.tv_sec = 0;\n\t\t\t\t\ttv.tv_usec = 20000;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tFD_ZERO(&fds);\n\t\tmaxfd = 0;\n\n\t\tif (dns_fds->v4fd >= 0) {\n\t\t\tFD_SET(dns_fds->v4fd, &fds);\n\t\t\tmaxfd = MAX(dns_fds->v4fd, maxfd);\n\t\t}\n\t\tif (dns_fds->v6fd >= 0) {\n\t\t\tFD_SET(dns_fds->v6fd, &fds);\n\t\t\tmaxfd = MAX(dns_fds->v6fd, maxfd);\n\t\t}\n\n\t\tif (bind_fd) {\n\t\t\t/* wait for replies from real DNS */\n\t\t\tFD_SET(bind_fd, &fds);\n\t\t\tmaxfd = MAX(bind_fd, maxfd);\n\t\t}\n\n\t\t/* Don't read from tun if no users can accept data anyway;\n\t\t   tun queue/TCP buffers are larger than our outpacket-queues */\n\t\tif (!all_users_waiting_to_send()) {\n\t\t\tFD_SET(tun_fd, &fds);\n\t\t\tmaxfd = MAX(tun_fd, maxfd);\n\t\t}\n\n\t\ti = select(maxfd + 1, &fds, NULL, NULL, &tv);\n\n\t\tif (i < 0) {\n\t\t\tif (running)\n\t\t\t\twarn(\"select\");\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (i == 0) {\n\t\t\tif (max_idle_time) {\n\t\t\t\t/* only trigger the check if that's worth (ie, no need to loop over if there\n\t\t\t\tis something to send */\n\t\t\t\tif (last_action + max_idle_time < time(NULL)) {\n\t\t\t\t\tfor (userid = 0; userid < created_users; userid++) {\n\t\t\t\t\t\tlast_action = (users[userid].last_pkt > last_action) ?\n\t\t\t\t\t\t\tusers[userid].last_pkt : last_action;\n\t\t\t\t\t}\n\t\t\t\t\tif (last_action + max_idle_time < time(NULL)) {\n\t\t\t\t\t\tfprintf(stderr, \"Idling since too long, shutting down...\\n\");\n\t\t\t\t\t\trunning = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (FD_ISSET(tun_fd, &fds)) {\n\t\t\t\ttunnel_tun(tun_fd, dns_fds);\n\t\t\t}\n\t\t\tif (dns_fds->v4fd >= 0 && FD_ISSET(dns_fds->v4fd, &fds)) {\n\t\t\t\ttunnel_dns(tun_fd, dns_fds->v4fd, dns_fds, bind_fd);\n\t\t\t}\n\t\t\tif (dns_fds->v6fd >= 0 && FD_ISSET(dns_fds->v6fd, &fds)) {\n\t\t\t\ttunnel_dns(tun_fd, dns_fds->v6fd, dns_fds, bind_fd);\n\t\t\t}\n\t\t\tif (FD_ISSET(bind_fd, &fds)) {\n\t\t\t\ttunnel_bind(bind_fd, dns_fds);\n\t\t\t}\n\t\t}\n\n\t\t/* Send realsoon's if tun or dns didn't already */\n\t\tfor (userid = 0; userid < created_users; userid++)\n\t\t\tif (users[userid].active && !users[userid].disabled &&\n\t\t\t    users[userid].last_pkt + 60 > time(NULL) &&\n\t\t\t    users[userid].q_sendrealsoon.id != 0 &&\n\t\t\t    users[userid].conn == CONN_DNS_NULL &&\n\t\t\t    !users[userid].q_sendrealsoon_new) {\n\t\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[userid].q_sendrealsoon.from);\n\t\t\t\tsend_chunk_or_dataless(dns_fd, userid, &users[userid].q_sendrealsoon);\n\t\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic void\nhandle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid)\n{\n\tunsigned long outlen;\n\tchar out[64*1024];\n\tint touser;\n\tint ret;\n\n\toutlen = sizeof(out);\n\tret = uncompress((uint8_t*)out, &outlen,\n\t\t   (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);\n\n\tif (ret == Z_OK) {\n\t\tstruct ip *hdr;\n\n\t\thdr = (struct ip*) (out + 4);\n\t\ttouser = find_user_by_ip(hdr->ip_dst.s_addr);\n\n\t\tif (touser == -1) {\n\t\t\t/* send the uncompressed packet to tun device */\n\t\t\twrite_tun(tun_fd, out, outlen);\n\t\t} else {\n\t\t\t/* send the compressed(!) packet to other client */\n\t\t\tif (users[touser].conn == CONN_DNS_NULL) {\n\t\t\t\tif (users[touser].outpacket.len == 0) {\n\t\t\t\t\tstart_new_outpacket(touser,\n\t\t\t\t\t\tusers[userid].inpacket.data,\n\t\t\t\t\t\tusers[userid].inpacket.len);\n\n\t\t\t\t\t/* Start sending immediately if query is waiting */\n\t\t\t\t\tif (users[touser].q_sendrealsoon.id != 0) {\n\t\t\t\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[touser].q_sendrealsoon.from);\n\t\t\t\t\t\tsend_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon);\n\t\t\t\t\t} else if (users[touser].q.id != 0) {\n\t\t\t\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[touser].q.from);\n\t\t\t\t\t\tsend_chunk_or_dataless(dns_fd, touser, &users[touser].q);\n\t\t\t\t\t}\n#ifdef OUTPACKETQ_LEN\n\t\t\t\t} else {\n\t\t\t\t\tsave_to_outpacketq(touser,\n\t\t\t\t\t\tusers[userid].inpacket.data,\n\t\t\t\t\t\tusers[userid].inpacket.len);\n#endif\n\t\t\t\t}\n\t\t\t} else{ /* CONN_RAW_UDP */\n\t\t\t\tint dns_fd = get_dns_fd(dns_fds, &users[touser].q.from);\n\t\t\t\tsend_raw(dns_fd, users[userid].inpacket.data,\n\t\t\t\t\t users[userid].inpacket.len, touser,\n\t\t\t\t\t RAW_HDR_CMD_DATA, &users[touser].q);\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif (debug >= 1)\n\t\t\tfprintf(stderr, \"Discarded data, uncompress() result: %d\\n\", ret);\n\t}\n\n\t/* This packet is done */\n\tusers[userid].inpacket.len = 0;\n\tusers[userid].inpacket.offset = 0;\n}\n\nstatic void\nhandle_raw_login(char *packet, int len, struct query *q, int fd, int userid)\n{\n\tchar myhash[16];\n\n\tif (len < 16) return;\n\n\t/* can't use check_authenticated_user_and_ip() since IP address will be different,\n\t   so duplicate here except IP address */\n\tif (userid < 0 || userid >= created_users) return;\n\tif (!users[userid].active || users[userid].disabled) return;\n\tif (!users[userid].authenticated) return;\n\tif (users[userid].last_pkt + 60 < time(NULL)) return;\n\n\tif (debug >= 1) {\n\t\tfprintf(stderr, \"IN   login raw, len %d, from user %d\\n\",\n\t\t\tlen, userid);\n\t}\n\n\t/* User sends hash of seed + 1 */\n\tlogin_calculate(myhash, 16, password, users[userid].seed + 1);\n\tif (memcmp(packet, myhash, 16) == 0) {\n\t\t/* Update query and time info for user */\n\t\tusers[userid].last_pkt = time(NULL);\n\t\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\n\t\t/* Store remote IP number */\n\t\tmemcpy(&(users[userid].host), &(q->from), q->fromlen);\n\t\tusers[userid].hostlen = q->fromlen;\n\n\t\t/* Correct hash, reply with hash of seed - 1 */\n\t\tuser_set_conn_type(userid, CONN_RAW_UDP);\n\t\tlogin_calculate(myhash, 16, password, users[userid].seed - 1);\n\t\tsend_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q);\n\n\t\tusers[userid].authenticated_raw = 1;\n\t}\n}\n\nstatic void\nhandle_raw_data(char *packet, int len, struct query *q, struct dnsfd *dns_fds, int tun_fd, int userid)\n{\n\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\treturn;\n\t}\n\tif (!users[userid].authenticated_raw) return;\n\n\t/* Update query and time info for user */\n\tusers[userid].last_pkt = time(NULL);\n\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\n\t/* copy to packet buffer, update length */\n\tusers[userid].inpacket.offset = 0;\n\tmemcpy(users[userid].inpacket.data, packet, len);\n\tusers[userid].inpacket.len = len;\n\n\tif (debug >= 1) {\n\t\tfprintf(stderr, \"IN   pkt raw, total %d, from user %d\\n\",\n\t\t\tusers[userid].inpacket.len, userid);\n\t}\n\n\thandle_full_packet(tun_fd, dns_fds, userid);\n}\n\nstatic void\nhandle_raw_ping(struct query *q, int dns_fd, int userid)\n{\n\tif (check_authenticated_user_and_ip(userid, q) != 0) {\n\t\treturn;\n\t}\n\tif (!users[userid].authenticated_raw) return;\n\n\t/* Update query and time info for user */\n\tusers[userid].last_pkt = time(NULL);\n\tmemcpy(&(users[userid].q), q, sizeof(struct query));\n\n\tif (debug >= 1) {\n\t\tfprintf(stderr, \"IN   ping raw, from user %d\\n\", userid);\n\t}\n\n\t/* Send ping reply */\n\tsend_raw(dns_fd, NULL, 0, userid, RAW_HDR_CMD_PING, q);\n}\n\nstatic int\nraw_decode(char *packet, int len, struct query *q, int dns_fd, struct dnsfd *dns_fds, int tun_fd)\n{\n\tint raw_user;\n\n\t/* minimum length */\n\tif (len < RAW_HDR_LEN) return 0;\n\t/* should start with header */\n\tif (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0;\n\n\traw_user = RAW_HDR_GET_USR(packet);\n\tswitch (RAW_HDR_GET_CMD(packet)) {\n\tcase RAW_HDR_CMD_LOGIN:\n\t\t/* Login challenge */\n\t\thandle_raw_login(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, raw_user);\n\t\tbreak;\n\tcase RAW_HDR_CMD_DATA:\n\t\t/* Data packet */\n\t\thandle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fds, tun_fd, raw_user);\n\t\tbreak;\n\tcase RAW_HDR_CMD_PING:\n\t\t/* Keepalive packet */\n\t\thandle_raw_ping(q, dns_fd, raw_user);\n\t\tbreak;\n\tdefault:\n\t\twarnx(\"Unhandled raw command %02X from user %d\", RAW_HDR_GET_CMD(packet), raw_user);\n\t\tbreak;\n\t}\n\treturn 1;\n}\n\nstatic int\nread_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q)\n/* FIXME: dns_fds and tun_fd are because of raw_decode() below */\n{\n\tstruct sockaddr_storage from;\n\tsocklen_t addrlen;\n\tchar packet[64*1024];\n\tint r;\n#ifndef WINDOWS32\n\tchar control[CMSG_SPACE(sizeof (struct in6_pktinfo))];\n\tstruct msghdr msg;\n\tstruct iovec iov;\n\tstruct cmsghdr *cmsg;\n\n\taddrlen = sizeof(struct sockaddr_storage);\n\tiov.iov_base = packet;\n\tiov.iov_len = sizeof(packet);\n\n\tmsg.msg_name = (caddr_t) &from;\n\tmsg.msg_namelen = (unsigned) addrlen;\n\tmsg.msg_iov = &iov;\n\tmsg.msg_iovlen = 1;\n\tmsg.msg_control = control;\n\tmsg.msg_controllen = sizeof(control);\n\tmsg.msg_flags = 0;\n\n\tr = recvmsg(fd, &msg, 0);\n#else\n\taddrlen = sizeof(struct sockaddr_storage);\n\tr = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);\n#endif /* !WINDOWS32 */\n\n\tif (r > 0) {\n\t\tmemcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);\n\t\tq->fromlen = addrlen;\n\n\t\t/* TODO do not handle raw packets here! */\n\t\tif (raw_decode(packet, r, q, fd, dns_fds, tun_fd)) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (dns_decode(NULL, 0, q, QR_QUERY, packet, r) <= 0) {\n\t\t\treturn 0;\n\t\t}\n\n#ifndef WINDOWS32\n\t\tmemset(&q->destination, 0, sizeof(struct sockaddr_storage));\n\t\t/* Read destination IP address */\n\t\tfor (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;\n\t\t\tcmsg = CMSG_NXTHDR(&msg, cmsg)) {\n\n\t\t\tif (cmsg->cmsg_level == IPPROTO_IP &&\n\t\t\t\tcmsg->cmsg_type == DSTADDR_SOCKOPT) {\n\n\t\t\t\tstruct sockaddr_in *addr = (struct sockaddr_in *) &q->destination;\n\t\t\t\taddr->sin_family = AF_INET;\n\t\t\t\taddr->sin_addr = *dstaddr(cmsg);\n\t\t\t\tq->dest_len = sizeof(*addr);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (cmsg->cmsg_level == IPPROTO_IPV6 &&\n\t\t\t\tcmsg->cmsg_type == IPV6_PKTINFO) {\n\n\t\t\t\tstruct in6_pktinfo *pktinfo;\n\t\t\t\tstruct sockaddr_in6 *addr = (struct sockaddr_in6 *) &q->destination;\n\t\t\t\tpktinfo = (struct in6_pktinfo *) CMSG_DATA(cmsg);\n\t\t\t\taddr->sin6_family = AF_INET6;\n\t\t\t\tmemcpy(&addr->sin6_addr, &pktinfo->ipi6_addr, sizeof(struct in6_addr));\n\t\t\t\tq->dest_len = sizeof(*addr);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n#endif\n\n\t\treturn strlen(q->name);\n\t} else if (r < 0) {\n\t\t/* Error */\n\t\twarn(\"read dns\");\n\t}\n\n\treturn 0;\n}\n\nstatic size_t\nwrite_dns_nameenc(char *buf, size_t buflen, const char *data, int datalen, char downenc)\n/* Returns #bytes of data that were encoded */\n{\n\tstatic int td1 = 0;\n\tstatic int td2 = 0;\n\tsize_t space;\n\tchar *b;\n\n\t/* Make a rotating topdomain to prevent filtering */\n\ttd1+=3;\n\ttd2+=7;\n\tif (td1>=26) td1-=26;\n\tif (td2>=25) td2-=25;\n\n\t/* encode data,datalen to CNAME/MX answer\n\t   (adapted from build_hostname() in encoding.c)\n\t */\n\n\tspace = MIN(0xFF, buflen) - 4 - 2;\n\t/* -1 encoding type, -3 \".xy\", -2 for safety */\n\n\tmemset(buf, 0, buflen);\n\n\tif (downenc == 'S') {\n\t\tbuf[0] = 'i';\n\t\tif (!base64_ops.places_dots)\n\t\t\tspace -= (space / 57);\t/* space for dots */\n\t\tbase64_ops.encode(buf+1, &space, data, datalen);\n\t\tif (!base64_ops.places_dots)\n\t\t\tinline_dotify(buf, buflen);\n\t} else if (downenc == 'U') {\n\t\tbuf[0] = 'j';\n\t\tif (!base64u_ops.places_dots)\n\t\t\tspace -= (space / 57);\t/* space for dots */\n\t\tbase64u_ops.encode(buf+1, &space, data, datalen);\n\t\tif (!base64u_ops.places_dots)\n\t\t\tinline_dotify(buf, buflen);\n\t} else if (downenc == 'V') {\n\t\tbuf[0] = 'k';\n\t\tif (!base128_ops.places_dots)\n\t\t\tspace -= (space / 57);\t/* space for dots */\n\t\tbase128_ops.encode(buf+1, &space, data, datalen);\n\t\tif (!base128_ops.places_dots)\n\t\t\tinline_dotify(buf, buflen);\n\t} else {\n\t\tbuf[0] = 'h';\n\t\tif (!base32_ops.places_dots)\n\t\t\tspace -= (space / 57);\t/* space for dots */\n\t\tbase32_ops.encode(buf+1, &space, data, datalen);\n\t\tif (!base32_ops.places_dots)\n\t\t\tinline_dotify(buf, buflen);\n\t}\n\n\t/* Add dot (if it wasn't there already) and topdomain */\n\tb = buf;\n\tb += strlen(buf) - 1;\n\tif (*b != '.')\n\t\t*++b = '.';\n\tb++;\n\n\t*b = 'a' + td1;\n\tb++;\n\t*b = 'a' + td2;\n\tb++;\n\t*b = '\\0';\n\n\treturn space;\n}\n\nstatic void\nwrite_dns(int fd, struct query *q, const char *data, int datalen, char downenc)\n{\n\tchar buf[64*1024];\n\tint len = 0;\n\n\tif (q->type == T_CNAME || q->type == T_A) {\n\t\tchar cnamebuf[1024];\t\t/* max 255 */\n\n\t\twrite_dns_nameenc(cnamebuf, sizeof(cnamebuf),\n\t\t\t\t  data, datalen, downenc);\n\n\t\tlen = dns_encode(buf, sizeof(buf), q, QR_ANSWER, cnamebuf,\n\t\t\t\t sizeof(cnamebuf));\n\t} else if (q->type == T_MX || q->type == T_SRV) {\n\t\tchar mxbuf[64*1024];\n\t\tchar *b = mxbuf;\n\t\tint offset = 0;\n\t\tint res;\n\n\t\twhile (1) {\n\t\t\tres = write_dns_nameenc(b, sizeof(mxbuf) - (b - mxbuf),\n\t\t\t\t\t\tdata + offset,\n\t\t\t\t\t\tdatalen - offset, downenc);\n\t\t\tif (res < 1) {\n\t\t\t\t/* nothing encoded */\n\t\t\t\tb++;\t/* for final \\0 */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tb = b + strlen(b) + 1;\n\n\t\t\toffset += res;\n\t\t\tif (offset >= datalen)\n\t\t\t\tbreak;\n\t\t}\n\n\t\t/* Add final \\0 */\n\t\t*b = '\\0';\n\n\t\tlen = dns_encode(buf, sizeof(buf), q, QR_ANSWER, mxbuf,\n\t\t\t\t sizeof(mxbuf));\n\t} else if (q->type == T_TXT) {\n\t\t/* TXT with base32 */\n\t\tchar txtbuf[64*1024];\n\t\tsize_t space = sizeof(txtbuf) - 1;;\n\n\t\tmemset(txtbuf, 0, sizeof(txtbuf));\n\n\t\tif (downenc == 'S') {\n\t\t\ttxtbuf[0] = 's';\t/* plain base64(Sixty-four) */\n\t\t\tlen = base64_ops.encode(txtbuf+1, &space, data, datalen);\n\t\t}\n\t\telse if (downenc == 'U') {\n\t\t\ttxtbuf[0] = 'u';\t/* Base64 with Underscore */\n\t\t\tlen = base64u_ops.encode(txtbuf+1, &space, data, datalen);\n\t\t}\n\t\telse if (downenc == 'V') {\n\t\t\ttxtbuf[0] = 'v';\t/* Base128 */\n\t\t\tlen = base128_ops.encode(txtbuf+1, &space, data, datalen);\n\t\t}\n\t\telse if (downenc == 'R') {\n\t\t\ttxtbuf[0] = 'r';\t/* Raw binary data */\n\t\t\tlen = MIN(datalen, sizeof(txtbuf) - 1);\n\t\t\tmemcpy(txtbuf + 1, data, len);\n\t\t} else {\n\t\t\ttxtbuf[0] = 't';\t/* plain base32(Thirty-two) */\n\t\t\tlen = base32_ops.encode(txtbuf+1, &space, data, datalen);\n\t\t}\n\t\tlen = dns_encode(buf, sizeof(buf), q, QR_ANSWER, txtbuf, len+1);\n\t} else {\n\t\t/* Normal NULL-record encode */\n\t\tlen = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);\n\t}\n\n\tif (len < 1) {\n\t\twarnx(\"dns_encode doesn't fit\");\n\t\treturn;\n\t}\n\n\tif (debug >= 2) {\n\t\tfprintf(stderr, \"TX: client %s, type %d, name %s, %d bytes data\\n\",\n\t\t\tformat_addr(&q->from, q->fromlen), q->type, q->name, datalen);\n\t}\n\n\tsendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);\n}\n\nstatic void print_usage(FILE *stream)\n{\n\tfprintf(stream,\n\t\t\"Usage: %s [-46cDfsv] [-u user] [-t chrootdir] [-d device] [-m mtu]\\n\"\n\t\t\"               [-z context] [-l ipv4 listen address] [-L ipv6 listen address]\\n\"\n\t\t\"               [-p port] [-n auto|external_ip] [-b dnsport] [-P password]\\n\"\n\t\t\"               [-F pidfile] [-i max idle time] tunnel_ip[/netmask] topdomain\\n\",\n\t\t__progname);\n}\n\nstatic void usage(void)\n{\n\tprint_usage(stderr);\n\texit(2);\n}\n\nstatic void help(FILE *stream)\n{\n\tfprintf(stream, \"iodine IP over DNS tunneling server\\n\\n\");\n\tprint_usage(stream);\n\tfprintf(stream,\n\t\t\"\\nAvailable options:\\n\"\n\t\t\"  -v to print version info and exit\\n\"\n\t\t\"  -h to print this help and exit\\n\"\n\t\t\"  -4 to listen only on IPv4\\n\"\n\t\t\"  -6 to listen only on IPv6\\n\"\n\t\t\"  -c to disable check of client IP/port on each request\\n\"\n\t\t\"  -s to skip creating and configuring the tun device,\\n\"\n\t\t\"     which then has to be created manually\\n\"\n\t\t\"  -f to keep running in foreground\\n\"\n\t\t\"  -D to increase debug level\\n\"\n\t\t\"     (using -DD in UTF-8 terminal: \\\"LC_ALL=C luit iodined -DD ...\\\")\\n\"\n\t\t\"  -u name to drop privileges and run as user 'name'\\n\"\n\t\t\"  -t dir to chroot to directory dir\\n\"\n\t\t\"  -d device to set tunnel device name\\n\"\n\t\t\"  -m mtu to set tunnel device mtu\\n\"\n\t\t\"  -z context to apply SELinux context after initialization\\n\"\n\t\t\"  -l IPv4 address to listen on for incoming dns traffic \"\n\t\t\"(default 0.0.0.0)\\n\"\n\t\t\"     (Use 'external' to listen only on external IP, looked up via a service)\\n\"\n\t\t\"  -L IPv6 address to listen on for incoming dns traffic \"\n\t\t\"(default ::)\\n\"\n\t\t\"  -p port to listen on for incoming dns traffic (default 53)\\n\"\n\t\t\"  -n ip to respond with to NS queries\\n\"\n\t\t\"     (Use 'auto' to use the external IP, looked up via a service)\\n\"\n\t\t\"  -b port to forward normal DNS queries to (on localhost)\\n\"\n\t\t\"  -P password used for authentication (max 32 chars will be used)\\n\"\n\t\t\"  -F pidfile to write pid to a file\\n\"\n\t\t\"  -i maximum idle time before shutting down\\n\\n\"\n\t\t\"tunnel_ip is the IP number of the local tunnel interface.\\n\"\n\t\t\"   /netmask sets the size of the tunnel network.\\n\"\n\t\t\"topdomain is the FQDN that is delegated to this server.\\n\"\n\t\t\"   Initial wildcard is allowed (example: *.tun.com)\\n\");\n\n\texit(0);\n}\n\nstatic void version(void)\n{\n\tfprintf(stderr,\n\t\t\"iodine IP over DNS tunneling server\\n\"\n\t\t\"Git version: %s\\n\", GITREVISION);\n\n\texit(0);\n}\n\nstatic void prepare_dns_fd(int fd)\n{\n#ifndef WINDOWS32\n\tint flag = 1;\n\n\t/* To get destination address from each UDP datagram, see read_dns() */\n\tsetsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));\n#ifdef IPV6_RECVPKTINFO\n\tsetsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void*) &flag, sizeof(flag));\n#endif\n#ifdef IPV6_PKTINFO\n\tsetsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, (const void*) &flag, sizeof(flag));\n#endif\n\n#endif\n}\n\nint\nmain(int argc, char **argv)\n{\n\tchar *listen_ip4;\n\tchar *listen_ip6;\n\tchar *errormsg;\n#ifndef WINDOWS32\n\tstruct passwd *pw;\n#endif\n\tint foreground;\n\tchar *username;\n\tchar *newroot;\n\tchar *context;\n\tchar *device;\n\tchar *pidfile;\n\tint addrfamily;\n\tstruct dnsfd dns_fds;\n\tint tun_fd;\n\n\t/* settings for forwarding normal DNS to\n\t * local real DNS server */\n\tint bind_fd;\n\tint bind_enable;\n\n\tint choice;\n\tint port;\n\tint mtu;\n\tint skipipconfig;\n\tchar *netsize;\n\tint ns_get_externalip;\n\tint retval;\n\tint max_idle_time = 0;\n\tstruct sockaddr_storage dns4addr;\n\tint dns4addr_len;\n\tstruct sockaddr_storage dns6addr;\n\tint dns6addr_len;\n#ifdef HAVE_SYSTEMD\n\tint nb_fds;\n#endif\n\n#ifndef WINDOWS32\n\tpw = NULL;\n#endif\n\terrormsg = NULL;\n\tusername = NULL;\n\tnewroot = NULL;\n\tcontext = NULL;\n\tdevice = NULL;\n\tforeground = 0;\n\tbind_enable = 0;\n\tbind_fd = 0;\n\tmtu = 1130;\t/* Very many relays give fragsize 1150 or slightly\n\t\t\t   higher for NULL; tun/zlib adds ~17 bytes. */\n\tlisten_ip4 = NULL;\n\tlisten_ip6 = NULL;\n\tport = 53;\n\tns_ip = INADDR_ANY;\n\tns_get_externalip = 0;\n\taddrfamily = AF_UNSPEC;\n\tcheck_ip = 1;\n\tskipipconfig = 0;\n\tdebug = 0;\n\tnetmask = 27;\n\tpidfile = NULL;\n\n\tretval = 0;\n\n#ifdef WINDOWS32\n\tWSAStartup(req_version, &wsa_data);\n#endif\n\n#if !defined(BSD) && !defined(__GLIBC__)\n\t__progname = strrchr(argv[0], '/');\n\tif (__progname == NULL)\n\t\t__progname = argv[0];\n\telse\n\t\t__progname++;\n#endif\n\n\tsrand(time(NULL));\n\tfw_query_init();\n\n\twhile ((choice = getopt(argc, argv, \"46vcsfhDu:t:d:m:l:L:p:n:b:P:z:F:i:\")) != -1) {\n\t\tswitch(choice) {\n\t\tcase '4':\n\t\t\taddrfamily = AF_INET;\n\t\t\tbreak;\n\t\tcase '6':\n\t\t\taddrfamily = AF_INET6;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tversion();\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tcheck_ip = 0;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tskipipconfig = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tforeground = 1;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\t\thelp(stdout);\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tdebug++;\n\t\t\tbreak;\n\t\tcase 'u':\n\t\t\tusername = optarg;\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\tnewroot = optarg;\n\t\t\tbreak;\n\t\tcase 'd':\n\t\t\tdevice = optarg;\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tmtu = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tlisten_ip4 = optarg;\n\t\t\tbreak;\n\t\tcase 'L':\n\t\t\tlisten_ip6 = optarg;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tport = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tif (optarg && strcmp(\"auto\", optarg) == 0) {\n\t\t\t\tns_get_externalip = 1;\n\t\t\t} else {\n\t\t\t\tns_ip = inet_addr(optarg);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tbind_enable = 1;\n\t\t\tbind_port = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tpidfile = optarg;\n\t\t\tbreak;\n\t\tcase 'i':\n\t\t\tmax_idle_time = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tstrncpy(password, optarg, sizeof(password));\n\t\t\tpassword[sizeof(password)-1] = 0;\n\n\t\t\t/* XXX: find better way of cleaning up ps(1) */\n\t\t\tmemset(optarg, 0, strlen(optarg));\n\t\t\tbreak;\n\t\tcase 'z':\n\t\t\tcontext = optarg;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\targc -= optind;\n\targv += optind;\n\n\tcheck_superuser();\n\n\tif (argc != 2)\n\t\tusage();\n\n\tnetsize = strchr(argv[0], '/');\n\tif (netsize) {\n\t\t*netsize = 0;\n\t\tnetsize++;\n\t\tnetmask = atoi(netsize);\n\t}\n\n\tmy_ip = inet_addr(argv[0]);\n\n\tif (my_ip == INADDR_NONE) {\n\t\twarnx(\"Bad IP address to use inside tunnel.\");\n\t\tusage();\n\t}\n\n\ttopdomain = strdup(argv[1]);\n\tif (check_topdomain(topdomain, 1, &errormsg)) {\n\t\twarnx(\"Invalid topdomain: %s\", errormsg);\n\t\tusage();\n\t\t/* NOTREACHED */\n\t}\n\n\tif (username != NULL) {\n#ifndef WINDOWS32\n\t\tif ((pw = getpwnam(username)) == NULL) {\n\t\t\twarnx(\"User %s does not exist!\", username);\n\t\t\tusage();\n\t\t}\n#endif\n\t}\n\n\tif (mtu <= 0) {\n\t\twarnx(\"Bad MTU given.\");\n\t\tusage();\n\t}\n\n\tif (port < 1 || port > 65535) {\n\t\twarnx(\"Bad port number given.\");\n\t\tusage();\n\t}\n\n\tif (port != 53) {\n\t\tfprintf(stderr, \"ALERT! Other dns servers expect you to run on port 53.\\n\");\n\t\tfprintf(stderr, \"You must manually forward port 53 to port %d for things to work.\\n\", port);\n\t}\n\n\tif (debug) {\n\t\tfprintf(stderr, \"Debug level %d enabled, will stay in foreground.\\n\", debug);\n\t\tfprintf(stderr, \"Add more -D switches to set higher debug level.\\n\");\n\t\tforeground = 1;\n\t}\n\tif (addrfamily == AF_UNSPEC || addrfamily == AF_INET) {\n\t\tif (listen_ip4 && strcmp(\"external\", listen_ip4) == 0) {\n\t\t\tstruct in_addr extip;\n\t\t\tint res = get_external_ip(&extip);\n\t\t\tif (res) {\n\t\t\t\tfprintf(stderr, \"Failed to get external IP via DNS query.\\n\");\n\t\t\t\texit(3);\n\t\t\t}\n\t\t\tlisten_ip4 = inet_ntoa(extip);\n\t\t\tfprintf(stderr, \"Will listen on external IP %s\\n\", listen_ip4);\n\t\t}\n\t\tdns4addr_len = get_addr(listen_ip4, port, AF_INET, AI_PASSIVE, &dns4addr);\n\t\tif (dns4addr_len < 0) {\n\t\t\twarnx(\"Bad IPv4 address to listen on: '%s'\", listen_ip4);\n\t\t\tusage();\n\t\t}\n\t\t// Use dns4addr from here on.\n\t\tlisten_ip4 = NULL;\n\t}\n\tif (addrfamily == AF_UNSPEC || addrfamily == AF_INET6) {\n\t\tint addr6_res = get_addr(listen_ip6, port, AF_INET6, AI_PASSIVE, &dns6addr);\n\t\tif (addr6_res < 0) {\n\t\t\tif (listen_ip6 == NULL) {\n\t\t\t\tif (addrfamily == AF_INET6) {\n\t\t\t\t\tfprintf(stderr, \"IPv6 not supported\");\n\t\t\t\t\texit(3);\n\t\t\t\t} else {\n\t\t\t\t\twarnx(\"IPv6 not supported, skipping\");\n\t\t\t\t\taddrfamily = AF_INET;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarnx(\"Failed to get IPv6 address to listen on: '%s': %s\",\n\t\t\t\t\tlisten_ip6, gai_strerror(addr6_res));\n\t\t\t\tusage();\n\t\t\t\t/* NOTREACHED */\n\t\t\t}\n\t\t} else {\n\t\t\tdns6addr_len = addr6_res;\n\t\t}\n\t\t// Use dns6addr from here on.\n\t\tlisten_ip6 = NULL;\n\t}\n\n\tif (bind_enable) {\n\t\tin_addr_t dns_ip = ((struct sockaddr_in *) &dns4addr)->sin_addr.s_addr;\n\t\tif (bind_port < 1 || bind_port > 65535) {\n\t\t\twarnx(\"Bad DNS server port number given.\");\n\t\t\tusage();\n\t\t\t/* NOTREACHED */\n\t\t}\n\t\t/* Avoid forwarding loops */\n\t\tif (bind_port == port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) {\n\t\t\twarnx(\"Forward port is same as listen port (%d), will create a loop!\", bind_port);\n\t\t\tfprintf(stderr, \"Use -l to set listen ip to avoid this.\\n\");\n\t\t\tusage();\n\t\t\t/* NOTREACHED */\n\t\t}\n\t\tfprintf(stderr, \"Requests for domains outside of %s will be forwarded to port %d\\n\",\n\t\t\ttopdomain, bind_port);\n\t}\n\n\tif (ns_get_externalip) {\n\t\tstruct in_addr extip;\n\t\tint res = get_external_ip(&extip);\n\t\tif (res) {\n\t\t\tfprintf(stderr, \"Failed to get external IP via DNS query.\\n\");\n\t\t\texit(3);\n\t\t}\n\t\tns_ip = extip.s_addr;\n\t\tfprintf(stderr, \"Using %s as external IP.\\n\", inet_ntoa(extip));\n\t}\n\n\tif (ns_ip == INADDR_NONE) {\n\t\twarnx(\"Bad IP address to return as nameserver.\");\n\t\tusage();\n\t}\n\tif (netmask > 30 || netmask < 8) {\n\t\twarnx(\"Bad netmask (%d bits). Use 8-30 bits.\", netmask);\n\t\tusage();\n\t}\n\n\tif (strlen(password) == 0) {\n\t\tif (NULL != getenv(PASSWORD_ENV_VAR))\n\t\t\tsnprintf(password, sizeof(password), \"%s\", getenv(PASSWORD_ENV_VAR));\n\t\telse\n\t\t\tread_password(password, sizeof(password));\n\t}\n\n\t/* Mark both file descriptors as unused */\n\tdns_fds.v4fd = -1;\n\tdns_fds.v6fd = -1;\n\n\tcreated_users = init_users(my_ip, netmask);\n\n\tif ((tun_fd = open_tun(device)) == -1) {\n\t\t/* nothing to clean up, just return */\n\t\treturn 1;\n\t}\n\tif (!skipipconfig) {\n\t\tconst char *other_ip = users_get_first_ip();\n\t\tif (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {\n\t\t\tretval = 1;\n\t\t\tfree((void*) other_ip);\n\t\t\tgoto cleanup;\n\t\t}\n\t\tfree((void*) other_ip);\n\t}\n\n#ifdef HAVE_SYSTEMD\n\tnb_fds = sd_listen_fds(0);\n\tif (nb_fds < 0) {\n\t\twarnx(\"Failed to receive file descriptors from systemd: %s\", strerror(-nb_fds));\n\t\tretval = 1;\n\t\tgoto cleanup;\n\t} else if (nb_fds == 0) {\n#endif\n\t\tif ((addrfamily == AF_UNSPEC || addrfamily == AF_INET) &&\n\t\t\t(dns_fds.v4fd = open_dns(&dns4addr, dns4addr_len)) < 0) {\n\n\t\t\tretval = 1;\n\t\t\tgoto cleanup;\n\t\t}\n\t\tif ((addrfamily == AF_UNSPEC || addrfamily == AF_INET6) &&\n\t\t\t/* Set IPv6 socket to V6ONLY */\n\t\t\t(dns_fds.v6fd = open_dns_opt(&dns6addr, dns6addr_len, 1)) < 0) {\n\n\t\t\tretval = 1;\n\t\t\tgoto cleanup;\n\t\t}\n#ifdef HAVE_SYSTEMD\n\t} else if (nb_fds <= 2) {\n\t\t/* systemd may pass up to two sockets, for ip4 and ip6, try to figure out\n\t\t\twhich is which */\n\t\tfor (int i = 0; i < nb_fds; i++) {\n\t\t\tint fd = SD_LISTEN_FDS_START + i;\n\t\t\tif (sd_is_socket(fd, AF_INET, SOCK_DGRAM, -1)) {\n\t\t\t\tdns_fds.v4fd = fd;\n\t\t\t} else if (sd_is_socket(fd, AF_INET6, SOCK_DGRAM, -1)) {\n\t\t\t\tdns_fds.v6fd = fd;\n\t\t\t} else {\n\t\t\t\tretval = 1;\n\t\t\t\twarnx(\"Unknown socket %d passed to iodined!\\n\", fd);\n\t\t\t\tgoto cleanup;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tretval = 1;\n\t\twarnx(\"Too many file descriptors received!\\n\");\n\t\tgoto cleanup;\n\t}\n#endif\n\n\t/* Setup dns file descriptors to get destination IP address */\n\tif (dns_fds.v4fd >= 0)\n\t\tprepare_dns_fd(dns_fds.v4fd);\n\tif (dns_fds.v6fd >= 0)\n\t\tprepare_dns_fd(dns_fds.v6fd);\n\n\tif (bind_enable) {\n\t\tif ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {\n\t\t\tretval = 1;\n\t\t\tgoto cleanup;\n\t\t}\n\t}\n\n\tmy_mtu = mtu;\n\n\tif (created_users < USERS) {\n\t\tfprintf(stderr, \"Limiting to %d simultaneous users because of netmask /%d\\n\",\n\t\t\tcreated_users, netmask);\n\t}\n\tfprintf(stderr, \"Listening to dns for domain %s\\n\", topdomain);\n\n\tif (foreground == 0)\n\t\tdo_detach();\n\n\tif (pidfile != NULL)\n\t\tdo_pidfile(pidfile);\n\n#ifdef FREEBSD\n\ttzset();\n#endif\n#ifndef WINDOWS32\n\topenlog(__progname, LOG_NDELAY, LOG_DAEMON);\n#endif\n\n\tif (newroot != NULL)\n\t\tdo_chroot(newroot);\n\n\tsignal(SIGINT, sigint);\n\tif (username != NULL) {\n#ifndef WINDOWS32\n\t\tgid_t gids[1];\n\t\tgids[0] = pw->pw_gid;\n\t\tif (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {\n\t\t\twarnx(\"Could not switch to user %s!\\n\", username);\n\t\t\tusage();\n\t\t}\n#endif\n\t}\n\n\tif (context != NULL)\n\t\tdo_setcon(context);\n\n\tsyslog(LOG_INFO, \"started, listening on port %d\", port);\n\n\ttunnel(tun_fd, &dns_fds, bind_fd, max_idle_time);\n\n\tsyslog(LOG_INFO, \"stopping\");\n\tclose_dns(bind_fd);\ncleanup:\n\tif (dns_fds.v6fd >= 0)\n\t\tclose_dns(dns_fds.v6fd);\n\tif (dns_fds.v4fd >= 0)\n\t\tclose_dns(dns_fds.v4fd);\n\tclose_tun(tun_fd);\n\n\treturn retval;\n}\n"
  },
  {
    "path": "src/login.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <string.h>\n#include <sys/types.h>\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#else\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#endif\n\n#include \"login.h\"\n#include \"md5.h\"\n\n/*\n * Needs a 16byte array for output, and 32 bytes password\n */\nvoid\nlogin_calculate(char *buf, int buflen, const char *pass, int seed)\n{\n\tunsigned char temp[32];\n\tmd5_state_t ctx;\n\tint *ix;\n\tint i;\n\tint k;\n\n\tif (buflen < 16)\n\t\treturn;\n\n\tmemcpy(temp, pass, 32);\n\tix = (int*) temp;\n\n\tfor (i = 0; i < 8; i++) {\n\t\tk = ntohl(*ix);\n\t\tk ^= seed;\n\t\t*ix++ = htonl(k);\n\t}\n\n\tmd5_init(&ctx);\n\tmd5_append(&ctx, temp, 32);\n\tmd5_finish(&ctx, (unsigned char *) buf);\n\n}\n\n"
  },
  {
    "path": "src/login.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __LOGIN_H__\n#define __LOGIN_H__\n\nvoid login_calculate(char *, int, const char *, int);\n\n#endif\n\n"
  },
  {
    "path": "src/md5.c",
    "content": "/*\n  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  L. Peter Deutsch\n  ghost@aladdin.com\n\n */\n/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */\n/*\n  Independent implementation of MD5 (RFC 1321).\n\n  This code implements the MD5 Algorithm defined in RFC 1321, whose\n  text is available at\n\thttp://www.ietf.org/rfc/rfc1321.txt\n  The code is derived from the text of the RFC, including the test suite\n  (section A.5) but excluding the rest of Appendix A.  It does not include\n  any code or documentation that is identified in the RFC as being\n  copyrighted.\n\n  The original and principal author of md5.c is L. Peter Deutsch\n  <ghost@aladdin.com>.  Other authors are noted in the change history\n  that follows (in reverse chronological order):\n\n  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order\n\teither statically or dynamically; added missing #include <string.h>\n\tin library.\n  2002-03-11 lpd Corrected argument list for main(), and added int return\n\ttype, in test program and T value program.\n  2002-02-21 lpd Added missing #include <stdio.h> in test program.\n  2000-07-03 lpd Patched to eliminate warnings about \"constant is\n\tunsigned in ANSI C, signed in traditional\"; made test program\n\tself-checking.\n  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\n  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).\n  1999-05-03 lpd Original version.\n */\n\n#include \"md5.h\"\n#include <string.h>\n\n#undef BYTE_ORDER\t/* 1 = big-endian, -1 = little-endian, 0 = unknown */\n#ifdef ARCH_IS_BIG_ENDIAN\n#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)\n#else\n#  define BYTE_ORDER 0\n#endif\n\n#define T_MASK ((md5_word_t)~0)\n#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)\n#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)\n#define T3    0x242070db\n#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)\n#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)\n#define T6    0x4787c62a\n#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)\n#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)\n#define T9    0x698098d8\n#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)\n#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)\n#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)\n#define T13    0x6b901122\n#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)\n#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)\n#define T16    0x49b40821\n#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)\n#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)\n#define T19    0x265e5a51\n#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)\n#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)\n#define T22    0x02441453\n#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)\n#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)\n#define T25    0x21e1cde6\n#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)\n#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)\n#define T28    0x455a14ed\n#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)\n#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)\n#define T31    0x676f02d9\n#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)\n#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)\n#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)\n#define T35    0x6d9d6122\n#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)\n#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)\n#define T38    0x4bdecfa9\n#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)\n#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)\n#define T41    0x289b7ec6\n#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)\n#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)\n#define T44    0x04881d05\n#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)\n#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)\n#define T47    0x1fa27cf8\n#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)\n#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)\n#define T50    0x432aff97\n#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)\n#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)\n#define T53    0x655b59c3\n#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)\n#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)\n#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)\n#define T57    0x6fa87e4f\n#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)\n#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)\n#define T60    0x4e0811a1\n#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)\n#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)\n#define T63    0x2ad7d2bb\n#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)\n\n\nstatic void\nmd5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)\n{\n    md5_word_t\n\ta = pms->abcd[0], b = pms->abcd[1],\n\tc = pms->abcd[2], d = pms->abcd[3];\n    md5_word_t t;\n#if BYTE_ORDER > 0\n    /* Define storage only for big-endian CPUs. */\n    md5_word_t X[16];\n#else\n    /* Define storage for little-endian or both types of CPUs. */\n    md5_word_t xbuf[16];\n    const md5_word_t *X;\n#endif\n\n    {\n#if BYTE_ORDER == 0\n\t/*\n\t * Determine dynamically whether this is a big-endian or\n\t * little-endian machine, since we can use a more efficient\n\t * algorithm on the latter.\n\t */\n\tstatic const int w = 1;\n\n\tif (*((const md5_byte_t *)&w)) /* dynamic little-endian */\n#endif\n#if BYTE_ORDER <= 0\t\t/* little-endian */\n\t{\n\t\t/*\n\t\t * On little-endian machines, we can process properly aligned\n\t\t * data without copying it.\n\t\t */\n\t\tif (!((data - (const md5_byte_t *)0) & 3)) {\n\t\t\t/* data are properly aligned */\n\t\t\tX = (const md5_word_t *)data;\n\t\t} else {\n\t\t\t/* not aligned */\n\t\t\tmemcpy(xbuf, data, 64);\n\t\t\tX = xbuf;\n\t\t}\n\t}\n#endif\n#if BYTE_ORDER == 0\n\telse\t\t\t/* dynamic big-endian */\n#endif\n#if BYTE_ORDER >= 0\t\t/* big-endian */\n\t{\n\t\t/*\n\t\t * On big-endian machines, we must arrange the bytes in the\n\t\t * right order.\n\t\t */\n\t\tconst md5_byte_t *xp = data;\n\t\tint i;\n\n#  if BYTE_ORDER == 0\n\t\tX = xbuf;\t\t/* (dynamic only) */\n#  else\n#    define xbuf X\t\t/* (static only) */\n#  endif\n\t\tfor (i = 0; i < 16; ++i, xp += 4)\n\t\t\txbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);\n\t}\n#endif\n    }\n\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\n\n    /* Round 1. */\n    /* Let [abcd k s i] denote the operation\n       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */\n#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + F(b,c,d) + X[k] + Ti;\\\n  a = ROTATE_LEFT(t, s) + b\n    /* Do the following 16 operations. */\n    SET(a, b, c, d,  0,  7,  T1);\n    SET(d, a, b, c,  1, 12,  T2);\n    SET(c, d, a, b,  2, 17,  T3);\n    SET(b, c, d, a,  3, 22,  T4);\n    SET(a, b, c, d,  4,  7,  T5);\n    SET(d, a, b, c,  5, 12,  T6);\n    SET(c, d, a, b,  6, 17,  T7);\n    SET(b, c, d, a,  7, 22,  T8);\n    SET(a, b, c, d,  8,  7,  T9);\n    SET(d, a, b, c,  9, 12, T10);\n    SET(c, d, a, b, 10, 17, T11);\n    SET(b, c, d, a, 11, 22, T12);\n    SET(a, b, c, d, 12,  7, T13);\n    SET(d, a, b, c, 13, 12, T14);\n    SET(c, d, a, b, 14, 17, T15);\n    SET(b, c, d, a, 15, 22, T16);\n#undef SET\n\n     /* Round 2. */\n     /* Let [abcd k s i] denote the operation\n          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */\n#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + G(b,c,d) + X[k] + Ti;\\\n  a = ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  1,  5, T17);\n    SET(d, a, b, c,  6,  9, T18);\n    SET(c, d, a, b, 11, 14, T19);\n    SET(b, c, d, a,  0, 20, T20);\n    SET(a, b, c, d,  5,  5, T21);\n    SET(d, a, b, c, 10,  9, T22);\n    SET(c, d, a, b, 15, 14, T23);\n    SET(b, c, d, a,  4, 20, T24);\n    SET(a, b, c, d,  9,  5, T25);\n    SET(d, a, b, c, 14,  9, T26);\n    SET(c, d, a, b,  3, 14, T27);\n    SET(b, c, d, a,  8, 20, T28);\n    SET(a, b, c, d, 13,  5, T29);\n    SET(d, a, b, c,  2,  9, T30);\n    SET(c, d, a, b,  7, 14, T31);\n    SET(b, c, d, a, 12, 20, T32);\n#undef SET\n\n     /* Round 3. */\n     /* Let [abcd k s t] denote the operation\n          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + H(b,c,d) + X[k] + Ti;\\\n  a = ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  5,  4, T33);\n    SET(d, a, b, c,  8, 11, T34);\n    SET(c, d, a, b, 11, 16, T35);\n    SET(b, c, d, a, 14, 23, T36);\n    SET(a, b, c, d,  1,  4, T37);\n    SET(d, a, b, c,  4, 11, T38);\n    SET(c, d, a, b,  7, 16, T39);\n    SET(b, c, d, a, 10, 23, T40);\n    SET(a, b, c, d, 13,  4, T41);\n    SET(d, a, b, c,  0, 11, T42);\n    SET(c, d, a, b,  3, 16, T43);\n    SET(b, c, d, a,  6, 23, T44);\n    SET(a, b, c, d,  9,  4, T45);\n    SET(d, a, b, c, 12, 11, T46);\n    SET(c, d, a, b, 15, 16, T47);\n    SET(b, c, d, a,  2, 23, T48);\n#undef SET\n\n     /* Round 4. */\n     /* Let [abcd k s t] denote the operation\n          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */\n#define I(x, y, z) ((y) ^ ((x) | ~(z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + I(b,c,d) + X[k] + Ti;\\\n  a = ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  0,  6, T49);\n    SET(d, a, b, c,  7, 10, T50);\n    SET(c, d, a, b, 14, 15, T51);\n    SET(b, c, d, a,  5, 21, T52);\n    SET(a, b, c, d, 12,  6, T53);\n    SET(d, a, b, c,  3, 10, T54);\n    SET(c, d, a, b, 10, 15, T55);\n    SET(b, c, d, a,  1, 21, T56);\n    SET(a, b, c, d,  8,  6, T57);\n    SET(d, a, b, c, 15, 10, T58);\n    SET(c, d, a, b,  6, 15, T59);\n    SET(b, c, d, a, 13, 21, T60);\n    SET(a, b, c, d,  4,  6, T61);\n    SET(d, a, b, c, 11, 10, T62);\n    SET(c, d, a, b,  2, 15, T63);\n    SET(b, c, d, a,  9, 21, T64);\n#undef SET\n\n     /* Then perform the following additions. (That is increment each\n        of the four registers by the value it had before this block\n        was started.) */\n    pms->abcd[0] += a;\n    pms->abcd[1] += b;\n    pms->abcd[2] += c;\n    pms->abcd[3] += d;\n}\n\nvoid\nmd5_init(md5_state_t *pms)\n{\n    pms->count[0] = pms->count[1] = 0;\n    pms->abcd[0] = 0x67452301;\n    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;\n    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;\n    pms->abcd[3] = 0x10325476;\n}\n\nvoid\nmd5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)\n{\n    const md5_byte_t *p = data;\n    int left = nbytes;\n    int offset = (pms->count[0] >> 3) & 63;\n    md5_word_t nbits = (md5_word_t)(nbytes << 3);\n\n    if (nbytes <= 0)\n\treturn;\n\n    /* Update the message length. */\n    pms->count[1] += nbytes >> 29;\n    pms->count[0] += nbits;\n    if (pms->count[0] < nbits)\n\tpms->count[1]++;\n\n    /* Process an initial partial block. */\n    if (offset) {\n\tint copy = (offset + nbytes > 64 ? 64 - offset : nbytes);\n\n\tmemcpy(pms->buf + offset, p, copy);\n\tif (offset + copy < 64)\n\t\treturn;\n\tp += copy;\n\tleft -= copy;\n\tmd5_process(pms, pms->buf);\n    }\n\n    /* Process full blocks. */\n    for (; left >= 64; p += 64, left -= 64)\n\tmd5_process(pms, p);\n\n    /* Process a final partial block. */\n    if (left)\n\tmemcpy(pms->buf, p, left);\n}\n\nvoid\nmd5_finish(md5_state_t *pms, md5_byte_t digest[16])\n{\n    static const md5_byte_t pad[64] = {\n\t0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    };\n    md5_byte_t data[8];\n    int i;\n\n    /* Save the length before padding. */\n    for (i = 0; i < 8; ++i)\n\tdata[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));\n    /* Pad to 56 bytes mod 64. */\n    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);\n    /* Append the length. */\n    md5_append(pms, data, 8);\n    for (i = 0; i < 16; ++i)\n\tdigest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));\n}\n\n\n\n"
  },
  {
    "path": "src/md5.h",
    "content": "/*\n  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  L. Peter Deutsch\n  ghost@aladdin.com\n\n */\n/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */\n/*\n  Independent implementation of MD5 (RFC 1321).\n\n  This code implements the MD5 Algorithm defined in RFC 1321, whose\n  text is available at\n\thttp://www.ietf.org/rfc/rfc1321.txt\n  The code is derived from the text of the RFC, including the test suite\n  (section A.5) but excluding the rest of Appendix A.  It does not include\n  any code or documentation that is identified in the RFC as being\n  copyrighted.\n\n  The original and principal author of md5.h is L. Peter Deutsch\n  <ghost@aladdin.com>.  Other authors are noted in the change history\n  that follows (in reverse chronological order):\n\n  2002-04-13 lpd Removed support for non-ANSI compilers; removed\n\treferences to Ghostscript; clarified derivation from RFC 1321;\n\tnow handles byte order either statically or dynamically.\n  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\n  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);\n\tadded conditionalization for C++ compilation from Martin\n\tPurschke <purschke@bnl.gov>.\n  1999-05-03 lpd Original version.\n */\n\n#ifndef md5_INCLUDED\n#  define md5_INCLUDED\n\n/*\n * This package supports both compile-time and run-time determination of CPU\n * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be\n * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is\n * defined as non-zero, the code will be compiled to run only on big-endian\n * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to\n * run on either big- or little-endian CPUs, but will run slightly less\n * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.\n */\n\ntypedef unsigned char md5_byte_t; /* 8-bit byte */\ntypedef unsigned int md5_word_t; /* 32-bit word */\n\n/* Define the state of the MD5 Algorithm. */\ntypedef struct md5_state_s {\n    md5_word_t count[2];\t/* message length in bits, lsw first */\n    md5_word_t abcd[4];\t\t/* digest buffer */\n    md5_byte_t buf[64];\t\t/* accumulate block */\n} md5_state_t;\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/* Initialize the algorithm. */\nvoid md5_init(md5_state_t *pms);\n\n/* Append a string to the message. */\nvoid md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);\n\n/* Finish the message and return the digest. */\nvoid md5_finish(md5_state_t *pms, md5_byte_t digest[16]);\n\n#ifdef __cplusplus\n}  /* end extern \"C\" */\n#endif\n\n#endif /* md5_INCLUDED */\n"
  },
  {
    "path": "src/osflags",
    "content": "#!/bin/sh\n\n: \"${PKG_CONFIG:=pkg-config}\"\n\ncase $2 in\nlink)\n\n\tcase $1 in\n\t\tSunOS | solaris)\n\t\t\techo '-lsocket -lnsl';\n\t\t;;\n\t\tBeOS)\n\t\t\techo '-lsocket -lbind -lbsd';\n\t\t;;\n\t\tHaiku)\n\t\t\techo '-lnetwork -lbsd';\n\t\t;;\n\t\twindows32)\n\t\t\techo '-lws2_32 -liphlpapi';\n\t\t;;\n\t\tLinux)\n\t\t\tFLAGS=\"\";\n\t\t\t\"$PKG_CONFIG\" --exists libselinux && FLAGS=\"$FLAGS $($PKG_CONFIG --libs libselinux)\";\n\t\t\t\"$PKG_CONFIG\" --exists libsystemd-daemon && FLAGS=\"$FLAGS $($PKG_CONFIG --libs libsystemd-daemon)\";\n\t\t\t\"$PKG_CONFIG\" --exists libsystemd && FLAGS=\"$FLAGS $($PKG_CONFIG --libs libsystemd)\";\n\t\t\techo $FLAGS;\n\t\t;;\n\tesac\n\t;;\ncflags)\n\tcase $1 in\n\t\twindows32)\n\t\t\techo '-DWINVER=0x0501';\n\t\t;;\n\t\tBeOS)\n\t\t\techo '-Dsocklen_t=int';\n\t\t;;\n\t\tHaiku)\n\t\t\techo '-D_DEFAULT_SOURCE';\n\t\t;;\n\t\tDarwin)\n\t\t\techo '-D__APPLE_USE_RFC_3542';\n\t\t;;\n\t\tLinux)\n\t\t\tFLAGS=\"-D_GNU_SOURCE\"\n\t\t\t\"$PKG_CONFIG\" --exists libselinux && FLAGS=\"$FLAGS -DHAVE_SETCON\";\n\t\t\t\"$PKG_CONFIG\" --exists libsystemd-daemon && FLAGS=\"$FLAGS -DHAVE_SYSTEMD\";\n\t\t\t\"$PKG_CONFIG\" --exists libsystemd && FLAGS=\"$FLAGS -DHAVE_SYSTEMD\";\n\t\t\techo $FLAGS;\n\t\t;;\n\t\tGNU/kFreeBSD|GNU)\n\t\t\techo '-D_GNU_SOURCE'\n\t\t;;\n\tesac\n;;\n*)\n;;\nesac\n"
  },
  {
    "path": "src/read.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <string.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#include \"read.h\"\n\nstatic int\nreadname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)\n{\n\tchar *dummy;\n\tchar *s;\n\tchar *d;\n\tint len;\n\tint offset;\n\tchar c;\n\n\tif (loop <= 0)\n\t\treturn 0;\n\n\tlen = 0;\n\ts = *src;\n\td = dst;\n\twhile(*s && len < length - 2) {\n\t\tc = *s++;\n\n\t\t/* is this a compressed label? */\n\t\tif ((c & 0xc0) == 0xc0) {\n\t\t\toffset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));\n\t\t\tif (offset > packetlen) {\n\t\t\t\tif (len == 0) {\n\t\t\t\t\t/* Bad jump first in packet */\n\t\t\t\t\treturn 0;\n\t\t\t\t} else {\n\t\t\t\t\t/* Bad jump after some data */\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdummy = packet + offset;\n\t\t\tlen += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);\n\t\t\tgoto end;\n\t\t}\n\n\t\twhile(c && len < length - 1) {\n\t\t\t*d++ = *s++;\n\t\t\tlen++;\n\n\t\t\tc--;\n\t\t}\n\n\t\tif (len >= length - 1) {\n\t\t\tbreak; /* We used up all space */\n\t\t}\n\n\t\tif (*s != 0) {\n\t\t\t*d++ = '.';\n\t\t\tlen++;\n\t\t}\n\t}\n\tdst[len++] = '\\0';\n\nend:\n\t(*src) = s+1;\n\treturn len;\n}\n\nint\nreadname(char *packet, int packetlen, char **src, char *dst, size_t length)\n{\n\treturn readname_loop(packet, packetlen, src, dst, length, 10);\n}\n\nint\nreadshort(char *packet, char **src, unsigned short *dst)\n{\n\tunsigned char *p;\n\n\tp = (unsigned char *) *src;\n\t*dst = (p[0] << 8) | p[1];\n\n\t(*src) += sizeof(unsigned short);\n\treturn sizeof(unsigned short);\n}\n\nint\nreadlong(char *packet, char **src, uint32_t *dst)\n{\n\t/* A long as described in dns protocol is always 32 bits */\n\tunsigned char *p;\n\n\tp = (unsigned char *) *src;\n\n\t*dst = ((uint32_t)p[0] << 24)\n\t\t | ((uint32_t)p[1] << 16)\n\t\t | ((uint32_t)p[2] << 8)\n\t\t | ((uint32_t)p[3]);\n\n\t(*src) += sizeof(uint32_t);\n\treturn sizeof(uint32_t);\n}\n\nint\nreaddata(char *packet, char **src, char *dst, size_t len)\n{\n\tmemcpy(dst, *src, len);\n\n\t(*src) += len;\n\n\treturn len;\n}\n\nint\nreadtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain)\n{\n\tunsigned char *uc;\n\tint tocopy;\n\tint dstused = 0;\n\n\twhile (srcremain > 0)\n\t{\n\t\tuc = (unsigned char*) (*src);\n\t\ttocopy = *uc;\n\t\t(*src)++;\n\t\tsrcremain--;\n\n\t\tif (tocopy > srcremain)\n\t\t\treturn 0;\t/* illegal, better have nothing */\n\t\tif (tocopy > dstremain)\n\t\t\treturn 0;\t/* doesn't fit, better have nothing */\n\n\t\tmemcpy(dst, *src, tocopy);\n\t\tdst += tocopy;\n\t\t(*src) += tocopy;\n\t\tsrcremain -= tocopy;\n\t\tdstremain -= tocopy;\n\t\tdstused += tocopy;\n\t}\n\treturn dstused;\n}\n\nint\nputname(char **buf, size_t buflen, const char *host)\n{\n\tchar *word;\n\tint left;\n\tchar *h;\n\tchar *p;\n\n\th = strdup(host);\n\tleft = buflen;\n\tp = *buf;\n\n\tword = strtok(h, \".\");\n\twhile(word) {\n\t\tsize_t word_len = strlen(word);\n\t\tif (word_len > 63 || word_len > left) {\n\t\t\tfree(h);\n\t\t\treturn -1;\n\t\t}\n\n\t\tleft -= (word_len + 1);\n\t\t*p++ = (char)word_len;\n\t\tmemcpy(p, word, word_len);\n\t\tp += word_len;\n\n\t\tword = strtok(NULL, \".\");\n\t}\n\n\t*p++ = 0;\n\n\tfree(h);\n\n\t*buf = p;\n\treturn buflen - left;\n}\n\nint\nputbyte(char **dst, unsigned char value)\n{\n\t**dst = value;\n\t(*dst)++;\n\n\treturn sizeof(char);\n}\n\nint\nputshort(char **dst, unsigned short value)\n{\n\tunsigned char *p;\n\n\tp = (unsigned char *) *dst;\n\n\t*p++ = (value >> 8);\n\t*p++ = value;\n\n\t(*dst) = (char *) p;\n\treturn sizeof(short);\n}\n\nint\nputlong(char **dst, uint32_t value)\n{\n\t/* A long as described in dns protocol is always 32 bits */\n\tunsigned char *p;\n\n\tp = (unsigned char *) *dst;\n\n\t*p++ = (value >> 24);\n\t*p++ = (value >> 16);\n\t*p++ = (value >> 8);\n\t*p++ = (value);\n\n\t(*dst) = (char *) p;\n\treturn sizeof(uint32_t);\n}\n\nint\nputdata(char **dst, const char *data, size_t len)\n{\n\tmemcpy(*dst, data, len);\n\n\t(*dst) += len;\n\treturn len;\n}\n\nint\nputtxtbin(char **buf, size_t bufremain, const char *from, size_t fromremain)\n{\n\tunsigned char uc;\n\tunsigned char *ucp = &uc;\n\tchar *cp = (char *) ucp;\n\tint tocopy;\n\tint bufused = 0;\n\n\twhile (fromremain > 0)\n\t{\n\t\ttocopy = fromremain;\n\t\tif (tocopy > 252)\n\t\t\ttocopy = 252;\t/* allow off-by-1s in caches etc */\n\t\tif (tocopy + 1 > bufremain)\n\t\t\treturn -1;\t/* doesn't fit, better have nothing */\n\n\t\tuc = tocopy;\n\t\t**buf = *cp;\n\t\t(*buf)++;\n\t\tbufremain--;\n\t\tbufused++;\n\n\t\tmemcpy(*buf, from, tocopy);\n\t\t(*buf) += tocopy;\n\t\tfrom += tocopy;\n\t\tbufremain -= tocopy;\n\t\tfromremain -= tocopy;\n\t\tbufused += tocopy;\n\t}\n\treturn bufused;\n}\n"
  },
  {
    "path": "src/read.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef _READ_H_\n#define _READ_H_\n\nint readname(char *, int, char **, char *, size_t);\nint readshort(char *, char **, unsigned short *);\nint readlong(char *, char **, uint32_t *);\nint readdata(char *, char **, char *, size_t);\nint readtxtbin(char *, char **, size_t, char *, size_t);\n\nint putname(char **, size_t, const char *);\nint putbyte(char **, unsigned char);\nint putshort(char **, unsigned short);\nint putlong(char **, uint32_t);\nint putdata(char **, const char *, size_t);\nint puttxtbin(char **, size_t, const char *, size_t);\n\n#endif\n"
  },
  {
    "path": "src/tun.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n * 2013 Peter Sagerson <psagers.github@ignorare.net>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <errno.h>\n#include <stdint.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\n#ifdef DARWIN\n#include <ctype.h>\n#include <sys/kern_control.h>\n#include <sys/sys_domain.h>\n#include <sys/ioctl.h>\n/* Inline used parts of if_utun.h to compile without it. */\n#define UTUN_CONTROL_NAME \"com.apple.net.utun_control\"\n#define UTUN_OPT_IFNAME 2\n#include <netinet/ip.h>\n#endif\n\n#ifndef IFCONFIGPATH\n#define IFCONFIGPATH \"PATH=/sbin:/bin \"\n#endif\n\n#ifndef ROUTEPATH\n#define ROUTEPATH \"PATH=/sbin:/bin \"\n#endif\n\n#ifdef WINDOWS32\n#include \"windows.h\"\n#include <winioctl.h>\n\nstatic HANDLE dev_handle;\nstatic struct tun_data data;\n\nstatic void get_name(char *ifname, int namelen, char *dev_name);\n\n#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)\n#define TAP_IOCTL_CONFIG_TUN       TAP_CONTROL_CODE(10, METHOD_BUFFERED)\n#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)\n\n#define TAP_ADAPTER_KEY \"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Class\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}\"\n#define NETWORK_KEY \"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Network\\\\{4D36E972-E325-11CE-BFC1-08002BE10318}\"\n#define TAP_DEVICE_SPACE \"\\\\\\\\.\\\\Global\\\\\"\n#define TAP_VERSION_ID_0801 \"tap0801\"\n#define TAP_VERSION_ID_0901 \"tap0901\"\n#define TAP_VERSION_ID_0901_ROOT \"root\\\\tap0901\"\n#define KEY_COMPONENT_ID \"ComponentId\"\n#define NET_CFG_INST_ID \"NetCfgInstanceId\"\n#else\n#include <err.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\n#define TUN_MAX_TRY 50\n#endif\n\n#include \"tun.h\"\n#include \"common.h\"\n\nstatic char if_name[250];\n\n#ifdef LINUX\n\n#include <sys/ioctl.h>\n#include <net/if.h>\n#include <linux/if_tun.h>\n\nint\nopen_tun(const char *tun_device)\n{\n\tint i;\n\tint tun_fd;\n\tstruct ifreq ifreq;\n#ifdef ANDROID\n\tchar *tunnel = \"/dev/tun\";\n#else\n\tchar *tunnel = \"/dev/net/tun\";\n#endif\n\n\tif ((tun_fd = open(tunnel, O_RDWR)) < 0) {\n\t\twarn(\"open_tun: %s\", tunnel);\n\t\treturn -1;\n\t}\n\n\tmemset(&ifreq, 0, sizeof(ifreq));\n\n\tifreq.ifr_flags = IFF_TUN;\n\n\tif (tun_device != NULL) {\n\t\tstrncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);\n\t\tifreq.ifr_name[IFNAMSIZ-1] = '\\0';\n\t\tstrncpy(if_name, tun_device, sizeof(if_name));\n\t\tif_name[sizeof(if_name)-1] = '\\0';\n\n\t\tif (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {\n\t\t\tfprintf(stderr, \"Opened %s\\n\", ifreq.ifr_name);\n\t\t\tfd_set_close_on_exec(tun_fd);\n\t\t\treturn tun_fd;\n\t\t}\n\n\t\tif (errno != EBUSY) {\n\t\t\twarn(\"open_tun: ioctl[TUNSETIFF]\");\n\t\t\treturn -1;\n\t\t}\n\t} else {\n\t\tfor (i = 0; i < TUN_MAX_TRY; i++) {\n\t\t\tsnprintf(ifreq.ifr_name, IFNAMSIZ, \"dns%d\", i);\n\n\t\t\tif (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {\n\t\t\t\tfprintf(stderr, \"Opened %s\\n\", ifreq.ifr_name);\n\t\t\t\tsnprintf(if_name, sizeof(if_name), \"dns%d\", i);\n\t\t\t\tfd_set_close_on_exec(tun_fd);\n\t\t\t\treturn tun_fd;\n\t\t\t}\n\n\t\t\tif (errno != EBUSY) {\n\t\t\t\twarn(\"open_tun: ioctl[TUNSETIFF]\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\n\t\twarn(\"open_tun: Couldn't set interface name\");\n\t}\n\twarn(\"error when opening tun\");\n\treturn -1;\n}\n\n#elif WINDOWS32\n\nstatic void\nget_device(char *device, int device_len, const char *wanted_dev)\n{\n\tLONG status;\n\tHKEY adapter_key;\n\tint index;\n\n\tindex = 0;\n\tstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);\n\n\tif (status != ERROR_SUCCESS) {\n\t\twarnx(\"Error opening registry key \" TAP_ADAPTER_KEY);\n\t\treturn;\n\t}\n\n\twhile (TRUE) {\n\t\tchar name[256];\n\t\tchar unit[256];\n\t\tchar component[256];\n\n\t\tchar cid_string[256] = KEY_COMPONENT_ID;\n\t\tHKEY device_key;\n\t\tDWORD datatype;\n\t\tDWORD len;\n\n\t\t/* Iterate through all adapter of this kind */\n\t\tlen = sizeof(name);\n\t\tstatus = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);\n\t\tif (status == ERROR_NO_MORE_ITEMS) {\n\t\t\tbreak;\n\t\t} else if (status != ERROR_SUCCESS) {\n\t\t\twarnx(\"Error enumerating subkeys of registry key \" TAP_ADAPTER_KEY);\n\t\t\tbreak;\n\t\t}\n\n\t\tsnprintf(unit, sizeof(unit), TAP_ADAPTER_KEY \"\\\\%s\", name);\n\t\tstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);\n\t\tif (status != ERROR_SUCCESS) {\n\t\t\twarnx(\"Error opening registry key %s\", unit);\n\t\t\tgoto next;\n\t\t}\n\n\t\t/* Check component id */\n\t\tlen = sizeof(component);\n\t\tstatus = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);\n\t\tif (status != ERROR_SUCCESS || datatype != REG_SZ) {\n\t\t\tgoto next;\n\t\t}\n\t\tif (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||\n\t\t\tstrncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0 ||\n\t\t\tstrncmp(TAP_VERSION_ID_0901_ROOT, component, strlen(TAP_VERSION_ID_0901_ROOT)) == 0) {\n\t\t\t/* We found a TAP32 device, get its NetCfgInstanceId */\n\t\t\tchar iid_string[256] = NET_CFG_INST_ID;\n\n\t\t\tstatus = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);\n\t\t\tif (status != ERROR_SUCCESS || datatype != REG_SZ) {\n\t\t\t\twarnx(\"Error reading registry key %s\\\\%s on TAP device\", unit, iid_string);\n\t\t\t} else {\n\t\t\t\t/* Done getting GUID of TAP device,\n\t\t\t\t * now check if the name is the requested one */\n\t\t\t\tif (wanted_dev) {\n\t\t\t\t\tchar name[250];\n\t\t\t\t\tget_name(name, sizeof(name), device);\n\t\t\t\t\tif (strncmp(name, wanted_dev, strlen(wanted_dev))) {\n\t\t\t\t\t\t/* Skip if name mismatch */\n\t\t\t\t\t\tgoto next;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t/* Get the if name */\n\t\t\t\tget_name(if_name, sizeof(if_name), device);\n\t\t\t\tRegCloseKey(device_key);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\nnext:\n\t\tRegCloseKey(device_key);\n\t\tindex++;\n\t}\n\tRegCloseKey(adapter_key);\n}\n\nstatic void\nget_name(char *ifname, int namelen, char *dev_name)\n{\n\tchar path[256];\n\tchar name_str[256] = \"Name\";\n\tLONG status;\n\tHKEY conn_key;\n\tDWORD len;\n\tDWORD datatype;\n\n\tmemset(ifname, 0, namelen);\n\n\tsnprintf(path, sizeof(path), NETWORK_KEY \"\\\\%s\\\\Connection\", dev_name);\n\tstatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &conn_key);\n\tif (status != ERROR_SUCCESS) {\n\t\tfprintf(stderr, \"Could not look up name of interface %s: error opening key\\n\", dev_name);\n\t\tRegCloseKey(conn_key);\n\t\treturn;\n\t}\n\tlen = namelen;\n\tstatus = RegQueryValueEx(conn_key, name_str, NULL, &datatype, (LPBYTE)ifname, &len);\n\tif (status != ERROR_SUCCESS || datatype != REG_SZ) {\n\t\tfprintf(stderr, \"Could not look up name of interface %s: error reading value\\n\", dev_name);\n\t\tRegCloseKey(conn_key);\n\t\treturn;\n\t}\n\tRegCloseKey(conn_key);\n}\n\nDWORD WINAPI tun_reader(LPVOID arg)\n{\n\tstruct tun_data *tun = arg;\n\tchar buf[64*1024];\n\tint len;\n\tint res;\n\tOVERLAPPED olpd;\n\tint sock;\n\n\tsock = open_dns_from_host(\"127.0.0.1\", 0, AF_INET, 0);\n\n\tolpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\n\n\twhile(TRUE) {\n\t\tolpd.Offset = 0;\n\t\tolpd.OffsetHigh = 0;\n\t\tres = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);\n\t\tif (!res) {\n\t\t\tWaitForSingleObject(olpd.hEvent, INFINITE);\n\t\t\tres = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);\n\t\t\tres = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),\n\t\t\t\ttun->addrlen);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint\nopen_tun(const char *tun_device)\n{\n\tchar adapter[256];\n\tchar tapfile[512];\n\tint tunfd;\n\tstruct sockaddr_storage localsock;\n\tint localsock_len;\n\n\tmemset(adapter, 0, sizeof(adapter));\n\tmemset(if_name, 0, sizeof(if_name));\n\tget_device(adapter, sizeof(adapter), tun_device);\n\n\tif (strlen(adapter) == 0 || strlen(if_name) == 0) {\n\t\tif (tun_device) {\n\t\t\twarnx(\"No TAP adapters found. Try without -d.\");\n\t\t} else {\n\t\t\twarnx(\"No TAP adapters found. Version 0801 and 0901 are supported.\");\n\t\t}\n\t\treturn -1;\n\t}\n\n\tfprintf(stderr, \"Opening device %s\\n\", if_name);\n\tsnprintf(tapfile, sizeof(tapfile), \"%s%s.tap\", TAP_DEVICE_SPACE, adapter);\n\tdev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);\n\tif (dev_handle == INVALID_HANDLE_VALUE) {\n\t\twarnx(\"Could not open device!\");\n\t\treturn -1;\n\t}\n\n\t/* Use a UDP connection to forward packets from tun,\n\t * so we can still use select() in main code.\n\t * A thread does blocking reads on tun device and\n\t * sends data as udp to this socket */\n\n\tlocalsock_len = get_addr(\"127.0.0.1\", 55353, AF_INET, 0, &localsock);\n\ttunfd = open_dns(&localsock, localsock_len);\n\n\tdata.tun = dev_handle;\n\tmemcpy(&(data.addr), &localsock, localsock_len);\n\tdata.addrlen = localsock_len;\n\tCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);\n\n\treturn tunfd;\n}\n\n#else /* BSD and friends */\n\n#ifdef DARWIN\n\n/* Extract the device number from the name, if given. The value returned will\n * be suitable for sockaddr_ctl.sc_unit, which means 0 for auto-assign, or\n * (n + 1) for manual.\n */\nstatic int\nutun_unit(const char *dev)\n{\n\tconst char *unit_str = dev;\n\tint unit = 0;\n\n\tif (!dev)\n\t\treturn -1;\n\n\twhile (*unit_str != '\\0' && !isdigit(*unit_str))\n\t\tunit_str++;\n\n\tif (isdigit(*unit_str))\n\t\tunit = strtol(unit_str, NULL, 10) + 1;\n\n\treturn unit;\n}\n\nstatic int\nopen_utun(const char *dev)\n{\n\tstruct sockaddr_ctl addr;\n\tstruct ctl_info info;\n\tchar ifname[10];\n\tsocklen_t ifname_len = sizeof(ifname);\n\tint unit;\n\tint fd = -1;\n\tint err = 0;\n\n\tfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);\n\tif (fd < 0) {\n\t\twarn(\"open_utun: socket(PF_SYSTEM)\");\n\t\treturn -1;\n\t}\n\n\t/* Look up the kernel controller ID for utun devices. */\n\tbzero(&info, sizeof(info));\n\tstrncpy(info.ctl_name, UTUN_CONTROL_NAME, MAX_KCTL_NAME);\n\n\terr = ioctl(fd, CTLIOCGINFO, &info);\n\tif (err != 0) {\n\t\twarn(\"open_utun: ioctl(CTLIOCGINFO)\");\n\t\tclose(fd);\n\t\treturn -1;\n\t}\n\n\t/* Connecting to the socket creates the utun device. */\n\taddr.sc_len = sizeof(addr);\n\taddr.sc_family = AF_SYSTEM;\n\taddr.ss_sysaddr = AF_SYS_CONTROL;\n\taddr.sc_id = info.ctl_id;\n\tunit = utun_unit(dev);\n\tif (unit < 0) {\n\t\tclose(fd);\n\t\treturn -1;\n\t}\n\taddr.sc_unit = unit;\n\n\terr = connect(fd, (struct sockaddr *)&addr, sizeof(addr));\n\tif (err != 0) {\n\t\twarn(\"open_utun: connect\");\n\t\tclose(fd);\n\t\treturn -1;\n\t}\n\n\t/* Retrieve the assigned interface name. */\n\terr = getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, ifname, &ifname_len);\n\tif (err != 0) {\n\t\twarn(\"open_utun: getsockopt(UTUN_OPT_IFNAME)\");\n\t\tclose(fd);\n\t\treturn -1;\n\t}\n\n\tstrncpy(if_name, ifname, sizeof(if_name));\n\n\tfprintf(stderr, \"Opened %s\\n\", ifname);\n\tfd_set_close_on_exec(fd);\n\n\treturn fd;\n}\n\n#endif\n\nint\nopen_tun(const char *tun_device)\n{\n\tint i;\n\tint tun_fd;\n\tchar tun_name[50];\n\n\tif (tun_device != NULL) {\n#ifdef DARWIN\n\t\tif (!strncmp(tun_device, \"utun\", 4)) {\n\t\t\ttun_fd = open_utun(tun_device);\n\t\t\tif (tun_fd >= 0) {\n\t\t\t\treturn tun_fd;\n\t\t\t}\n\t\t}\n#endif\n\n\t\tsnprintf(tun_name, sizeof(tun_name), \"/dev/%s\", tun_device);\n\t\tstrncpy(if_name, tun_device, sizeof(if_name));\n\t\tif_name[sizeof(if_name)-1] = '\\0';\n\n\t\tif ((tun_fd = open(tun_name, O_RDWR)) < 0) {\n\t\t\twarn(\"open_tun: %s\", tun_name);\n\t\t\treturn -1;\n\t\t}\n\n\t\tfprintf(stderr, \"Opened %s\\n\", tun_name);\n\t\tfd_set_close_on_exec(tun_fd);\n\t\treturn tun_fd;\n\t} else {\n\t\tfor (i = 0; i < TUN_MAX_TRY; i++) {\n\t\t\tsnprintf(tun_name, sizeof(tun_name), \"/dev/tun%d\", i);\n\n\t\t\tif ((tun_fd = open(tun_name, O_RDWR)) >= 0) {\n\t\t\t\tfprintf(stderr, \"Opened %s\\n\", tun_name);\n\t\t\t\tsnprintf(if_name, sizeof(if_name), \"tun%d\", i);\n\t\t\t\tfd_set_close_on_exec(tun_fd);\n\t\t\t\treturn tun_fd;\n\t\t\t}\n\n\t\t\tif (errno == ENOENT)\n\t\t\t\tbreak;\n\t\t}\n\n#ifdef DARWIN\n\t\tfprintf(stderr, \"No tun devices found, trying utun\\n\");\n\t\tfor (i = 0; i < TUN_MAX_TRY; i++) {\n\t\t\tsnprintf(tun_name, sizeof(tun_name), \"utun%d\", i);\n\t\t\ttun_fd = open_utun(tun_name);\n\t\t\tif (tun_fd >= 0) {\n\t\t\t\treturn tun_fd;\n\t\t\t}\n\t\t}\n#endif\n\n\t\twarn(\"open_tun: Failed to open tunneling device\");\n\t}\n\n\treturn -1;\n}\n\n#endif\n\nvoid\nclose_tun(int tun_fd)\n{\n\tif (tun_fd >= 0)\n\t\tclose(tun_fd);\n}\n\n#ifdef WINDOWS32\nint\nwrite_tun(int tun_fd, char *data, size_t len)\n{\n\tDWORD written;\n\tDWORD res;\n\tOVERLAPPED olpd;\n\n\tdata += 4;\n\tlen -= 4;\n\n\tolpd.Offset = 0;\n\tolpd.OffsetHigh = 0;\n\tolpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\n\tres = WriteFile(dev_handle, data, len, &written, &olpd);\n\tif (!res && GetLastError() == ERROR_IO_PENDING) {\n\t\tWaitForSingleObject(olpd.hEvent, INFINITE);\n\t\tres = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);\n\t\tif (written != len) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\treturn 0;\n}\n\nssize_t\nread_tun(int tun_fd, char *buf, size_t len)\n{\n\tint bytes;\n\tmemset(buf, 0, 4);\n\n\tbytes = recv(tun_fd, buf + 4, len - 4, 0);\n\tif (bytes < 0) {\n\t\treturn bytes;\n\t} else {\n\t\treturn bytes + 4;\n\t}\n}\n#else\nstatic int\ntun_uses_header(void)\n{\n#if defined (FREEBSD) || defined (NETBSD)\n\t/* FreeBSD/NetBSD has no header */\n\treturn 0;\n#elif defined (DARWIN)\n\t/* Darwin tun has no header, Darwin utun does */\n\treturn !strncmp(if_name, \"utun\", 4);\n#else  /* LINUX/OPENBSD */\n\treturn 1;\n#endif\n}\n\nint\nwrite_tun(int tun_fd, char *data, size_t len)\n{\n\tif (!tun_uses_header()) {\n\t\tdata += 4;\n\t\tlen -= 4;\n\t} else {\n#ifdef LINUX\n\t\t// Linux prefixes with 32 bits ethertype\n\t\t// 0x0800 for IPv4, 0x86DD for IPv6\n\t\tdata[0] = 0x00;\n\t\tdata[1] = 0x00;\n\t\tdata[2] = 0x08;\n\t\tdata[3] = 0x00;\n#else /* OPENBSD and DARWIN(utun) */\n\t\t// BSDs prefix with 32 bits address family\n\t\t// AF_INET for IPv4, AF_INET6 for IPv6\n\t\tdata[0] = 0x00;\n\t\tdata[1] = 0x00;\n\t\tdata[2] = 0x00;\n\t\tdata[3] = 0x02;\n#endif\n\t}\n\n\tif (write(tun_fd, data, len) != len) {\n\t\twarn(\"write_tun\");\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nssize_t\nread_tun(int tun_fd, char *buf, size_t len)\n{\n\tif (!tun_uses_header()) {\n\t\tint bytes;\n\t\tmemset(buf, 0, 4);\n\n\t\tbytes = read(tun_fd, buf + 4, len - 4);\n\t\tif (bytes < 0) {\n\t\t\treturn bytes;\n\t\t} else {\n\t\t\treturn bytes + 4;\n\t\t}\n\t} else {\n\t\treturn read(tun_fd, buf, len);\n\t}\n}\n#endif\n\nint\ntun_setip(const char *ip, const char *other_ip, int netbits)\n{\n\tchar cmdline[512];\n\tint netmask;\n\tstruct in_addr net;\n\tint i;\n#ifndef LINUX\n\tint r;\n#endif\n#ifdef WINDOWS32\n\tDWORD status;\n\tDWORD ipdata[3];\n\tstruct in_addr addr;\n\tDWORD len;\n#else\n\tconst char *display_ip;\n#ifndef LINUX\n\tstruct in_addr netip;\n#endif\n#endif\n\n\tnetmask = 0;\n\tfor (i = 0; i < netbits; i++) {\n\t\tnetmask = (netmask << 1) | 1;\n\t}\n\tnetmask <<= (32 - netbits);\n\tnet.s_addr = htonl(netmask);\n\n\tif (inet_addr(ip) == INADDR_NONE) {\n\t\tfprintf(stderr, \"Invalid IP: %s!\\n\", ip);\n\t\treturn 1;\n\t}\n#ifndef WINDOWS32\n# ifdef FREEBSD\n\tdisplay_ip = other_ip; /* FreeBSD wants other IP as second IP */\n# else\n\tdisplay_ip = ip;\n# endif\n\tsnprintf(cmdline, sizeof(cmdline),\n\t\t\tIFCONFIGPATH \"ifconfig %s %s %s netmask %s\",\n\t\t\tif_name,\n\t\t\tip,\n\t\t\tdisplay_ip,\n\t\t\tinet_ntoa(net));\n\n\tfprintf(stderr, \"Setting IP of %s to %s\\n\", if_name, ip);\n#ifndef LINUX\n\tnetip.s_addr = inet_addr(ip);\n\tnetip.s_addr = netip.s_addr & net.s_addr;\n\tr = system(cmdline);\n\tif (r != 0) {\n\t\treturn r;\n\t} else {\n\n\t\tsnprintf(cmdline, sizeof(cmdline),\n\t\t\t\tROUTEPATH \"route add %s/%d %s\",\n\t\t\t\tinet_ntoa(netip), netbits, ip);\n\t}\n\tfprintf(stderr, \"Adding route %s/%d to %s\\n\", inet_ntoa(netip), netbits, ip);\n#endif\n\treturn system(cmdline);\n#else /* WINDOWS32 */\n\n\t/* Set device as connected */\n\tfprintf(stderr, \"Enabling interface '%s'\\n\", if_name);\n\tstatus = 1;\n\tr = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,\n\t\tsizeof(status), &status, sizeof(status), &len, NULL);\n\tif (!r) {\n\t\tfprintf(stderr, \"Failed to enable interface\\n\");\n\t\treturn -1;\n\t}\n\n\tif (inet_aton(ip, &addr)) {\n\t\tipdata[0] = (DWORD) addr.s_addr;   /* local ip addr */\n\t\tipdata[1] = net.s_addr & ipdata[0]; /* network addr */\n\t\tipdata[2] = (DWORD) net.s_addr;    /* netmask */\n\t} else {\n\t\treturn -1;\n\t}\n\n\t/* Tell ip/networkaddr/netmask to device for arp use */\n\tr = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata,\n\t\tsizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);\n\tif (!r) {\n\t\tfprintf(stderr, \"Failed to set interface in TUN mode\\n\");\n\t\treturn -1;\n\t}\n\n\t/* use netsh to set ip address */\n\tfprintf(stderr, \"Setting IP of interface '%s' to %s (can take a few seconds)...\\n\", if_name, ip);\n\tsnprintf(cmdline, sizeof(cmdline), \"netsh interface ip set address \\\"%s\\\" static %s %s\",\n\t\tif_name, ip, inet_ntoa(net));\n\treturn system(cmdline);\n#endif\n}\n\nint\ntun_setmtu(const unsigned mtu)\n{\n#ifndef WINDOWS32\n\tchar cmdline[512];\n\n\tif (mtu > 200 && mtu <= 1500) {\n\t\tsnprintf(cmdline, sizeof(cmdline),\n\t\t\t\tIFCONFIGPATH \"ifconfig %s mtu %u\",\n\t\t\t\tif_name,\n\t\t\t\tmtu);\n\n\t\tfprintf(stderr, \"Setting MTU of %s to %u\\n\", if_name, mtu);\n\t\treturn system(cmdline);\n\t} else {\n\t\twarn(\"MTU out of range: %u\\n\", mtu);\n\t}\n\n\treturn 1;\n#else /* WINDOWS32 */\n\n\treturn 0;\n#endif\n}\n\n"
  },
  {
    "path": "src/tun.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef _TUN_H_\n#define _TUN_H_\n\nint open_tun(const char *);\nvoid close_tun(int);\nint write_tun(int, char *, size_t);\nssize_t read_tun(int, char *, size_t);\nint tun_setip(const char *, const char *, int);\nint tun_setmtu(const unsigned);\n\n#endif /* _TUN_H_ */\n"
  },
  {
    "path": "src/user.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <time.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n#include <unistd.h>\n#include <fcntl.h>\n\n#ifdef WINDOWS32\n#include <winsock2.h>\n#else\n#include <netdb.h>\n#endif\n\n#include \"common.h\"\n#include \"encoding.h\"\n#include \"user.h\"\n\nstruct tun_user *users;\nunsigned usercount;\n\nint init_users(in_addr_t my_ip, int netbits)\n{\n\tint i;\n\tint skip = 0;\n\tchar newip[32];\n\n\tint maxusers;\n\n\tin_addr_t netmask = 0;\n\tstruct in_addr net;\n\tstruct in_addr ipstart;\n\n\tfor (i = 0; i < netbits; i++) {\n\t\tnetmask = (netmask << 1) | 1;\n\t}\n\tnetmask <<= (32 - netbits);\n\tnet.s_addr = htonl(netmask);\n\tipstart.s_addr = my_ip & net.s_addr;\n\n\tmaxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */\n\tusercount = MIN(maxusers, USERS);\n\n\tusers = calloc(usercount, sizeof(struct tun_user));\n\tfor (i = 0; i < usercount; i++) {\n\t\tin_addr_t ip;\n\t\tusers[i].id = i;\n\t\tsnprintf(newip, sizeof(newip), \"0.0.0.%d\", i + skip + 1);\n\t\tip = ipstart.s_addr + inet_addr(newip);\n\t\tif (ip == my_ip && skip == 0) {\n\t\t\t/* This IP was taken by iodined */\n\t\t\tskip++;\n\t\t\tsnprintf(newip, sizeof(newip), \"0.0.0.%d\", i + skip + 1);\n\t\t\tip = ipstart.s_addr + inet_addr(newip);\n\t\t}\n\t\tusers[i].tun_ip = ip;\n\t\tnet.s_addr = ip;\n\t\tusers[i].disabled = 0;\n\t\tusers[i].authenticated = 0;\n\t\tusers[i].authenticated_raw = 0;\n\t\tusers[i].options_locked = 0;\n\t\tusers[i].active = 0;\n \t\t/* Rest is reset on login ('V' packet) */\n\t}\n\n\treturn usercount;\n}\n\nconst char *users_get_first_ip(void)\n{\n\tstruct in_addr ip;\n\tip.s_addr = users[0].tun_ip;\n\treturn strdup(inet_ntoa(ip));\n}\n\nint find_user_by_ip(uint32_t ip)\n{\n\tint ret;\n\tint i;\n\n\tret = -1;\n\tfor (i = 0; i < usercount; i++) {\n\t\tif (users[i].active &&\n\t\t\tusers[i].authenticated &&\n\t\t\t!users[i].disabled &&\n\t\t\tusers[i].last_pkt + 60 > time(NULL) &&\n\t\t\tip == users[i].tun_ip) {\n\t\t\tret = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn ret;\n}\n\n/* If this returns true, then reading from tun device is blocked.\n   So only return true when all clients have at least one packet in\n   the outpacket-queue, so that sending back-to-back is possible\n   without going through another select loop.\n*/\nint all_users_waiting_to_send(void)\n{\n\ttime_t now;\n\tint ret;\n\tint i;\n\n\tret = 1;\n\tnow = time(NULL);\n\tfor (i = 0; i < usercount; i++) {\n\t\tif (users[i].active && !users[i].disabled &&\n\t\t\tusers[i].last_pkt + 60 > now &&\n\t\t\t((users[i].conn == CONN_RAW_UDP) ||\n\t\t\t((users[i].conn == CONN_DNS_NULL)\n#ifdef OUTPACKETQ_LEN\n\t\t\t\t&& users[i].outpacketq_filled < 1\n#else\n\t\t\t\t&& users[i].outpacket.len == 0\n#endif\n\t\t\t))) {\n\n\t\t\tret = 0;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn ret;\n}\n\nint find_available_user(void)\n{\n\tint ret = -1;\n\tint i;\n\tfor (i = 0; i < usercount; i++) {\n\t\t/* Not used at all or not used in one minute */\n\t\tif ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {\n\t\t\tusers[i].active = 1;\n\t\t\tusers[i].authenticated = 0;\n\t\t\tusers[i].authenticated_raw = 0;\n\t\t\tusers[i].options_locked = 0;\n\t\t\tusers[i].last_pkt = time(NULL);\n\t\t\tusers[i].fragsize = 4096;\n\t\t\tusers[i].conn = CONN_DNS_NULL;\n\t\t\tret = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn ret;\n}\n\nvoid user_switch_codec(int userid, const struct encoder *enc)\n{\n\tif (userid < 0 || userid >= usercount)\n\t\treturn;\n\n\tusers[userid].encoder = enc;\n}\n\nvoid user_set_conn_type(int userid, enum connection c)\n{\n\tif (userid < 0 || userid >= usercount)\n\t\treturn;\n\n\tif (c < CONN_RAW_UDP || c >= CONN_MAX)\n\t\treturn;\n\n\tusers[userid].conn = c;\n}\n\n"
  },
  {
    "path": "src/user.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __USER_H__\n#define __USER_H__\n\n#define USERS 16\n\n#define OUTPACKETQ_LEN 4\t\t/* Note: 16 users * 1 packet = 1MB */\n/* Undefine to have no queue for packets coming in from tun device, which may\n   lead to massive dropping in multi-user situations with high traffic. */\n\n#define DNSCACHE_LEN 4\n/* Undefine to disable. Should be less than 18; also see comments in iodined.c */\n\n\n#define QMEMPING_LEN 30\n/* Max advisable: 64k/2 = 32000. Total mem usage: QMEMPING_LEN * USERS * 6 bytes */\n\n#define QMEMDATA_LEN 15\n/* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */\n\nstruct tun_user {\n\tchar id;\n\tint active;\n\tint authenticated;\n\tint authenticated_raw;\n\tint options_locked;\n\tint disabled;\n\ttime_t last_pkt;\n\tint seed;\n\tin_addr_t tun_ip;\n\tstruct sockaddr_storage host;\n\tsocklen_t hostlen;\n\tstruct query q;\n\tstruct query q_sendrealsoon;\n\tint q_sendrealsoon_new;\n\tstruct packet inpacket;\n\tstruct packet outpacket;\n\tint outfragresent;\n\tconst struct encoder *encoder;\n\tchar downenc;\n\tint out_acked_seqno;\n\tint out_acked_fragment;\n\tint fragsize;\n\tenum connection conn;\n\tint lazy;\n\tunsigned char qmemping_cmc[QMEMPING_LEN * 4];\n\tunsigned short qmemping_type[QMEMPING_LEN];\n\tint qmemping_lastfilled;\n\tunsigned char qmemdata_cmc[QMEMDATA_LEN * 4];\n\tunsigned short qmemdata_type[QMEMDATA_LEN];\n\tint qmemdata_lastfilled;\n#ifdef OUTPACKETQ_LEN\n\tstruct packet outpacketq[OUTPACKETQ_LEN];\n\tint outpacketq_nexttouse;\n\tint outpacketq_filled;\n#endif\n#ifdef DNSCACHE_LEN\n\tstruct query dnscache_q[DNSCACHE_LEN];\n\tchar dnscache_answer[DNSCACHE_LEN][4096];\n\tint dnscache_answerlen[DNSCACHE_LEN];\n\tint dnscache_lastfilled;\n#endif\n};\n\nextern struct tun_user *users;\n\nint init_users(in_addr_t, int);\nconst char* users_get_first_ip(void);\nint find_user_by_ip(uint32_t);\nint all_users_waiting_to_send(void);\nint find_available_user(void);\nvoid user_switch_codec(int userid, const struct encoder *enc);\nvoid user_set_conn_type(int userid, enum connection c);\n\n#endif\n"
  },
  {
    "path": "src/util.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdio.h>\n#include \"common.h\"\n#include \"util.h\"\n\nchar *get_resolvconf_addr(void)\n{\n\tstatic char addr[257];\n\tchar *rv = NULL;\n#ifndef WINDOWS32\n\tchar buf[257];\n\tFILE *fp;\n#ifdef ANDROID\n\tfp = popen(\"getprop net.dns1\", \"r\");\n\tif (fp == NULL)\n\t\terr(1, \"getprop net.dns1 failed\");\n\tif (fgets(buf, sizeof(buf), fp) == NULL)\n\t\terr(1, \"read getprop net.dns1 failed\");\n\tif (sscanf(buf, \"%256s\", addr) == 1)\n\t\trv = addr;\n\tpclose(fp);\n#else\n\tif ((fp = fopen(\"/etc/resolv.conf\", \"r\")) == NULL)\n\t\terr(1, \"/etc/resolv.conf\");\n\n\twhile (feof(fp) == 0) {\n\t\tfgets(buf, sizeof(buf), fp);\n\n\t\tif (sscanf(buf, \"nameserver %256s\", addr) == 1) {\n\t\t\trv = addr;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tfclose(fp);\n#endif\n#else /* !WINDOWS32 */\n\tFIXED_INFO  *fixed_info;\n\tULONG       buflen;\n\tDWORD       ret;\n\n\tfixed_info = malloc(sizeof(FIXED_INFO));\n\tbuflen = sizeof(FIXED_INFO);\n\n\tif (GetNetworkParams(fixed_info, &buflen) == ERROR_BUFFER_OVERFLOW) {\n\t\t/* official ugly api workaround */\n\t\tfree(fixed_info);\n\t\tfixed_info = malloc(buflen);\n\t}\n\n\tret = GetNetworkParams(fixed_info, &buflen);\n\tif (ret == NO_ERROR) {\n\t\tstrncpy(addr, fixed_info->DnsServerList.IpAddress.String, sizeof(addr));\n\t\taddr[15] = 0;\n\t\trv = addr;\n\t}\n\tfree(fixed_info);\n#endif\n\treturn rv;\n}\n\n#ifdef OPENBSD\nvoid\nsocket_setrtable(int fd, int rtable)\n{\n#ifdef SO_RTABLE\n\tif (setsockopt (fd, IPPROTO_IP, SO_RTABLE, &rtable, sizeof(rtable)) == -1)\n\t\terr(1, \"Failed to set routing table %d\", rtable);\n#else\n\tfprintf(stderr, \"Routing domain support was not available at compile time.\\n\");\n#endif\n}\n#endif\n"
  },
  {
    "path": "src/util.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __UTIL_H__\n#define __UTIL_H__\n\nchar *get_resolvconf_addr(void);\nvoid socket_setrtable(int fd, int rtable);\n\n#endif\n"
  },
  {
    "path": "src/version.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef _VERSION_H_\n#define _VERSION_H_\n\n/* This is the version of the network protocol\n   It is usually equal to the latest iodine version number */\n#define PROTOCOL_VERSION 0x00000502\n\n#endif /* _VERSION_H_ */\n\n"
  },
  {
    "path": "src/windows.h",
    "content": "/*\r\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\r\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\r\n *\r\n * Permission to use, copy, modify, and/or distribute this software for any\r\n * purpose with or without fee is hereby granted, provided that the above\r\n * copyright notice and this permission notice appear in all copies.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r\n */\r\n\r\n#ifndef __FIX_WINDOWS_H__\r\n#define __FIX_WINDOWS_H__\r\n\r\ntypedef unsigned int in_addr_t;\r\n\r\n#include <winsock2.h>\r\n#include <windows.h>\r\n#include <windns.h>\r\n#include <ws2tcpip.h>\r\n#include <iphlpapi.h>\r\n\r\n/* Missing from the mingw headers */\r\n#ifndef DNS_TYPE_SRV\r\n# define DNS_TYPE_SRV 33\r\n#endif\r\n#ifndef DNS_TYPE_TXT\r\n# define DNS_TYPE_TXT 16\r\n#endif\r\n\r\n#define T_A DNS_TYPE_A\r\n#define T_NS DNS_TYPE_NS\r\n#define T_NULL DNS_TYPE_NULL\r\n#define T_CNAME DNS_TYPE_CNAME\r\n#define T_MX DNS_TYPE_MX\r\n#define T_TXT DNS_TYPE_TXT\r\n#define T_SOA DNS_TYPE_SOA\r\n#define T_SRV DNS_TYPE_SRV\r\n\r\n#define C_IN 1\r\n\r\n#define FORMERR 1\r\n#define SERVFAIL 2\r\n#define NXDOMAIN 3\r\n#define NOTIMP 4\r\n#define REFUSED 5\r\n\r\n#define sleep(seconds) Sleep((seconds)*1000)\r\n\r\ntypedef struct {\r\n\tunsigned id :16;\t/* query identification number */\r\n\t\t\t\t/* fields in third byte */\r\n\tunsigned rd :1;\t\t/* recursion desired */\r\n\tunsigned tc :1;\t\t/* truncated message */\r\n\tunsigned aa :1;\t\t/* authoritive answer */\r\n\tunsigned opcode :4;\t/* purpose of message */\r\n\tunsigned qr :1;\t\t/* response flag */\r\n\t\t\t\t/* fields in fourth byte */\r\n\tunsigned rcode :4;\t/* response code */\r\n\tunsigned cd: 1;\t\t/* checking disabled by resolver */\r\n\tunsigned ad: 1;\t\t/* authentic data from named */\r\n\tunsigned unused :1;\t/* unused bits (MBZ as of 4.9.3a3) */\r\n\tunsigned ra :1;\t\t/* recursion available */\r\n\t\t\t\t/* remaining bytes */\r\n\tunsigned qdcount :16;\t/* number of question entries */\r\n\tunsigned ancount :16;\t/* number of answer entries */\r\n\tunsigned nscount :16;\t/* number of authority entries */\r\n\tunsigned arcount :16;\t/* number of resource entries */\r\n} HEADER;\r\n\r\nstruct ip {\r\n\tunsigned int ip_hl:4;\t/* header length */\r\n\tunsigned int ip_v:4;\t/* version */\r\n\tu_char ip_tos;\t\t/* type of service */\r\n\tu_short ip_len;\t\t/* total length */\r\n\tu_short ip_id;\t\t/* identification */\r\n\tu_short ip_off;\t\t/* fragment offset field */\r\n#define IP_RF 0x8000\t\t/* reserved fragment flag */\r\n#define IP_DF 0x4000\t\t/* dont fragment flag */\r\n#define IP_MF 0x2000\t\t/* more fragments flag */\r\n#define IP_OFFMASK 0x1fff\t/* mask for fragmenting bits */\r\n\tu_char ip_ttl;\t\t/* time to live */\r\n\tu_char ip_p;\t\t/* protocol */\r\n\tu_short ip_sum;\t\t/* checksum */\r\n\tstruct in_addr ip_src, ip_dst; /* source and dest address */\r\n};\r\n\r\nDWORD WINAPI tun_reader(LPVOID arg);\r\nstruct tun_data {\r\n\tHANDLE tun;\r\n\tint sock;\r\n\tstruct sockaddr_storage addr;\r\n\tint addrlen;\r\n};\r\n\r\n/* No-op for now. */\r\n#define syslog(...)\r\n\r\n#endif\r\n"
  },
  {
    "path": "tests/Makefile",
    "content": "TEST = test\nOBJS = test.o base32.o base64.o common.o read.o dns.o encoding.o login.o user.o fw_query.o\nSRCOBJS = ../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\n\nOS = `uname | tr \"a-z\" \"A-Z\"`\n\nCHECK_PATH = /usr/local\nLDFLAGS = -L$(CHECK_PATH)/lib `pkg-config check --libs` -lpthread `sh ../src/osflags $(TARGETOS) link`\nCFLAGS = -std=c99 -g -Wall -D$(OS) `pkg-config check --cflags` -I../src -I$(CHECK_PATH)/include -pedantic `sh ../src/osflags $(TARGETOS) cflags`\n\nall: $(TEST)\n\t@LD_LIBRARY_PATH=${CHECK_PATH}/lib ./$(TEST)\n\n$(TEST): $(OBJS) $(SRCOBJS)\n\t@echo LD $(TEST)\n\t@$(CC) -o $@ $(SRCOBJS) $(OBJS) $(LDFLAGS)\n\n.c.o:\n\t@echo CC $<\n\t@$(CC) $(CFLAGS) -c $<\n\nclean:\n\t@echo \"Cleaning tests/\"\n\t@rm -f *~ *.core $(TEST) $(OBJS)\n\n"
  },
  {
    "path": "tests/base32.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n\n#include \"encoding.h\"\n#include \"test.h\"\n\n#define TUPLES 5\n\nstatic struct tuple\n{\n\tchar *a;\n\tchar *b;\n} testpairs[TUPLES] = {\n\t{ \"iodinetestingtesting\", \"nfxwi0lomv0gk21unfxgo3dfon0gs1th\" },\n\t{ \"abc123\", \"mfrggmjsgm\" },\n\t{ \"test\", \"orsxg3a\" },\n\t{ \"tst\", \"orzxi\" },\n\t{ \"\", \"\" },\n};\n\nSTART_TEST(test_base32_encode)\n{\n\tsize_t len;\n\tchar buf[4096];\n\tint val;\n\n\n\tlen = sizeof(buf);\n\tval = base32_ops.encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));\n\n\tck_assert(val == strlen(testpairs[_i].b));\n\tck_assert_str_eq(buf, testpairs[_i].b);\n}\nEND_TEST\n\nSTART_TEST(test_base32_decode)\n{\n\tsize_t len;\n\tchar buf[4096];\n\tint val;\n\n\tlen = sizeof(buf);\n\tval = base32_ops.decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));\n\n\tck_assert(val == strlen(testpairs[_i].a));\n\tck_assert_str_eq(buf, testpairs[_i].a);\n}\nEND_TEST\n\nSTART_TEST(test_base32_5to8_8to5)\n{\n\tint i;\n\tint c;\n\n\tfor (i = 0; i < 32; i++) {\n\t\tc = b32_5to8(i);\n\t\tck_assert(b32_8to5(c) == i);\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_base32_blksize)\n{\n\tsize_t rawlen;\n\tsize_t enclen;\n\tchar *rawbuf;\n\tchar *encbuf;\n\tint i;\n\tint val;\n\n\trawlen = base32_ops.blocksize_raw;\n\tenclen = base32_ops.blocksize_encoded;\n\n\trawbuf = malloc(rawlen + 16);\n\tencbuf = malloc(enclen + 16);\n\n\tfor (i = 0; i < rawlen; i++) {\n\t\trawbuf[i] = 'A';\n\t}\n\trawbuf[i] = 0;\n\n\tval = base32_ops.encode(encbuf, &enclen, rawbuf, rawlen);\n\n\tck_assert_msg(rawlen == 5, \"raw length was %zu not 5\", rawlen);\n\tck_assert_msg(enclen == 5, \"encoded %zu bytes, not 5\", enclen);\n\tck_assert_msg(val == 8, \"encoded string %s was length %d\", encbuf, val);\n\n\tmemset(rawbuf, 0, rawlen + 16);\n\n\tenclen = val;\n\tval = base32_ops.decode(rawbuf, &rawlen, encbuf, enclen);\n\n\tck_assert_msg(rawlen == 5, \"raw length was %zu not 5\", rawlen);\n\tck_assert_msg(val == 5, \"val was not 5 but %d\", val);\n\tfor (i = 0; i < rawlen; i++) {\n\t\tck_assert(rawbuf[i] == 'A');\n\t}\n}\nEND_TEST\n\nTCase *\ntest_base32_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Base32\");\n\ttcase_add_loop_test(tc, test_base32_encode, 0, TUPLES);\n\ttcase_add_loop_test(tc, test_base32_decode, 0, TUPLES);\n\ttcase_add_test(tc, test_base32_5to8_8to5);\n\ttcase_add_test(tc, test_base32_blksize);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/base64.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n\n#include \"encoding.h\"\n#include \"test.h\"\n\n#define TUPLES 5\n\nstatic struct tuple\n{\n\tchar *a;\n\tchar *b;\n} testpairs[TUPLES] = {\n\t{ \"iodinetestingtesting\", \"Aw8KAw4LDgvZDgLUz2rLC2rPBMC\" },\n\t{ \"abc1231\", \"ywjJmtiZmq\" },\n\t{\n\t  \"\\xFF\\xEF\\x7C\\xEF\\xAE\\x78\\xDF\\x6D\\x74\\xCF\\x2C\\x70\\xBE\\xEB\\x6C\\xAE\\xAA\\x68\"\n\t  \"\\x9E\\x69\\x64\\x8E\\x28\\x60\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\\x5D\\x65\\x54\\x4D\\x24\\x50\"\n\t  \"\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\\x1C\\x61\\x44\\x0C\\x20\\x40\\x3F\\x3F\\x3C\\xEF\\xAE\\x78\"\n\t  \"\\xDF\\x6D\\x74\\xCF\\x2C\\x70\\xBE\\xEB\\x6C\\xAE\\xAA\\x68\\x9E\\x69\\x64\\x8E\\x28\\x60\"\n\t  \"\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\\x5D\\x65\\x54\\x4D\\x24\\x50\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\"\n\t  \"\\x1C\\x61\\x44\\x0C\\x20\\x40\\xFF\\xEF\\x7C\\xEF\\xAE\\x78\\xDF\\x6D\\x74\\xCF\\x2C\\x70\"\n\t  \"\\xBE\\xEB\\x6C\\xAE\\xAA\\x68\\x9E\\x69\\x64\\x8E\\x28\\x60\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\"\n\t  \"\\x5D\\x65\\x54\\x4D\\x24\\x50\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\\x1C\\x61\\x44\\x0C\\x20\\x40\",\n\n\t  \"+9876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ\"\n\t  \"776543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654\"\n\t  \"3210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba\"\n\t},\n\t{\n\t  \"\\xFF\\xEF\\x7C\\xEF\\xAE\\x78\\xDF\\x6D\\x74\\xCF\\x2C\\x70\\xBE\\xEB\\x6C\\xAE\\xAA\\x68\"\n\t  \"\\x9E\\x69\\x64\\x8E\\x28\\x60\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\\x5D\\x65\\x54\\x4D\\x24\\x50\"\n\t  \"\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\\x1C\\x61\\x44\\x0C\\x20\\x40\\x3F\\x3F\\x3C\\xEF\\xAE\\x78\"\n\t  \"\\xDF\\x6D\\x74\\xCF\\x2C\\x70\\xBE\\xEB\\x6C\\xAE\\xA1\\x61\\x91\\x61\\x61\\x81\\x28\\x60\"\n\t  \"\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\\x5D\\x65\\x54\\x4D\\x24\\x50\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\"\n\t  \"\\x1C\\x61\\x44\\x0C\\x20\\x40\\xFF\\xEF\\x7C\\xEF\\xAE\\x78\\xDF\\x6D\\x74\\xCF\\x2C\\x70\"\n\t  \"\\xBE\\xEB\\x6C\\xAE\\xA1\\x61\\x91\\x61\\x61\\x81\\x28\\x60\\x7D\\xE7\\x5C\\x6D\\xA6\\x58\"\n\t  \"\\x5D\\x65\\x54\\x4D\\x24\\x50\\x3C\\xE3\\x4C\\x2C\\xA2\\x48\\x1C\\x61\\x44\\x0C\\x20\\x40\",\n\n\t  \"+9876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ\"\n\t  \"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654321\"\n\t  \"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba\"\n\t},\n\t{ \"\", \"\" }\n};\n\nSTART_TEST(test_base64_encode)\n{\n\tsize_t len;\n\tchar buf[4096];\n\tint val;\n\n\tlen = sizeof(buf);\n\tval = base64_ops.encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));\n\n\tck_assert(val == strlen(testpairs[_i].b));\n\tck_assert_str_eq(buf, testpairs[_i].b);\n}\nEND_TEST\n\nSTART_TEST(test_base64_decode)\n{\n\tsize_t len;\n\tchar buf[4096];\n\tint val;\n\n\tlen = sizeof(buf);\n\tval = base64_ops.decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));\n\n\tck_assert(val == strlen(testpairs[_i].a));\n\tck_assert_str_eq(buf, testpairs[_i].a);\n}\nEND_TEST\n\nSTART_TEST(test_base64_blksize)\n{\n\tsize_t rawlen;\n\tsize_t enclen;\n\tchar *rawbuf;\n\tchar *encbuf;\n\tint i;\n\tint val;\n\n\trawlen = base64_ops.blocksize_raw;\n\tenclen = base64_ops.blocksize_encoded;\n\n\trawbuf = malloc(rawlen + 16);\n\tencbuf = malloc(enclen + 16);\n\n\tfor (i = 0; i < rawlen; i++) {\n\t\trawbuf[i] = 'A';\n\t}\n\trawbuf[i] = 0;\n\n\tval = base64_ops.encode(encbuf, &enclen, rawbuf, rawlen);\n\n\tck_assert_msg(rawlen == 3, \"raw length was %zu not 3\", rawlen);\n\tck_assert_msg(enclen == 3, \"encoded %zu bytes, not 3\", enclen);\n\tck_assert_msg(val == 4, \"encoded string %s was length %d\", encbuf, val);\n\n\tmemset(rawbuf, 0, rawlen + 16);\n\n\tenclen = val;\n\tval = base64_ops.decode(rawbuf, &rawlen, encbuf, enclen);\n\n\tck_assert_msg(rawlen == 3, \"raw length was %zu not 3\", rawlen);\n\tck_assert(val == 3);\n\tfor (i = 0; i < rawlen; i++) {\n\t\tck_assert(rawbuf[i] == 'A');\n\t}\n}\nEND_TEST\n\nTCase *\ntest_base64_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Base64\");\n\ttcase_add_loop_test(tc, test_base64_encode, 0, TUPLES);\n\ttcase_add_loop_test(tc, test_base64_decode, 0, TUPLES);\n\ttcase_add_test(tc, test_base64_blksize);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/common.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <common.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <netdb.h>\n\nSTART_TEST(test_topdomain_ok)\n{\n\tchar *error = NULL;\n\n\tck_assert(check_topdomain(\"foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com\", 0, &error) == 0);\n\tck_assert(error == NULL);\n\t/* Allowing wildcard */\n\tck_assert(check_topdomain(\"foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com\", 1, &error) == 0);\n\tck_assert(error == NULL);\n\n\t/* Not allowed to start with dot */\n\tck_assert(check_topdomain(\".foo.0123456789.qwertyuiop.asdfghjkl.zxcvbnm.com\", 0, &error));\n\tck_assert_str_eq(\"Starts with a dot\", error);\n\n\t/* Test missing error msg ptr */\n\tck_assert(check_topdomain(\".foo\", 0, NULL));\n}\nEND_TEST\n\nSTART_TEST(test_topdomain_length)\n{\n\tchar *error;\n\n\t/* Test empty and too short */\n\tck_assert(check_topdomain(\"\", 0, &error));\n\tck_assert_str_eq(\"Too short (< 3)\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"a\", 0, &error));\n\tck_assert_str_eq(\"Too short (< 3)\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\".a\", 0, &error));\n\tck_assert_str_eq(\"Too short (< 3)\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"a.\", 0, &error));\n\tck_assert_str_eq(\"Too short (< 3)\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"ab\", 0, &error));\n\tck_assert_str_eq(\"Too short (< 3)\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"a.b\", 0, &error) == 0);\n\n\t/* Test too long (over 128, need rest of space for data) */\n\tck_assert(check_topdomain(\n\t\t\"abcd12345.abcd12345.abcd12345.abcd12345.abcd12345.\"\n\t\t\"abcd12345.abcd12345.abcd12345.abcd12345.abcd12345.\"\n\t\t\"abcd12345.abcd12345.foo129xxx\", 0, &error));\n\tck_assert_str_eq(\"Too long (> 128)\", error);\n\tck_assert(check_topdomain(\n\t\t\"abcd12345.abcd12345.abcd12345.abcd12345.abcd12345.\"\n\t\t\"abcd12345.abcd12345.abcd12345.abcd12345.abcd12345.\"\n\t\t\"abcd12345.abcd12345.foo128xx\", 0, &error) == 0);\n}\nEND_TEST\n\nSTART_TEST(test_topdomain_chunks)\n{\n\tchar *error;\n\n\t/* Must have at least one dot */\n\tck_assert(check_topdomain(\"abcde.gh\", 0, &error) == 0);\n\tck_assert(check_topdomain(\"abcdefgh\", 0, &error));\n\tck_assert_str_eq(\"No dots\", error);\n\n\t/* Not two consecutive dots */\n\tck_assert(check_topdomain(\"abc..defgh\", 0, &error));\n\tck_assert_str_eq(\"Consecutive dots\", error);\n\n\t/* Not end with a dots */\n\tck_assert(check_topdomain(\"abc.defgh.\", 0, &error));\n\tck_assert_str_eq(\"Ends with a dot\", error);\n\n\t/* No chunk longer than 63 chars */\n\tck_assert(check_topdomain(\"123456789012345678901234567890\"\n\t\t\"123456789012345678901234567890333.com\", 0, &error) == 0);\n\tck_assert(check_topdomain(\"123456789012345678901234567890\"\n\t\t\"1234567890123456789012345678904444.com\", 0, &error));\n\tck_assert_str_eq(\"Too long domain part (> 63)\", error);\n\n\tck_assert(check_topdomain(\"abc.123456789012345678901234567890\"\n\t\t\"123456789012345678901234567890333.com\", 0, &error) == 0);\n\tck_assert(check_topdomain(\"abc.123456789012345678901234567890\"\n\t\t\"1234567890123456789012345678904444.com\", 0, &error));\n\tck_assert_str_eq(\"Too long domain part (> 63)\", error);\n\n\tck_assert(check_topdomain(\"abc.123456789012345678901234567890\"\n\t\t\"123456789012345678901234567890333\", 0, &error) == 0);\n\tck_assert(check_topdomain(\"abc.123456789012345678901234567890\"\n\t\t\"1234567890123456789012345678904444\", 0, &error));\n\tck_assert_str_eq(\"Too long domain part (> 63)\", error);\n}\nEND_TEST\n\nSTART_TEST(test_topdomain_wild)\n{\n\tchar *error = NULL;\n\n\tck_assert(check_topdomain(\"*.a\", 0, &error) == 1);\n\tck_assert_str_eq(\"Contains illegal character (allowed: [a-zA-Z0-9-.])\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"*.a\", 1, &error) == 0);\n\tck_assert(error == NULL);\n\n\tck_assert(check_topdomain(\"b*.a\", 0, &error) == 1);\n\tck_assert_str_eq(\"Contains illegal character (allowed: [a-zA-Z0-9-.])\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"b*.a\", 1, &error) == 1);\n\tck_assert_str_eq(\"Wildcard (*) only allowed as first char\", error);\n\n\tck_assert(check_topdomain(\"*b.a\", 0, &error) == 1);\n\tck_assert_str_eq(\"Contains illegal character (allowed: [a-zA-Z0-9-.])\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"*b.a\", 1, &error) == 1);\n\tck_assert_str_eq(\"Wildcard (*) must be followed by dot\", error);\n\n\tck_assert(check_topdomain(\"*.*.a\", 0, &error) == 1);\n\tck_assert_str_eq(\"Contains illegal character (allowed: [a-zA-Z0-9-.])\", error);\n\terror = NULL;\n\tck_assert(check_topdomain(\"*.*.a\", 1, &error) == 1);\n\tck_assert_str_eq(\"Wildcard (*) only allowed as first char\", error);\n}\nEND_TEST\n\nSTART_TEST(test_query_datalen)\n{\n\tchar *topdomain = \"r.foo.com\";\n\t/* With data */\n\tck_assert(query_datalen(\"foobar.r.foo.com\", topdomain) == 7);\n\tck_assert(query_datalen(\"foobar.r.FoO.Com\", topdomain) == 7);\n\tck_assert(query_datalen(\"foo.bar.r.FoO.Com\", topdomain) == 8);\n\tck_assert(query_datalen(\".r.foo.com\", topdomain) == 1);\n\t/* Without data */\n\tck_assert(query_datalen(\"r.foo.com\", topdomain) == 0);\n\tck_assert(query_datalen(\"R.foo.com\", topdomain) == 0);\n\t/* Shorter query name */\n\tck_assert(query_datalen(\"foo.com\", topdomain) == -1);\n\t/* Mismatched query name */\n\tck_assert(query_datalen(\"b.foo.com\", topdomain) == -1);\n\tck_assert(query_datalen(\"*.foo.com\", topdomain) == -1);\n\t/* Query name overlaps topdomain, but is longer */\n\tck_assert(query_datalen(\"bar.foo.com\", topdomain) == -1);\n}\nEND_TEST\n\nSTART_TEST(test_query_datalen_wild)\n{\n\tchar *topdomain = \"*.foo.com\";\n\t/* With data */\n\tck_assert(query_datalen(\"foobar.a.foo.com\", topdomain) == 7);\n\tck_assert(query_datalen(\"foobar.r.FoO.Com\", topdomain) == 7);\n\tck_assert(query_datalen(\"foo.bar.r.FoO.Com\", topdomain) == 8);\n\tck_assert(query_datalen(\"foo.Ab.foo.cOm\", topdomain) == 4);\n\tck_assert(query_datalen(\"foo.Abcd.Foo.com\", topdomain) == 4);\n\tck_assert(query_datalen(\"***.STARs.foo.com\", topdomain) == 4);\n\tck_assert(query_datalen(\".a.foo.com\", topdomain) == 1);\n\tck_assert(query_datalen(\".ab.foo.com\", topdomain) == 1);\n\t/* Without data */\n\tck_assert(query_datalen(\"rr.foo.com\", topdomain) == 0);\n\tck_assert(query_datalen(\"b.foo.com\", topdomain) == 0);\n\tck_assert(query_datalen(\"B.foo.com\", topdomain) == 0);\n\t/* Shorter query name */\n\tck_assert(query_datalen(\"foo.com\", topdomain) == -1);\n\t/* Wildcard part of query name matching topdomain */\n\tck_assert(query_datalen(\"aa.*.foo.com\", topdomain) == -1);\n\t/* Mismatched query name */\n\tck_assert(query_datalen(\"bar.r.boo.com\", topdomain) == -1);\n}\nEND_TEST\n\nSTART_TEST(test_parse_format_ipv4)\n{\n\tchar *host = \"192.168.2.10\";\n\tchar *formatted;\n\tstruct sockaddr_storage addr;\n\tstruct sockaddr_in *v4addr;\n\tint addr_len;\n\n\taddr_len = get_addr(host, 53, AF_INET, 0, &addr);\n\tck_assert(addr_len == sizeof(struct sockaddr_in));\n\n\tv4addr = (struct sockaddr_in *) &addr;\n\tck_assert(v4addr->sin_addr.s_addr == htonl(0xc0a8020a));\n\tck_assert(v4addr->sin_port == htons(53));\n\n\tformatted = format_addr(&addr, addr_len);\n\tck_assert_str_eq(host, formatted);\n}\nEND_TEST\n\nSTART_TEST(test_parse_format_ipv4_listen_all)\n{\n\tchar *host = \"0.0.0.0\";\n\tchar *formatted;\n\tstruct sockaddr_storage addr;\n\tstruct sockaddr_in *v4addr;\n\tint addr_len;\n\n\taddr_len = get_addr(NULL, 53, AF_INET, AI_PASSIVE, &addr);\n\tck_assert(addr_len == sizeof(struct sockaddr_in));\n\n\tv4addr = (struct sockaddr_in *) &addr;\n\tck_assert(v4addr->sin_addr.s_addr == htonl(0x00000000));\n\tck_assert(v4addr->sin_port == htons(53));\n\n\tformatted = format_addr(&addr, addr_len);\n\tck_assert_str_eq(host, formatted);\n}\nEND_TEST\n\nSTART_TEST(test_parse_format_ipv6)\n{\n\tchar *host = \"2001:0db8:0505:0::123:0abc\";\n\tchar *compact = \"2001:db8:505::123:abc\";\n\tunsigned char v6_bits[] = {\n\t\t0x20, 0x01, 0x0d, 0xb8, 0x05, 0x05, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x0a, 0xbc,\n\t};\n\tchar *formatted;\n\tstruct sockaddr_storage addr;\n\tstruct sockaddr_in6 *v6addr;\n\tint addr_len;\n\n\taddr_len = get_addr(host, 53, AF_UNSPEC, 0, &addr);\n\tck_assert(addr_len == sizeof(struct sockaddr_in6));\n\n\tv6addr = (struct sockaddr_in6 *) &addr;\n\tck_assert(memcmp(&v6addr->sin6_addr, v6_bits, sizeof(v6_bits)) == 0);\n\tck_assert(v6addr->sin6_port == htons(53));\n\n\tformatted = format_addr(&addr, addr_len);\n\tck_assert_str_eq(compact, formatted);\n}\nEND_TEST\n\nSTART_TEST(test_parse_format_ipv4_mapped_ipv6)\n{\n\tchar *v4mapped = \"::FFFF:192.168.2.10\";\n\tchar *host = \"192.168.2.10\";\n\tunsigned char v6_bits[] = {\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x02, 0x0a,\n\t};\n\tchar *formatted;\n\tstruct sockaddr_storage addr;\n\tstruct sockaddr_in6 *v6addr;\n\tint addr_len;\n\n\taddr_len = get_addr(v4mapped, 53, AF_INET6, 0, &addr);\n\tck_assert(addr_len == sizeof(struct sockaddr_in6));\n\n\tv6addr = (struct sockaddr_in6 *) &addr;\n\tck_assert(memcmp(&v6addr->sin6_addr, v6_bits, sizeof(v6_bits)) == 0);\n\tck_assert(v6addr->sin6_port == htons(53));\n\n\t/* Format as IPv4 address */\n\tformatted = format_addr(&addr, addr_len);\n\tck_assert_str_eq(host, formatted);\n}\nEND_TEST\n\nSTART_TEST(test_get_addr_err)\n{\n\tchar *host = \"192.168.2.10\";\n\tstruct sockaddr_storage addr;\n\tint addr_len;\n\tint flags = AI_PASSIVE;\n\n\t/* Invalid host */\n\taddr_len = get_addr(NULL, -1, flags, 0, &addr);\n\tck_assert(addr_len == -1);\n\t/* Invalid port */\n\taddr_len = get_addr(host, -1, flags, 0, &addr);\n\tck_assert(addr_len == -1);\n\t/* Invalid flag */\n\taddr_len = get_addr(host, 53, flags | 0xFFF, 0, &addr);\n\tck_assert(addr_len == -1);\n\t/* Invalid addr */\n\taddr_len = get_addr(host, 53, flags, 0, (struct sockaddr_storage *)NULL);\n\tck_assert(addr_len == -1);\n}\nEND_TEST\n\nTCase *\ntest_common_create_tests(void)\n{\n\tTCase *tc;\n\tint sock;\n\n\ttc = tcase_create(\"Common\");\n\ttcase_add_test(tc, test_topdomain_ok);\n\ttcase_add_test(tc, test_topdomain_length);\n\ttcase_add_test(tc, test_topdomain_chunks);\n\ttcase_add_test(tc, test_topdomain_wild);\n\ttcase_add_test(tc, test_query_datalen);\n\ttcase_add_test(tc, test_query_datalen_wild);\n\ttcase_add_test(tc, test_parse_format_ipv4);\n\ttcase_add_test(tc, test_parse_format_ipv4_listen_all);\n\ttcase_add_test(tc, test_get_addr_err);\n\n\t/* Tests require IPv6 support */\n\tsock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);\n\tif (sock >= 0) {\n\t\tclose(sock);\n\t\ttcase_add_test(tc, test_parse_format_ipv6);\n\t\ttcase_add_test(tc, test_parse_format_ipv4_mapped_ipv6);\n\t}\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/dns.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/stat.h>\n#include <arpa/nameser.h>\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n\n#include \"common.h\"\n#include \"dns.h\"\n#include \"encoding.h\"\n#include \"test.h\"\n\nstatic void dump_packet(char *, size_t);\n\nstatic char query_packet[] =\n\t\"\\x05\\x39\\x01\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x2D\\x41\\x6A\\x62\\x63\"\n\t\"\\x75\\x79\\x74\\x63\\x70\\x65\\x62\\x30\\x67\\x71\\x30\\x6C\\x74\\x65\\x62\\x75\\x78\"\n\t\"\\x67\\x69\\x64\\x75\\x6E\\x62\\x73\\x73\\x61\\x33\\x64\\x66\\x6F\\x6E\\x30\\x63\\x61\"\n\t\"\\x7A\\x64\\x62\\x6F\\x72\\x71\\x71\\x04\\x6B\\x72\\x79\\x6F\\x02\\x73\\x65\\x00\\x00\"\n\t\"\\x0A\\x00\\x01\\x00\\x00\\x29\\x10\\x00\\x00\\x00\\x80\\x00\\x00\\x00\";\n\nstatic char answer_packet[] =\n\t\"\\x05\\x39\\x84\\x00\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x00\\x05\\x73\\x69\\x6C\\x6C\"\n\t\"\\x79\\x04\\x68\\x6F\\x73\\x74\\x02\\x6F\\x66\\x06\\x69\\x6F\\x64\\x69\\x6E\\x65\\x04\"\n\t\"\\x63\\x6F\\x64\\x65\\x04\\x6B\\x72\\x79\\x6F\\x02\\x73\\x65\\x00\\x00\\x0A\\x00\\x01\"\n\t\"\\xC0\\x0C\\x00\\x0A\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x23\\x74\\x68\\x69\\x73\\x20\"\n\t\"\\x69\\x73\\x20\\x74\\x68\\x65\\x20\\x6D\\x65\\x73\\x73\\x61\\x67\\x65\\x20\\x74\\x6F\"\n\t\"\\x20\\x62\\x65\\x20\\x64\\x65\\x6C\\x69\\x76\\x65\\x72\\x65\\x64\";\n\nstatic char answer_packet_high_trans_id[] =\n\t\"\\x85\\x39\\x84\\x00\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x00\\x05\\x73\\x69\\x6C\\x6C\"\n\t\"\\x79\\x04\\x68\\x6F\\x73\\x74\\x02\\x6F\\x66\\x06\\x69\\x6F\\x64\\x69\\x6E\\x65\\x04\"\n\t\"\\x63\\x6F\\x64\\x65\\x04\\x6B\\x72\\x79\\x6F\\x02\\x73\\x65\\x00\\x00\\x0A\\x00\\x01\"\n\t\"\\xC0\\x0C\\x00\\x0A\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x23\\x74\\x68\\x69\\x73\\x20\"\n\t\"\\x69\\x73\\x20\\x74\\x68\\x65\\x20\\x6D\\x65\\x73\\x73\\x61\\x67\\x65\\x20\\x74\\x6F\"\n\t\"\\x20\\x62\\x65\\x20\\x64\\x65\\x6C\\x69\\x76\\x65\\x72\\x65\\x64\";\nstatic char *msgData = \"this is the message to be delivered\";\nstatic char *topdomain = \"kryo.se\";\n\nstatic char *innerData = \"HELLO this is the test data\";\n\nSTART_TEST(test_encode_query)\n{\n\tchar buf[512];\n\tchar resolv[512];\n\tstruct query q;\n\tconst struct encoder *enc;\n\tchar *d;\n\tsize_t len;\n\tsize_t enclen;\n\tint ret;\n\n\tenclen = sizeof(resolv);\n\tmemset(&buf, 0, sizeof(buf));\n\tmemset(&resolv, 0, sizeof(resolv));\n\tmemset(&q, 0, sizeof(struct query));\n\tq.type = T_NULL;\n\tq.id = 1337;\n\td = resolv;\n\tenc = &base32_ops;\n\n\t*d++ = 'A';\n\tenc->encode(d, &enclen, innerData, strlen(innerData));\n\td = resolv + strlen(resolv);\n\tif (*d != '.') {\n\t\t*d++ = '.';\n\t}\n\tstrcpy(d, topdomain);\n\tlen = sizeof(buf);\n\tret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));\n\tlen = sizeof(query_packet) - 1; /* Skip extra null character */\n\n\tif (strncmp(query_packet, buf, sizeof(query_packet)) || ret != len) {\n\t\tprintf(\"\\n\");\n\t\tdump_packet(query_packet, len);\n\t\tdump_packet(buf, ret);\n\t}\n\tck_assert_msg(strncmp(query_packet, buf, sizeof(query_packet)) == 0,\n\t\t\"Did not compile expected packet\");\n\tck_assert_msg(ret == len,\n\t\t\"Bad packet length: %d, expected %zu\", ret, len);\n}\nEND_TEST\n\nSTART_TEST(test_decode_query)\n{\n\tchar buf[512];\n\tchar *domain;\n\tstruct query q;\n\tconst struct encoder *enc;\n\tsize_t len;\n\n\tmemset(&q, 0, sizeof(struct query));\n\tmemset(&buf, 0, sizeof(buf));\n\tq.id = 0;\n\tlen = sizeof(query_packet) - 1;\n\tenc = &base32_ops;\n\n\tdns_decode(buf, sizeof(buf), &q, QR_QUERY, query_packet, len);\n\tdomain = strstr(q.name, topdomain);\n\tlen = sizeof(buf);\n\tunpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);\n\n\tck_assert_msg(strncmp(buf, innerData, strlen(innerData)) == 0,\n\t\t\"Did not extract expected host: '%s'\", buf);\n\tck_assert_msg(strlen(buf) == strlen(innerData),\n\t\t\"Bad host length: %zu, expected %zu: '%s'\",\n\t\tstrlen(buf), strlen(innerData), buf);\n}\nEND_TEST\n\nSTART_TEST(test_encode_response)\n{\n\tchar buf[512];\n\tchar *host = \"silly.host.of.iodine.code.kryo.se\";\n\tstruct query q;\n\tint len;\n\tint ret;\n\n\tlen = sizeof(buf);\n\tmemset(&buf, 0, sizeof(buf));\n\tmemset(&q, 0, sizeof(struct query));\n\tstrncpy(q.name, host, strlen(host));\n\tq.type = T_NULL;\n\tq.id = 1337;\n\n\tret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData));\n\tlen = sizeof(answer_packet) - 1; /* Skip extra null character */\n\n\tck_assert_msg(strncmp(answer_packet, buf, sizeof(answer_packet)) == 0,\n\t\t\"Did not compile expected packet\");\n\tck_assert_msg(ret == len,\n\t\t\"Bad packet length: %d, expected %d\", ret, len);\n}\nEND_TEST\n\nSTART_TEST(test_decode_response)\n{\n\tchar buf[512];\n\tstruct query q;\n\tint len;\n\tint ret;\n\n\tlen = sizeof(buf);\n\tmemset(&buf, 0, sizeof(buf));\n\n\tret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet, sizeof(answer_packet)-1);\n\tck_assert_msg(ret == strlen(msgData),\n\t\t\"Bad data length: %d, expected %zu\", ret, strlen(msgData));\n\tck_assert_msg(strncmp(msgData, buf, strlen(msgData)) == 0,\n\t\t\"Did not extract expected data\");\n\tck_assert(q.id == 0x0539);\n}\nEND_TEST\n\nSTART_TEST(test_decode_response_with_high_trans_id)\n{\n\tchar buf[512];\n\tstruct query q;\n\tint len;\n\tint ret;\n\n\tlen = sizeof(buf);\n\tmemset(&buf, 0, sizeof(buf));\n\n\tret = dns_decode(buf, len, &q, QR_ANSWER, answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)-1);\n\tck_assert_msg(ret == strlen(msgData),\n\t\t\"Bad data length: %d, expected %zu\", ret, strlen(msgData));\n\tck_assert_msg(strncmp(msgData, buf, strlen(msgData)) == 0,\n\t\t\"Did not extract expected data\");\n\tck_assert_msg(q.id == 0x8539,\n\t\t\"q.id was %08X instead of %08X!\", q.id, 0x8539);\n}\nEND_TEST\n\nSTART_TEST(test_get_id_short_packet)\n{\n\tchar buf[5];\n\tint len;\n\tunsigned short id;\n\n\tlen = sizeof(buf);\n\tmemset(&buf, 5, sizeof(buf));\n\n\tid = dns_get_id(buf, len);\n\tck_assert(id == 0);\n}\nEND_TEST\n\nSTART_TEST(test_get_id_low)\n{\n\tunsigned short id;\n\n\tid = dns_get_id(answer_packet, sizeof(answer_packet));\n\tck_assert(id == 1337);\n}\nEND_TEST\n\nSTART_TEST(test_get_id_high)\n{\n\tunsigned short id;\n\n\tid = dns_get_id(answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id));\n\tck_assert(id == 0x8539);\n}\nEND_TEST\n\nstatic void\ndump_packet(char *buf, size_t len)\n{\n\tint pos;\n\n\tfor (pos = 0; pos < len; pos++) {\n\t\tprintf(\"\\\\x%02X\", (unsigned char) buf[pos]);\n\t}\n\tprintf(\"\\n\");\n\tfor (pos = 0; pos < len; pos++) {\n\t\tif (isalnum((unsigned char) buf[pos])) {\n\t\t\tprintf(\" %c  \", (unsigned char) buf[pos]);\n\t\t} else {\n\t\t\tprintf(\"    \");\n\t\t}\n\t}\n\tprintf(\"\\n\");\n}\n\nTCase *\ntest_dns_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Dns\");\n\ttcase_add_test(tc, test_encode_query);\n\ttcase_add_test(tc, test_decode_query);\n\ttcase_add_test(tc, test_encode_response);\n\ttcase_add_test(tc, test_decode_response);\n\ttcase_add_test(tc, test_decode_response_with_high_trans_id);\n\ttcase_add_test(tc, test_get_id_short_packet);\n\ttcase_add_test(tc, test_get_id_low);\n\ttcase_add_test(tc, test_get_id_high);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/encoding.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"encoding.h\"\n#include \"test.h\"\n\n#define TUPLES 4\n\nstatic struct tuple\n{\n\tchar *a;\n\tchar *b;\n} dottests[] = {\n\t{ \"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n\t  \"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaa\"},\n\t{ \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n\t  \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\"},\n\t{ \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n\t  \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\n\t{ \"abc123\", \"abc123\" },\n\t{ NULL, NULL }\n};\n\nSTART_TEST(test_inline_dotify)\n{\n\tchar temp[1024];\n\tchar *b;\n\n\tmemset(temp, 0, sizeof(temp));\n\tstrcpy(temp, dottests[_i].a);\n\tb = temp;\n\tinline_dotify(b, sizeof(temp));\n\n\tck_assert_str_eq(dottests[_i].b, temp);\n}\nEND_TEST\n\nSTART_TEST(test_inline_undotify)\n{\n\tchar temp[1024];\n\tchar *b;\n\n\tmemset(temp, 0, sizeof(temp));\n\tstrcpy(temp, dottests[_i].b);\n\tb = temp;\n\tinline_undotify(b, sizeof(temp));\n\n\tck_assert_str_eq(dottests[_i].a, temp);\n}\nEND_TEST\n\nSTART_TEST(test_build_hostname)\n{\n\tchar data[256];\n\tchar buf[1024];\n\tchar *topdomain = \"a.c\";\n\tint buflen;\n\tint i;\n\n\tfor (i = 0; i < sizeof(data); i++) {\n\t\tdata[i] = i & 0xFF;\n\t}\n\n\tbuflen = sizeof(buf);\n\n\tfor (i = 1; i < sizeof(data); i++) {\n\t\tint len = build_hostname(buf, buflen, data, i, topdomain, &base32_ops, sizeof(buf));\n\n\t\tck_assert(len <= i);\n\t\tck_assert_msg(strstr(buf, \"..\") == NULL,\n\t\t\t\"Found double dots when encoding data len %d! buf: %s\", i, buf);\n\t}\n}\nEND_TEST\n\nTCase *\ntest_encoding_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Encoding\");\n\ttcase_add_loop_test(tc, test_inline_dotify, 0, TUPLES);\n\ttcase_add_loop_test(tc, test_inline_undotify, 0, TUPLES);\n\ttcase_add_test(tc, test_build_hostname);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/fw_query.c",
    "content": "/*\n * Copyright (c) 2009-2014 Erik Ekman <yarrick@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n\n#include \"fw_query.h\"\n#include \"test.h\"\n\nSTART_TEST(test_fw_query_simple)\n{\n\tstruct fw_query q;\n\tstruct fw_query *qp;\n\n\tq.addrlen = 33;\n\tq.id = 0x848A;\n\n\tfw_query_init();\n\n\t/* Test empty cache */\n\tfw_query_get(0x848A, &qp);\n\tck_assert(qp == NULL);\n\n\tfw_query_put(&q);\n\n\t/* Test cache with one entry */\n\tfw_query_get(0x848A, &qp);\n\tck_assert(qp->addrlen == q.addrlen);\n\tck_assert(qp->id == q.id);\n}\nEND_TEST\n\nSTART_TEST(test_fw_query_edge)\n{\n\tstruct fw_query q;\n\tstruct fw_query *qp;\n\tint i;\n\n\tfw_query_init();\n\n\tq.addrlen = 33;\n\tq.id = 0x848A;\n\tfw_query_put(&q);\n\n\tfor (i = 1; i < FW_QUERY_CACHE_SIZE; i++) {\n\t\tq.addrlen++;\n\t\tq.id++;\n\t\tfw_query_put(&q);\n\t}\n\n\t/* The query should still be cached */\n\tfw_query_get(0x848A, &qp);\n\tck_assert(qp->addrlen == 33);\n\tck_assert(qp->id == 0x848A);\n\n\tq.addrlen++;\n\tq.id++;\n\tfw_query_put(&q);\n\n\t/* but now it is overwritten */\n\tfw_query_get(0x848A, &qp);\n\tck_assert(qp == NULL);\n}\nEND_TEST\n\nTCase *\ntest_fw_query_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Forwarded query\");\n\ttcase_add_test(tc, test_fw_query_simple);\n\ttcase_add_test(tc, test_fw_query_edge);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/login.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <string.h>\n\n#include \"test.h\"\n#include \"login.h\"\n\nSTART_TEST(test_login_hash)\n{\n\tchar ans[16];\n\tchar good[] = \"\\x2A\\x8A\\x12\\xB4\\xE0\\x42\\xEE\\xAB\\xD0\\x19\\x17\\x1E\\x44\\xA0\\x88\\xCD\";\n\tchar pass[32] = \"iodine is the shit\";\n\tint len;\n\tint seed;\n\n\tlen = sizeof(ans);\n\tseed = 15;\n\n\tmemset(ans, 0, sizeof(ans));\n\tlogin_calculate(ans, len, pass, seed);\n\tck_assert(strncmp(ans, good, len) == 0);\n}\nEND_TEST\n\nSTART_TEST(test_login_hash_short)\n{\n\tchar ans[8];\n\tchar check[sizeof(ans)];\n\tchar pass[32] = \"iodine is the shit\";\n\tint len;\n\tint seed;\n\n\tlen = sizeof(ans);\n\tseed = 15;\n\n\tmemset(ans, 0, sizeof(ans));\n\tmemset(check, 0, sizeof(check));\n\n\t/* If len < 16, it should do nothing */\n\tlogin_calculate(ans, len, pass, seed);\n\tck_assert(memcmp(ans, check, sizeof(ans)) == 0);\n}\nEND_TEST\n\nTCase *\ntest_login_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Login\");\n\ttcase_add_test(tc, test_login_hash);\n\ttcase_add_test(tc, test_login_hash_short);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/read.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/stat.h>\n#include <arpa/nameser.h>\n#ifdef DARWIN\n#define BIND_8_COMPAT\n#include <arpa/nameser_compat.h>\n#endif\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <check.h>\n\n#include \"common.h\"\n#include \"encoding.h\"\n#include \"dns.h\"\n#include \"read.h\"\n#include \"test.h\"\n\nSTART_TEST(test_read_putshort)\n{\n\tunsigned short k;\n\tunsigned short l;\n\tchar* p;\n\tint i;\n\n\tfor (i = 0; i < 65536; i++) {\n\t\tp = (char*)&k;\n\t\tputshort(&p, i);\n\t\tck_assert_msg(ntohs(k) == i,\n\t\t\t\t\"Bad value on putshort for %d: %d != %d\",\n\t\t\t\t\ti, ntohs(k), i);\n\n\t\tp = (char*)&k;\n\t\treadshort(NULL, &p, &l);\n\t\tck_assert_msg(l == i,\n\t\t\t\t\"Bad value on readshort for %d: %d != %d\",\n\t\t\t\t\ti, l, i);\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_read_putlong)\n{\n\tuint32_t k;\n\tuint32_t l;\n\tchar* p;\n\tint i;\n\tint j;\n\n\tfor (i = 0; i < 32; i++) {\n\t\tp = (char*)&k;\n\t\tj = 0xf << i;\n\n\t\tputlong(&p, j);\n\n\t\tck_assert_msg(ntohl(k) == j,\n\t\t\t\t\"Bad value on putlong for %d: %d != %d\", i, ntohl(j), j);\n\n\t\tp = (char*)&k;\n\t\treadlong(NULL, &p, &l);\n\n\t\tck_assert_msg(l == j,\n\t\t\t\t\"Bad value on readlong for %d: %d != %d\", i, l, j);\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_read_name_empty_loop)\n{\n\tunsigned char emptyloop[] = {\n\t\t'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\tmemset(buf, 0, sizeof(buf));\n\tdata = (char*) emptyloop + sizeof(HEADER);\n\tbuf[1023] = 'A';\n\trv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);\n\tck_assert(rv == 0);\n\tck_assert(buf[1023] == 'A');\n}\nEND_TEST\n\nSTART_TEST(test_read_name_inf_loop)\n{\n\tunsigned char infloop[] = {\n\t\t'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\tmemset(buf, 0, sizeof(buf));\n\tdata = (char*) infloop + sizeof(HEADER);\n\tbuf[4] = '\\a';\n\trv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);\n\tck_assert(rv == 3);\n\tck_assert(buf[4] == '\\a');\n}\nEND_TEST\n\nSTART_TEST(test_read_name_longname)\n{\n\tunsigned char longname[] =\n\t\t\"AA\\x81\\x80\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA\"\n\t\t\"\\x00\\x00\\x01\\x00\\x01\";\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\tmemset(buf, 0, sizeof(buf));\n\tdata = (char*) longname + sizeof(HEADER);\n\tbuf[256] = '\\a';\n\trv = readname((char*) longname, sizeof(longname), &data, buf, 256);\n\tck_assert(rv == 256);\n\tck_assert(buf[256] == '\\a');\n}\nEND_TEST\n\nSTART_TEST(test_read_name_onejump)\n{\n\tunsigned char onejump[] =\n\t\t\"AA\\x81\\x80\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\"\n\t\t\"\\x02hh\\xc0\\x15\\x00\\x01\\x00\\x01\\x05zBCDE\\x00\";\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\tmemset(buf, 0, sizeof(buf));\n\tdata = (char*) onejump + sizeof(HEADER);\n\trv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);\n\tck_assert(rv == 9);\n}\nEND_TEST\n\nSTART_TEST(test_read_name_badjump_start)\n{\n\tunsigned char badjump[] = {\n\t\t'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };\n\tunsigned char *jumper;\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\t/* This test uses malloc to cause segfault if jump is executed */\n\tmemset(buf, 0, sizeof(buf));\n\tjumper = malloc(sizeof(badjump));\n\tif (jumper) {\n\t\tmemcpy(jumper, badjump, sizeof(badjump));\n\t\tdata = (char*) jumper + sizeof(HEADER);\n\t\trv = readname((char*) jumper, sizeof(badjump), &data, buf, 256);\n\n\t\tck_assert(rv == 0);\n\t\tck_assert(buf[0] == 0);\n\t}\n\tfree(jumper);\n}\nEND_TEST\n\nSTART_TEST(test_read_name_badjump_second)\n{\n\tunsigned char badjump2[] = {\n\t\t'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };\n\tunsigned char *jumper;\n\tchar buf[1024];\n\tchar *data;\n\tint rv;\n\n\t/* This test uses malloc to cause segfault if jump is executed */\n\tmemset(buf, 0, sizeof(buf));\n\tjumper = malloc(sizeof(badjump2));\n\tif (jumper) {\n\t\tmemcpy(jumper, badjump2, sizeof(badjump2));\n\t\tdata = (char*) jumper + sizeof(HEADER);\n\t\trv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);\n\n\t\tck_assert(rv == 4);\n\t\tck_assert_str_eq(\"BA.\", buf);\n\t}\n\tfree(jumper);\n}\nEND_TEST\n\nSTART_TEST(test_putname)\n{\n\tchar out[] = \"\\x06\" \"BADGER\\x06\" \"BADGER\\x04\" \"KRYO\\x02\" \"SE\\x00\";\n\tchar buf[256];\n\tchar *domain = \"BADGER.BADGER.KRYO.SE\";\n\tchar *b;\n\tint ret;\n\n\tmemset(buf, 0, 256);\n\tb = buf;\n\tret = putname(&b, 256, domain);\n\n\tck_assert(ret == strlen(domain) + 1);\n\tck_assert_msg(strncmp(buf, out, ret) == 0, \"Happy flow failed\");\n}\nEND_TEST\n\nSTART_TEST(test_putname_nodot)\n{\n\tchar buf[256];\n\tchar *nodot =\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\tchar *b;\n\tint ret;\n\n\tmemset(buf, 0, 256);\n\tb = buf;\n\tret = putname(&b, 256, nodot);\n\n\tck_assert(ret == -1);\n\tck_assert(b == buf);\n}\nEND_TEST\n\nSTART_TEST(test_putname_toolong)\n{\n\tchar buf[256];\n\tchar *toolong =\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\"\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.\";\n\tchar *b;\n\tint ret;\n\n\tmemset(buf, 0, 256);\n\tb = buf;\n\tret = putname(&b, 256, toolong);\n\n\tck_assert(ret == -1);\n\tck_assert(b == buf);\n}\nEND_TEST\n\n\nTCase *\ntest_read_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"Read\");\n\ttcase_set_timeout(tc, 60);\n\ttcase_add_test(tc, test_read_putshort);\n\ttcase_add_test(tc, test_read_putlong);\n\ttcase_add_test(tc, test_read_name_empty_loop);\n\ttcase_add_test(tc, test_read_name_inf_loop);\n\ttcase_add_test(tc, test_read_name_longname);\n\ttcase_add_test(tc, test_read_name_onejump);\n\ttcase_add_test(tc, test_read_name_badjump_start);\n\ttcase_add_test(tc, test_read_name_badjump_second);\n\ttcase_add_test(tc, test_putname);\n\ttcase_add_test(tc, test_putname_nodot);\n\ttcase_add_test(tc, test_putname_toolong);\n\n\treturn tc;\n}\n"
  },
  {
    "path": "tests/test.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"test.h\"\n\nint\nmain(void)\n{\n\tSRunner *runner;\n\tSuite *iodine;\n\tTCase *test;\n\tint failed;\n\n\tiodine = suite_create(\"iodine\");\n\n\ttest = test_base32_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n\ttest = test_base64_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n\ttest = test_common_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n\ttest = test_dns_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n\ttest = test_encoding_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n \ttest = test_read_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n \ttest = test_login_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n \ttest = test_user_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n \ttest = test_fw_query_create_tests();\n\tsuite_add_tcase(iodine, test);\n\n\trunner = srunner_create(iodine);\n\tsrunner_run_all(runner, CK_NORMAL);\n\tfailed = srunner_ntests_failed(runner);\n\n\tsrunner_free(runner);\n\n\treturn (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test.h",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#ifndef __TEST_H__\n#define __TEST_H__\n\nTCase *test_base32_create_tests(void);\nTCase *test_base64_create_tests(void);\nTCase *test_common_create_tests(void);\nTCase *test_dns_create_tests(void);\nTCase *test_encoding_create_tests(void);\nTCase *test_read_create_tests(void);\nTCase *test_login_create_tests(void);\nTCase *test_user_create_tests(void);\nTCase *test_fw_query_create_tests(void);\n\nchar *va_str(const char *, ...);\n\n#if (CHECK_MAJOR_VERSION == 0 && \\\n\t((CHECK_MINOR_VERSION == 9 && CHECK_MICRO_VERSION < 2) || \\\n\t (CHECK_MINOR_VERSION < 9)))\n#define tcase_set_timeout(...)\n#endif\n\n#endif\n"
  },
  {
    "path": "tests/user.c",
    "content": "/*\n * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,\n * 2006-2009 Bjorn Andersson <flex@kryo.se>\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <check.h>\n#include <stdio.h>\n#include <string.h>\n#include <time.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\n#include \"common.h\"\n#include \"encoding.h\"\n#include \"user.h\"\n#include \"test.h\"\n\nSTART_TEST(test_init_users)\n{\n\tin_addr_t ip;\n\tchar givenip[16];\n\tint i;\n\tint count;\n\n\tip = inet_addr(\"127.0.0.1\");\n\tcount = init_users(ip, 27);\n\tfor (i = 0; i < count; i++) {\n\t\tck_assert(users[i].id == i);\n\t\tck_assert(users[i].q.id == 0);\n\t\tck_assert(users[i].inpacket.len == 0);\n\t\tck_assert(users[i].outpacket.len == 0);\n\t\tsnprintf(givenip, sizeof(givenip), \"127.0.0.%d\", i + 2);\n\t\tck_assert(users[i].tun_ip == inet_addr(givenip));\n\t}\n}\nEND_TEST\n\nSTART_TEST(test_find_user_by_ip)\n{\n\tin_addr_t ip;\n\tunsigned int testip;\n\n\tip = inet_addr(\"127.0.0.1\");\n\tinit_users(ip, 27);\n\tusers[0].conn = CONN_DNS_NULL;\n\n\ttestip = (unsigned int) inet_addr(\"10.0.0.1\");\n\tck_assert(find_user_by_ip(testip) == -1);\n\n\ttestip = (unsigned int) inet_addr(\"127.0.0.2\");\n\tck_assert(find_user_by_ip(testip) == -1);\n\n\tusers[0].active = 1;\n\n\ttestip = (unsigned int) inet_addr(\"127.0.0.2\");\n\tck_assert(find_user_by_ip(testip) == -1);\n\n\tusers[0].last_pkt = time(NULL);\n\n\ttestip = (unsigned int) inet_addr(\"127.0.0.2\");\n\tck_assert(find_user_by_ip(testip) == -1);\n\n\tusers[0].authenticated = 1;\n\n\ttestip = (unsigned int) inet_addr(\"127.0.0.2\");\n\tck_assert(find_user_by_ip(testip) == 0);\n}\nEND_TEST\n\nSTART_TEST(test_all_users_waiting_to_send)\n{\n\tin_addr_t ip;\n\n\tip = inet_addr(\"127.0.0.1\");\n\tinit_users(ip, 27);\n\n\tck_assert(all_users_waiting_to_send() == 1);\n\n\tusers[0].conn = CONN_DNS_NULL;\n\tusers[0].active = 1;\n\n\tck_assert(all_users_waiting_to_send() == 1);\n\n\tusers[0].last_pkt = time(NULL);\n\tusers[0].outpacket.len = 0;\n\n\tck_assert(all_users_waiting_to_send() == 0);\n\n#ifdef OUTPACKETQ_LEN\n\tusers[0].outpacketq_filled = 1;\n#else\n\tusers[0].outpacket.len = 44;\n#endif\n\n\tck_assert(all_users_waiting_to_send() == 1);\n}\nEND_TEST\n\nSTART_TEST(test_find_available_user)\n{\n\tin_addr_t ip;\n\tint i;\n\n\tip = inet_addr(\"127.0.0.1\");\n\tinit_users(ip, 27);\n\n\tfor (i = 0; i < USERS; i++) {\n\t\tusers[i].authenticated = 1;\n\t\tusers[i].authenticated_raw = 1;\n\t\tck_assert(find_available_user() == i);\n\t\tck_assert(users[i].authenticated == 0);\n\t\tck_assert(users[i].authenticated_raw == 0);\n\t}\n\n\tfor (i = 0; i < USERS; i++) {\n\t\tck_assert(find_available_user() == -1);\n\t}\n\n\tusers[3].active = 0;\n\n\tck_assert(find_available_user() == 3);\n\tck_assert(find_available_user() == -1);\n\n\tusers[3].last_pkt = 55;\n\n\tck_assert(find_available_user() == 3);\n\tck_assert(find_available_user() == -1);\n}\nEND_TEST\n\nSTART_TEST(test_find_available_user_small_net)\n{\n\tin_addr_t ip;\n\tint i;\n\n\tip = inet_addr(\"127.0.0.1\");\n\tinit_users(ip, 29); /* this should result in 5 enabled users */\n\n\tfor (i = 0; i < 5; i++) {\n\t\tck_assert(find_available_user() == i);\n\t}\n\n\tfor (i = 0; i < USERS; i++) {\n\t\tck_assert(find_available_user() == -1);\n\t}\n\n\tusers[3].active = 0;\n\n\tck_assert(find_available_user() == 3);\n\tck_assert(find_available_user() == -1);\n\n\tusers[3].last_pkt = 55;\n\n\tck_assert(find_available_user() == 3);\n\tck_assert(find_available_user() == -1);\n}\nEND_TEST\n\nTCase *\ntest_user_create_tests(void)\n{\n\tTCase *tc;\n\n\ttc = tcase_create(\"User\");\n\ttcase_add_test(tc, test_init_users);\n\ttcase_add_test(tc, test_find_user_by_ip);\n\ttcase_add_test(tc, test_all_users_waiting_to_send);\n\ttcase_add_test(tc, test_find_available_user);\n\ttcase_add_test(tc, test_find_available_user_small_net);\n\n\treturn tc;\n}\n"
  }
]