1
0
Fork 0
mirror of https://github.com/yarrick/iodine.git synced 2025-04-10 12:31:00 +00:00

Compare commits

...

163 commits

Author SHA1 Message Date
Erik Ekman
f41c4bb9f3 Release 0.5.0 2009-01-23 18:20:27 +00:00
Erik Ekman
30a3bb9445 Release 0.5.0-rc2 2009-01-17 09:06:33 +00:00
Erik Ekman
134fa90727 updated manpage 2009-01-10 20:56:39 +00:00
Erik Ekman
46293b51b1 prepare version 0.5.0-rc1 2009-01-10 20:40:22 +00:00
Erik Ekman
fa9b145af1 Branch 0.5 2009-01-10 20:36:16 +00:00
Erik Ekman
2b7bf00e1a Rename protocol to version 00000500 2009-01-10 20:32:53 +00:00
Erik Ekman
7a1733ae82 Rename protocol to version 00000500 2009-01-10 20:32:32 +00:00
Erik Ekman
d7f07d2f1f Enhanced checks on incoming queries, check user exists and is active 2009-01-10 20:23:50 +00:00
Erik Ekman
db13d81caf #7 finally done\! Added autoprobing of max downstream fragsize. 2009-01-10 19:30:55 +00:00
Erik Ekman
9a139b7005 #7, add probe fragsize support for server. documented 2009-01-10 16:22:51 +00:00
Erik Ekman
49e448fb19 fix warnings 2009-01-07 18:16:49 +00:00
Erik Ekman
9f3e397475 add osflags for tests 2009-01-06 22:05:15 +00:00
Erik Ekman
3ac090f847 Update readme with new url for osx tuntap driver 2009-01-06 19:58:29 +00:00
Erik Ekman
ab75dae208 allow custom check path 2009-01-06 13:41:45 +00:00
Erik Ekman
168b05e3f7 Fix build on OpenBSD 2009-01-06 10:47:01 +00:00
Erik Ekman
9f2730cb9a fix label 2009-01-05 19:52:01 +00:00
Erik Ekman
dfd6f9aa90 #7, set max fragsize with -m in the client 2009-01-05 19:47:59 +00:00
Erik Ekman
0ed202dd18 downstream fragsize is now per user 2009-01-05 18:50:46 +00:00
Erik Ekman
78aaf26369 #7, handle special case, remove up to 1 second pause when doing bulk download 2009-01-05 17:08:34 +00:00
Erik Ekman
20cfb002c3 Downstream fragmentation now working. Currently fragment size is hardcoded to 1200. More tweaking left, as well as fragsize auto detection. (#7) 2009-01-05 16:25:54 +00:00
Erik Ekman
d5f0dac459 Discard packets which only has data header 2009-01-04 18:59:12 +00:00
Erik Ekman
55d9ddb8dd add downstream data header and basic parsing in client, for #7 2009-01-04 18:56:24 +00:00
Erik Ekman
7dd38fec17 Create send_chunk() on server 2009-01-04 13:53:32 +00:00
Erik Ekman
f8eb4c952b Allow setting netmask in iodined, fixes #27. The same netmask will be given to clients as well. Updated docs. 2009-01-04 12:39:28 +00:00
Erik Ekman
f5e58e6527 Assign client IPs within the network (fixes #28), also limit number of users depending on netmask (for #27) 2009-01-04 12:03:35 +00:00
Erik Ekman
3f79d948bf updated docs 2009-01-04 10:58:52 +00:00
Erik Ekman
c742fe79c3 Happy new year 2009-01-03 23:39:54 +00:00
Erik Ekman
7791035364 Happy new year 2009-01-03 23:27:21 +00:00
Erik Ekman
58f789307b Updated changelog for #37 2009-01-03 23:14:02 +00:00
Erik Ekman
d027a60859 Handle trans id >= 0x8000, fix bug #37 2009-01-03 20:13:31 +00:00
Erik Ekman
da6eee279a make OUT debug look more like IN debug 2009-01-03 18:29:36 +00:00
Erik Ekman
b66dc4ea51 update tests after inline dot function now uses 57 as distance 2008-12-27 00:40:30 +00:00
Erik Ekman
3b4cc0989c Fix for compile error on FreeBSD 2008-12-27 00:30:51 +00:00
Erik Ekman
7335940130 make iodined build on opensolaris 2008-12-25 16:56:13 +00:00
Erik Ekman
18e0042ce4 Detect duplicates in upstream data, start frag at zero 2008-12-14 17:21:27 +00:00
Erik Ekman
89fdbc104b Implemented new protocol for upstream data 2008-12-11 22:39:06 +00:00
Erik Ekman
458b5af003 Added simple 5bits to 8 and reverse encoder, with test 2008-12-11 19:26:11 +00:00
Erik Ekman
9d8e9a7d18 Removing old code 2008-12-11 19:12:51 +00:00
Erik Ekman
e06ce0a213 Updated old proto, added new things to latest 2008-12-11 19:12:34 +00:00
Erik Ekman
a83164fad8 Added notreached 2008-12-11 19:11:53 +00:00
Erik Ekman
c7d1620cad Updated old protocol spec 2008-12-07 09:55:23 +00:00
Erik Ekman
fbb874c1ab fix version number in spec 2008-12-07 09:44:55 +00:00
Erik Ekman
48df1d896a Added old protocol spec 2008-12-07 09:42:19 +00:00
Erik Ekman
b639436375 updated docs 2008-12-07 09:41:06 +00:00
Erik Ekman
33b5ef9bf9 Reverted new protocol 2008-12-06 22:12:18 +00:00
Erik Ekman
5450372a75 Updated encoding tests 2008-12-06 19:08:14 +00:00
Erik Ekman
900a0e8df7 Added blocksize funcs, made funcs static 2008-12-06 15:31:28 +00:00
Erik Ekman
46f7eccf54 New protocol spec 2008-12-06 13:20:47 +00:00
Erik Ekman
3740894350 Revert client shutdown code, it seems BADIP can arrive even though everything works 2008-12-06 12:25:02 +00:00
Erik Ekman
cb0fa56232 updated changelog 2008-09-14 13:37:44 +00:00
Erik Ekman
55176af538 Added -n to set NS ip, updated docs, added checks 2008-09-14 13:21:11 +00:00
Erik Ekman
2eb78f9e8c Reverted [686], [689] and [692]. SSH login now works again. Increased version. 2008-09-14 12:44:55 +00:00
Erik Ekman
b4893e8a8b Rename codecs 2008-09-14 12:05:55 +00:00
Erik Ekman
4203f115f5 Use base64 is case is preserved and plus sign is allowed 2008-09-14 11:34:56 +00:00
Erik Ekman
e8ee981f97 Print failed tests 2008-09-14 11:33:18 +00:00
Erik Ekman
524522d00a Base64 codec now uses + as 64th char 2008-09-14 11:32:31 +00:00
Erik Ekman
de2912c089 rewrote strange message 2008-09-09 21:10:48 +00:00
Erik Ekman
6f097a4cb3 Added debugging 2008-09-09 21:09:06 +00:00
Erik Ekman
4c805fef6a Fix issue #33, respond to NS requests 2008-09-09 20:55:13 +00:00
Erik Ekman
d40c464ac1 shorten some lines 2008-09-09 19:55:45 +00:00
Erik Ekman
8eccbf097a Stop client if server is restarted 2008-09-09 19:37:51 +00:00
Erik Ekman
63d65bb30e formatting 2008-09-09 19:36:51 +00:00
Erik Ekman
e359f64003 Updated year 2008-09-09 19:07:09 +00:00
Erik Ekman
6ca1b992bb added include for iovec 2008-08-07 22:34:14 +00:00
Erik Ekman
d4e1eef6d5 Now fetches destination address from udp packets 2008-08-07 22:12:10 +00:00
Erik Ekman
c96b83e3d2 Forward non-tunnel requests to another udp port (fixes #31) 2008-08-07 21:18:15 +00:00
Erik Ekman
b619662201 Patch to make it build on BeOS R5-BONE and Haiku from Francois Revol 2008-08-07 16:53:59 +00:00
Erik Ekman
fb3fa24edb Implemented filtering based on topdomain 2008-08-07 16:49:22 +00:00
Erik Ekman
6531d5e72b Eliminate extra 'ping' message when server sends data to client which generates a reply 2008-08-07 15:05:51 +00:00
Erik Ekman
edf7e5a565 updated documentation 2008-08-07 14:44:02 +00:00
Erik Ekman
2270063464 updated changelog 2008-08-07 14:40:39 +00:00
Erik Ekman
55a689e759 Fix #34, send pings only every 5 seconds 2008-08-07 14:39:43 +00:00
Erik Ekman
188e69aa1f Fixed segfault when sending version rejects: VNAK/VFUL 2008-08-07 14:16:12 +00:00
Erik Ekman
798bbb64db Changed texts 2008-08-07 14:13:33 +00:00
Erik Ekman
9c74eb09a7 Improved latency for traffic initiated from server 2008-08-07 13:22:30 +00:00
Erik Ekman
d2b11c44b1 0.4.2 released 2008-08-06 20:51:20 +00:00
Erik Ekman
ad8afce8e1 fixed osflags script, updated changelog 2008-08-06 20:02:34 +00:00
Erik Ekman
9019b0639d fix opensolaris warning 2008-08-06 18:59:22 +00:00
Erik Ekman
dce8f8352b added -D to usage() and help() 2008-08-06 10:47:44 +00:00
Erik Ekman
fc6106153f Named the next release 2008-08-05 22:59:31 +00:00
Erik Ekman
9fa70acc69 Added debug capability on server 2008-08-05 22:37:40 +00:00
Erik Ekman
2ab94a7991 Changes to allow handling of queries of type A, NS etc 2008-08-05 21:53:19 +00:00
Erik Ekman
468bd706cb updated changelog 2008-08-05 14:56:11 +00:00
Erik Ekman
7b90054346 Reworked fix for #21 2008-08-05 14:47:51 +00:00
Erik Ekman
4d79bf6368 Added -c flag to disable IP/port checking in each request 2008-07-12 22:39:29 +00:00
Erik Ekman
e4e23275c9 Removed needless va_str() 2008-07-12 20:57:30 +00:00
Erik Ekman
d6ec29be4d Remove double warnings 2008-07-12 20:30:35 +00:00
Erik Ekman
6d1a003c1e Add extra ldflags for solaris 2008-07-12 12:42:19 +00:00
Erik Ekman
30014e6433 Applied Open/Solaris patch from Albert Lee 2008-07-12 12:26:41 +00:00
Erik Ekman
f2596cef24 Add include for setgroups() on Linux 2008-07-12 12:20:35 +00:00
Erik Ekman
71c5fe99ce updated changelog 2008-07-12 12:06:56 +00:00
Erik Ekman
adabd28b46 applied security patch from Andrew Griffiths, limit user groups 2008-07-12 12:05:59 +00:00
Erik Ekman
3f4852edab updated changelog 2008-07-12 11:50:42 +00:00
Erik Ekman
bc76b588c9 Applied patch for not configuring the tun interface, debian bug 477692 2008-07-12 11:45:22 +00:00
Erik Ekman
e7de432088 reapplied maxims patches 2008-07-12 11:41:01 +00:00
Erik Ekman
321781ad85 removed empty files 2008-07-12 11:37:25 +00:00
Erik Ekman
ddaebb0074 reverting the code after 0.4.1, except for some patches 2008-07-12 11:36:39 +00:00
Erik Ekman
cb3115865d Fix tests, dotting does not spare a char anymore 2008-01-07 22:24:19 +00:00
Erik Ekman
b121f638d0 Added port range check, based on patch from Maxim Bourmistrov 2008-01-07 22:18:27 +00:00
Erik Ekman
ac46718c16 Added checks on topdomain name based on patch from Maxim Bourmistrov 2008-01-07 22:06:09 +00:00
Erik Ekman
98061ccc0e Applied patch from Maxim Bourmistrov 2008-01-02 20:40:28 +00:00
Erik Ekman
5460c8eb0a Link test with packet 2007-12-02 10:51:52 +00:00
Erik Ekman
29b2348ca6 Reset sentlen when advancing 2007-12-02 02:28:18 +00:00
Erik Ekman
6fa0d98c99 #7 Actually update server_id 2007-12-02 02:27:36 +00:00
Erik Ekman
9ca4130e9a Always send latest chunk id 2007-12-02 01:22:34 +00:00
Erik Ekman
3eb835afe7 Add two chars from client to server for verification of data delivery 2007-12-02 01:16:53 +00:00
Erik Ekman
fd45a20f30 Rewrote strange warning message 2007-12-01 23:48:02 +00:00
Erik Ekman
4c6aae9e90 Use packet functions for packet handling. Prepare for sending fragmented ( #7 ) 2007-12-01 23:33:51 +00:00
Erik Ekman
de4a726cb9 Remove useless success warning message 2007-12-01 23:25:44 +00:00
Erik Ekman
317e1efbd6 use packet functions for empty check and fill 2007-12-01 23:05:54 +00:00
Erik Ekman
c8726f2c5d revert [607], [608] and parts of [611] 2007-12-01 23:02:06 +00:00
Erik Ekman
3b7927b2dc Fixed packet_empty() 2007-12-01 22:41:27 +00:00
Erik Ekman
9e60b36430 Renamed packet_sending to packet_empty 2007-12-01 22:19:54 +00:00
Erik Ekman
fc632e6311 Speling 2007-12-01 22:11:48 +00:00
Erik Ekman
d12d0fcff5 Added packet_init 2007-12-01 22:10:48 +00:00
Erik Ekman
7f48d0d99f Extract login handling to function 2007-12-01 21:55:48 +00:00
Erik Ekman
212a3b93e6 Extract version checking to function 2007-12-01 21:46:13 +00:00
Erik Ekman
b55c3f432b added license 2007-12-01 21:26:51 +00:00
Erik Ekman
c4a2b0c27f #7 Move packet handling out of iodine.c and into packet.c 2007-12-01 21:23:59 +00:00
Erik Ekman
2d8b2655ea packet name collided with global packet 2007-12-01 20:53:29 +00:00
Erik Ekman
fe75007109 Add notreached comments 2007-12-01 19:48:17 +00:00
Erik Ekman
509f445c1e Add notreached comments 2007-12-01 19:46:22 +00:00
Erik Ekman
f47c750c98 Escape dashes in man page 2007-12-01 10:16:19 +00:00
Erik Ekman
f265e4637f Missed one $(MAKE) 2007-12-01 10:12:25 +00:00
Erik Ekman
b6340acfb3 0.4.1 release at last 2007-11-30 22:02:21 +00:00
Erik Ekman
3b43db2529 updated changelog 2007-11-27 20:11:55 +00:00
Erik Ekman
bd2ed87022 apply patch to detach before chroot/privdrop 2007-11-27 20:11:43 +00:00
Erik Ekman
5adeafddfa Use %d for size_t sprintf 2007-11-27 20:04:13 +00:00
Erik Ekman
c22752d1f5 Use 2007-11-27 20:00:45 +00:00
Bjorn Andersson
488412d4e6 buffer overflow in dns.c pointed out by Matus Harvan, also strncpy cleanups 2007-08-26 15:47:32 +00:00
Erik Ekman
b0c6924a8e Init variables, fix #26 2007-08-08 06:20:09 +00:00
Bjorn Andersson
32bd132d43 local stuff in iodine made static 2007-07-12 15:50:06 +00:00
Bjorn Andersson
643178b207 stdin-echo fix in server too 2007-07-12 15:48:05 +00:00
Erik Ekman
e6286cc03c #21: Reverted [538], reopening 2007-07-12 15:22:32 +00:00
Bjorn Andersson
e5ee739537 some cleanup 2007-07-12 15:18:34 +00:00
Bjorn Andersson
0b9a532bbe name the address of the nameserver nameserv instead of peer 2007-07-12 15:18:23 +00:00
Bjorn Andersson
d9ca124e18 cleaning commandline on server too 2007-07-12 13:46:58 +00:00
Bjorn Andersson
c6f46ebaf9 fixes bad printf after resolv.conf-fix 2007-07-12 13:40:52 +00:00
Bjorn Andersson
e889185aca nasty hack hides password on commandline 2007-07-12 13:36:24 +00:00
Bjorn Andersson
1f9a0273db use termios to not echo password when entered on stdin 2007-07-12 13:24:55 +00:00
Erik Ekman
04487efe96 #23 updated manpage and log row 2007-07-12 13:23:44 +00:00
Bjorn Andersson
f6735782b1 /etc/resolv.conf is used if no nameserver is given on commandline 2007-07-12 13:01:18 +00:00
Erik Ekman
d5ffc25557 #25 Fixed crash on query with bad top domain 2007-07-12 08:38:00 +00:00
Erik Ekman
aae94200a5 #16 Do case preservation check after login 2007-07-12 08:31:29 +00:00
Erik Ekman
17c41d87bc #24: Add length check on topdomain, <= 128 chars 2007-07-11 23:25:03 +00:00
Erik Ekman
4e582e98c6 use common send_query function 2007-07-11 23:10:08 +00:00
Erik Ekman
11748b2963 converted iodine.c to use packet struct 2007-07-11 22:39:56 +00:00
Erik Ekman
5f6b7131cc updated log 2007-07-11 22:16:55 +00:00
Erik Ekman
ea30edd76f fixed #17: report RCODE error msgs 2007-07-11 22:10:53 +00:00
Erik Ekman
a4684f5ebf add check.sf.net note in test target 2007-07-11 21:31:49 +00:00
Erik Ekman
83f2e56426 Updated changelog for #21 2007-07-11 21:19:09 +00:00
Erik Ekman
639fb5f6aa Store only in_addr, not whole sockaddr, fixes #21 2007-07-11 18:27:18 +00:00
Erik Ekman
bb74190ed5 Prepare for encoding switching 2007-06-24 10:54:50 +00:00
Erik Ekman
acc8b798e3 changes since 0.4.0 2007-06-24 10:34:10 +00:00
Erik Ekman
d978ed47bc uninstall in destdir 2007-06-24 10:33:40 +00:00
Erik Ekman
d679babb67 updated date 2007-06-24 10:23:17 +00:00
Erik Ekman
63f9098aa0 Add mtu info to manpage 2007-06-24 10:04:02 +00:00
Erik Ekman
42fcc07379 remove last warning on osx 2007-06-18 07:17:55 +00:00
Erik Ekman
9b7863a668 fix sbin dir, add permissions 2007-06-17 12:54:49 +00:00
Erik Ekman
502205f1a1 hopefully more packaging-friendly makefile 2007-06-17 12:32:16 +00:00
Erik Ekman
854c7ed1c1 add patch from decker for osx 2007-06-17 12:19:50 +00:00
Erik Ekman
4d079b95f2 Remove warning for \!LINUX 2007-06-17 12:19:23 +00:00
Erik Ekman
5c9ff9ba06 add sys/time.h for old osx 2007-06-17 11:46:05 +00:00
41 changed files with 2413 additions and 775 deletions

View file

@ -5,6 +5,58 @@ iodine - http://code.kryo.se/iodine
CHANGES:
2009-01-23: 0.5.0 "iPassed"
- Fixed segfault in server when sending version reject.
- Applied patch to make iodine build on BeOS R5-BONE and Haiku,
from Francois Revol. Still work to do to get tun device working.
- Added capability to forward DNS queries outside tunnel domain to
a nameserver on localhost. Use -b port to enable, fixes #31.
- iodined now replies to NS request on its own domain, fixes issue #33.
The destination IP address is sent as reply. Use -n to specify
a specific IP address to return (if behind NAT etc).
- Upstream data is now Base64 encoded if relay server preserves case and
supports the plus (+) character in domain names, fixes #16.
- Fixed problem in client when DNS trans. ID has highest bit set (#37)
- IP addresses are now assigned within the netmask, so iodined can
use any address for itself, fixes #28.
- Netmask size is now adjustable. Setting a small net will reduce the
number of users. Use x.x.x.x/n notation on iodined tunnel ip.
This fixes #27.
- Downstream data is now fragmented, and the fragment size is auto-
probed after login. Fixes #7. It only took a few years :)
- Enhanced the checks that validates incoming packets
- Fixed endless loop in fragment size autodetection, #39.
- Fixed broken hostname dot placing with specific lengths, #40.
2008-08-06: 0.4.2 "Opened Zone"
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann
- Applied a patch for not creating and configuring the tun interface,
Debian bug #477692 by Vincent Bernat, controlled by -s switch
- Applied a security patch from Andrew Griffiths, use setgroups() to
limit the groups of the user
- Applied a patch to make iodine build on (Open)Solaris, from Albert Lee
Needs TUN/TAP driver http://www.whiteboard.ne.jp/~admin2/tuntap/
Still needs more code in tun.c for opening/closing the device
- Added option in server (-c) to disable IP/port checking on packets,
will hopefully help when server is behind NAT
- Fixed bug #21, now only IP address part of each packet is checked.
Should remove the need for the -c option and also work with
bugfixed DNS servers worldwide.
- Added -D option on server to enable debugging. Debug level 1 now
prints info about each RX/TX datagram.
2007-11-30: 0.4.1 "Tea Online"
- Introduced encoding API
- Switched to new Base32 implementation
- Added Base64 implementation that only uses 63 chars (not used yet)
- Refined 'install' make target and use $(MAKE) for recursive calls
- All received error messages (RCODE field) are echoed
- Top domain limited to 128 chars
- Case preservation check sent after login to decide codec
- Fixed crash on incoming NULL query in server with bad top domain
- /etc/resolv.conf is consulted if no nameserver is given on commandline
- Applied patch from Matthew W. S. Bell (Detach before chroot/dropping priv)
2007-03-25: 0.4.0 "Run Home"
- Added multiuser support (up to 8 users simultaneously)
- Added authentication (password entered as argument or on stdin)

View file

@ -1,6 +1,11 @@
PREFIX=/usr/local
prefix=/usr/local
sbindir=$(prefix)/sbin
datadir=$(prefix)/share
mandir=$(datadir)/man
INSTALL=/usr/bin/install
DESTDIR=
INSTALL=install
INSTALL_FLAGS=
MKDIR=mkdir
@ -10,26 +15,31 @@ RM=rm
RM_FLAGS=-f
all:
@(cd src; make all)
@(cd src; $(MAKE) all)
install: all
$(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/sbin
$(INSTALL) $(INSTALL_FLAGS) bin/iodine $(PREFIX)/sbin/iodine
$(INSTALL) $(INSTALL_FLAGS) bin/iodined $(PREFIX)/sbin/iodined
$(MKDIR) $(MKDIR_FLAGS) $(PREFIX)/man/man8
$(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(PREFIX)/man/man8/iodine.8
$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
$(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine
chmod 755 $(DESTDIR)$(sbindir)/iodine
$(INSTALL) $(INSTALL_FLAGS) bin/iodined $(DESTDIR)$(sbindir)/iodined
chmod 755 $(DESTDIR)$(sbindir)/iodined
$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(mandir)/man8
$(INSTALL) $(INSTALL_FLAGS) man/iodine.8 $(DESTDIR)$(mandir)/man8/iodine.8
chmod 644 $(DESTDIR)$(mandir)/man8/iodine.8
uninstall:
$(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodine
$(RM) $(RM_FLAGS) $(PREFIX)/sbin/iodined
$(RM) $(RM_FLAGS) $(PREFIX)/man/man8/iodine.8
$(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodine
$(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined
$(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8
test: all
@(cd tests; make all)
@echo "!! The check library is required for compiling and running the tests"
@echo "!! Get it at http://check.sf.net"
@(cd tests; $(MAKE) all)
clean:
@echo "Cleaning..."
@(cd src; make clean)
@(cd tests; make clean)
@(cd src; $(MAKE) clean)
@(cd tests; $(MAKE) clean)
@rm -rf bin

46
README
View file

@ -28,9 +28,11 @@ HOW TO USE:
Server side:
To use this tunnel, you need control over a real domain (like mytunnel.com),
and a server with a public IP number (not behind NAT) that does not yet run
a DNS server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the
server. If you use BIND for the domain, add these lines to the zone file:
and a server with a public IP number. If the server already runs a DNS
server, change the listening port and then use the -b option to let
iodined forward the DNS requests. Then, delegate a subdomain
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
add these lines to the zone file:
tunnel1host IN A 10.15.213.99
tunnel1 IN NS tunnel1host.mytunnel.com.
@ -50,15 +52,14 @@ password on the commandline (-P pass) or after the server has started. Now
everything is ready for the client.
Client side:
All the setup is done, just start iodine. It also takes two
arguments, the first is the local relaying DNS server and the second is the
domain used (tunnel1.mytunnnel.com). If DNS queries are allowed to any
computer, you can use the tunnel endpoint (example: 10.15.213.99 or
tunnel1host.mytunnel.com) as the first argument. The tunnel interface will get
an IP close to the servers (in this case 192.168.99.2) and a suitable MTU.
Enter the same password as on the server either by argument or after the client
has started. Now you should be able to ping the other end of the tunnel from
either side.
All the setup is done, just start iodine. It takes up to two arguments, the
first is the local relaying DNS server (optional) and the second is the domain
used (tunnel1.mytunnnel.com). If DNS queries are allowed to any computer, you
can use the tunnel endpoint (example: 10.15.213.99 or tunnel1host.mytunnel.com)
as the first argument. The tunnel interface will get an IP close to the servers
(in this case 192.168.99.2) and a suitable MTU. Enter the same password as on
the server either by argument or after the client has started. Now you should
be able to ping the other end of the tunnel from either side.
MISC. INFO:
@ -73,10 +74,11 @@ If you have problems, try inspecting the traffic with network monitoring tools
and make sure that the relaying DNS server has not cached the response. A
cached error message could mean that you started the client before the server.
The upstream data is sent gzipped encoded with Base32. DNS protocol allows
one query per packet, and one query can be max 256 chars. Each domain name part
can be max 63 chars. So your domain name and subdomain should be as short as
possible to allow maximum throughput.
The upstream data is sent gzipped encoded with Base32, or Base64 if the relay
server support '+' in domain names. DNS protocol allows one query per packet,
and one query can be max 256 chars. Each domain name part can be max 63 chars.
So your domain name and subdomain should be as short as possible to allow
maximum upstream throughput.
TIPS & TRICKS:
@ -90,11 +92,11 @@ iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
PORTABILITY:
iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD
(ia64, x86), OpenBSD (x86), NetBSD (x86) and MacOS X (ppc and x86, with
http://www-user.rhrk.uni-kl.de/~nissler/tuntap/). It should work on other
unix-like systems as well that has TUN/TAP tunneling support (after some
patching). Let us know if you get it to run on other platforms.
iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD
(ia64, x86), OpenBSD (x86), NetBSD (x86) and MacOS X (ppc and x86, with
http://tuntaposx.sourceforge.net/). It should be easy to port to other
unix-like systems that has TUN/TAP tunneling support. Let us know if you get it
to run on other platforms.
THE NAME:
@ -111,7 +113,7 @@ THANKS:
AUTHORS & LICENSE:
Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
Permission to use, copy, modify, and distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice

61
doc/proto_00000402.txt Normal file
View file

@ -0,0 +1,61 @@
Detailed specification of protocol in version 00000402
======================================================
CMC = 2 byte Cache Miss Counter, increased every time it is used
Version:
Client sends:
First byte v or V
Rest encoded with base32:
4 bytes big endian protocol version
CMC
Server replies:
4 chars:
VACK (version ok), followed by login challenge
VNAK (version differs), followed by server protocol version
VFUL (server has no free slots), followed by max users
4 byte value: means login challenge/server protocol version/max users
1 byte userid of the new user, or any byte if not VACK
Login:
Client sends:
First byte l or L
Rest encoded with base32:
1 byte userid
16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge)
CMC
Server replies:
LNAK means not accepted
x.x.x.x-y.y.y.y-mtu means accepted (server ip, client ip, mtu)
Case check:
Client sends:
First byte z or Z
Lots of data that should not be decoded
Server replies:
The requested domain copied raw
Data:
Data header:
321 0
+---+-+
|UUU|L|
+---+-+
UUU = Userid
L = Last fragment in packet flag
First byte is the header, 4 bits coded as hex in ASCII.
Followed by data encoded with Base32.
Ping:
Client sends:
First byte p or P
Rest encoded with Base32:
1 byte userid
CMC
The server response to Ping and Data packets is a DNS NULL type response:
If server has nothing to send, data length is 0 bytes.
If server has a packet to send, data length is set and the data is a full raw
unencoded ip packet, prefixed with 32 bits tun data.

112
doc/proto_00000500.txt Normal file
View file

@ -0,0 +1,112 @@
Detailed specification of protocol in version 00000500
======================================================
CMC = 2 byte Cache Miss Counter, increased every time it is used
Version:
Client sends:
First byte v or V
Rest encoded with base32:
4 bytes big endian protocol version
CMC
Server replies:
4 chars:
VACK (version ok), followed by login challenge
VNAK (version differs), followed by server protocol version
VFUL (server has no free slots), followed by max users
4 byte value: means login challenge/server protocol version/max users
1 byte userid of the new user, or any byte if not VACK
Login:
Client sends:
First byte l or L
Rest encoded with base32:
1 byte userid
16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge)
CMC
Server replies:
LNAK means not accepted
x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits)
Case check:
Client sends:
First byte z or Z
Lots of data that should not be decoded
Server replies:
The requested domain copied raw
Switch codec:
Client sends:
First byte s or S
5 bits coded as Base32 char, meaning userid
5 bits coded as Base32 char, with value 5 or 6, representing number of raw
bits per encoded byte
Server sends:
Name of codec if accepted. After this all upstream data packets must
be encoded with the new codec.
BADCODEC if not accepted. Client must then revert to Base32
Probe downstream fragment size:
Client sends:
First byte r or R
15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF
meaning 4 bits userid, 11 bits fragment size
Then follows a long random query which contents does not matter
Server sends:
Requested number of bytes as a response. The first two bytes contains
the requested length. Rest of message can be any data.
BADFRAG if requested length not accepted.
Set downstream fragment size:
Client sends:
First byte n or N
Rest encoded with base32:
1 byte userid
2 bytes new downstream fragment size
CMC
Server sends:
2 bytes new downstream fragment size. After this all downstream
payloads will be max (fragsize + 2) bytes long.
BADFRAG if not accepted.
Data:
Upstream data header:
3210 432 10 43 210 4321 0
+----+---+--+--+---+----+-+
|UUUU|SSS|FF|FF|DDD|GGGG|L|
+----+---+--+--+---+----+-+
Downstream data header:
7 654 3210 765 4321 0
+-+---+----+---+----+-+
|C|SSS|FFFF|DDD|GGGG|L|
+-+---+----+---+----+-+
UUUU = Userid
L = Last fragment in packet flag
SS = Upstream packet sequence number
FFFF = Upstream fragment number
DDD = Downstream packet sequence number
GGGG = Downstream fragment number
C = Compression enabled for downstream packet
Upstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes
Base32 encoded header, then comes the payload data, encoded with chosen codec.
Downstream data starts with 2 byte header. Then payload data, which may be
compressed.
Ping:
Client sends:
First byte p or P
Rest encoded with Base32:
1 byte with 4 bits userid
1 byte with:
3 bits downstream seqno
4 bits downstream fragment
CMC
The server response to Ping and Data packets is a DNS NULL type response:
If server has nothing to send, data length is 0 bytes.
If server has something to send, it will send a downstream data packet,
prefixed with 2 bytes header as shown above.

View file

@ -1,5 +1,5 @@
.\" groff -man -Tascii iodine.8
.TH IODINE 8 "FEB 2007" "User Manuals"
.TH IODINE 8 "JUL 2008" "User Manuals"
.SH NAME
iodine, iodined \- tunnel IPv4 over DNS
.SH SYNOPSIS
@ -11,32 +11,45 @@ iodine, iodined \- tunnel IPv4 over DNS
.I user
.B ] [-P
.I password
.B ] [-m
.I fragsize
.B ] [-t
.I chrootdir
.B ] [-d
.I device
.B ]
.B [
.I nameserver
.B ]
.I topdomain
.B iodined [-v]
.B iodined [-h]
.B iodined [-f] [-u
.B iodined [-c] [-s] [-f] [-D] [-u
.I user
.B ] [-P
.I password
.B ] [-t
.I chrootdir
.B ] [-d
.I device
.B ] [-m
.I mtu
.B ] [-l
.I listen_ip
.B ] [-d
.I device
.B ]
.B ] [-p
.I port
.B ] [-n
.I external ip
.B ] [-b
.I dnsport
.B ] [-P
.I password
.B ]
.I tunnel_ip
.B [
.I /netmask
.B ]
.I topdomain
.SH DESCRIPTION
.B iodine
@ -66,16 +79,31 @@ Drop privileges and run as user 'user' after setting up tunnel.
.B -t chrootdir
Chroot to 'chrootdir' after setting up tunnel.
.TP
.B -d device
Use the TUN device 'device' instead of the normal one, which is dnsX on Linux
and otherwise tunX.
.TP
.B -P password
Use 'password' to authenticate. If not used,
.B stdin
will be used as input. Only the first 32 characters will be used.
.SS Client Options:
.TP
.B -d device
Use the TUN device 'device' instead of the normal one, which is dnsX on Linux
and otherwise tunX.
.B -m fragsize
Maximum downstream fragsize. Not setting this will cause the client to probe
the maximum accepted downstream packet size.
.SS Server Options:
.TP
.B -c
Disable checks on client IP on all incoming requests.
.TP
.B -s
Don't try to configure IP address or MTU. This should only be used if
you have already configured the device that will be used.
.TP
.B -D
Increase debug level. Level 1 prints info about each RX/TX packet.
.TP
.B -m mtu
Set 'mtu' as mtu size for the tunnel device. This will be sent to the client
on connect, and the client will use the same mtu.
@ -88,12 +116,21 @@ connections.
Make the server listen on 'port' instead of 53 for traffic.
.B Note:
You must make sure the dns requests are forwarded to this port yourself.
.TP
.B -n external ip
The IP address to return in NS responses. Default is to return the address used
as destination in the query.
.TP
.B -b dnsport
If this port is specified, all incoming requests not inside the tunnel domain
will be forwarded to this port on localhost, to be handled by a real dns.
.SS Client Arguments:
.TP
.B nameserver
The nameserver to use to relay the dns traffic. This can be any relaying
nameserver or the ip number of the server running iodined if reachable.
Normally, you should specify a nameserver from your
This argument is optional, and if not specified a nameserver will be read
from the
.I /etc/resolv.conf
file.
.TP
@ -106,10 +143,12 @@ is the iodined server, then the topdomain can be chosen freely. This argument
must be the same on both the client and the server.
.SS Server Arguments:
.TP
.B tunnel_ip
.B tunnel_ip[/netmask]
This is the servers ip address on the tunnel interface. The client will be
given the next ip number in the range. It is recommended to use the
10.0.0.0/8 or 172.16.0.0/12 ranges.
10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden
by specifying it here. Using a smaller network will limit the number of
concurrent users.
.TP
.B topdomain
The dns traffic will is expected to be sent as querys of type NULL for
@ -121,13 +160,13 @@ the same on both the client and the server.
.TP
Try it out within your own LAN! Follow these simple steps:
.TP
- On your server, run: ./iodined -f 10.0.0.1 test.asdf
- On your server, run: ./iodined \-f 10.0.0.1 test.asdf
(If you already use the 10.0.0.0 network, use another internal net like
172.16.0.0)
.TP
- Enter a password
.TP
- On the client, run: ./iodine -f 192.168.0.1 test.asdf
- On the client, run: ./iodine \-f 192.168.0.1 test.asdf
(Replace 192.168.0.1 with the server's ip address)
.TP
- Enter the same password
@ -144,10 +183,11 @@ To actually use it through a relaying nameserver, see below.
.TP
.B Server side:
To use this tunnel, you need control over a real domain (like mytunnel.com),
and a server with a static public IP number that does not yet run a DNS
server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server.
If you use BIND for the domain, add these lines to the zone file (replace
10.15.213.99 with your server ip):
and a server with a public IP number. If the server already runs a DNS
server, change the listening port and then use the \-b option to let
iodined forward the DNS requests. Then, delegate a subdomain
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
add these lines to the zone file (replace 10.15.213.99 with your server ip):
.nf
tunnel1host IN A 10.15.213.99
@ -157,10 +197,10 @@ tunnel1 IN NS tunnel1host.mytunnel.com.
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
to your server. Start iodined on the server. The first argument is the tunnel
IP address (like 192.168.99.1) and the second is the assigned domain (in this
case tunnel1.mytunnel.com). The -f argument will keep iodined running in the
case tunnel1.mytunnel.com). The \-f argument will keep iodined running in the
foreground, which helps when testing. iodined will start a virtual interface,
and also start listening for DNS queries on UDP port 53. Either enter a
password on the commandline (-P pass) or after the server has started. Now
password on the commandline (\-P pass) or after the server has started. Now
everything is ready for the client.
.TP
.B Client side:
@ -179,6 +219,10 @@ The normal case is to route all traffic through the DNS tunnel. To do this, firs
add a route to the nameserver you use with the default gateway as gateway. Then
replace the default gateway with the servers IP address within the DNS tunnel,
and configure the server to do NAT.
.TP
.B MTU issues:
These issues should be solved now, with automatic fragmentation of downstream
packets. There should be no need to set the MTU explicitly on the server.
.SH BUGS
File bugs at http://dev.kryo.se/iodine/
.SH AUTHORS

View file

@ -2,16 +2,16 @@ CC = gcc
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o
CLIENTOBJS = iodine.o
CLIENT = ../bin/iodine
SERVEROBJS = iodined.o user.o
SERVEROBJS = iodined.o user.o fw_query.o
SERVER = ../bin/iodined
OS = `uname | tr "a-z" "A-Z"`
ARCH = `uname -m`
LDFLAGS = -lz
CFLAGS = -c -g -Wall -D$(OS) -pedantic
LDFLAGS = -lz `sh osflags link`
CFLAGS = -c -g -Wall -D$(OS) -pedantic `sh osflags cflags`
all: stateos $(CLIENT) $(SERVER) $(TESTSUITE)
all: stateos $(CLIENT) $(SERVER)
stateos:
@echo OS is $(OS), arch is $(ARCH)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -21,18 +21,29 @@
#include "encoding.h"
#include "base32.h"
#define BLKSIZE_RAW 5
#define BLKSIZE_ENC 8
static const char cb32[] =
"abcdefghijklmnopqrstuvwxyz0123456789";
"abcdefghijklmnopqrstuvwxyz012345";
static unsigned char rev32[128];
static int reverse_init = 0;
static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_encode(char *, size_t *, const void *, size_t);
static int base32_handles_dots();
static int base32_blksize_raw();
static int base32_blksize_enc();
static struct encoder base32_encoder =
{
"BASE32",
"Base32",
base32_encode,
base32_decode,
base32_handles_dots,
base32_handles_dots
base32_handles_dots,
base32_blksize_raw,
base32_blksize_enc
};
struct encoder
@ -41,18 +52,50 @@ struct encoder
return &base32_encoder;
}
int
static int
base32_handles_dots()
{
return 0;
}
int
static int
base32_blksize_raw()
{
return BLKSIZE_RAW;
}
static int
base32_blksize_enc()
{
return BLKSIZE_ENC;
}
int
b32_5to8(int in)
{
return cb32[in & 31];
}
int
b32_8to5(int in)
{
int i;
int c;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
return rev32[in];
}
static int
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
{
size_t newsize;
size_t maxsize;
unsigned char *s;
unsigned char *p;
unsigned char *q;
int i;
@ -60,18 +103,18 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
memset(buf, 0, *buflen);
/* how many chars can we encode within the buf */
maxsize = 5 * (*buflen / 8 - 1) - 1;
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
/* how big will the encoded data be */
newsize = 8 * (size / 5 + 1) + 1;
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
}
p = s = (unsigned char *) buf;
p = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=5) {
for(i=0;i<size;i+=BLKSIZE_RAW) {
p[0] = cb32[((q[0] & 0xf8) >> 3)];
p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
@ -81,8 +124,8 @@ base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
q += 5;
p += 8;
q += BLKSIZE_RAW;
p += BLKSIZE_ENC;
}
*p = 0;
@ -133,7 +176,7 @@ decode_token(const unsigned char *t, unsigned char *data, size_t len)
return 5;
}
int
static int
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{
unsigned char *q;
@ -153,21 +196,21 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
}
/* chars needed to decode slen */
newsize = 5 * (slen / 8 + 1) + 1;
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
/* encoded chars that fit in buf */
maxsize = 8 * (*buflen / 5 + 1) + 1;
maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
q = buf;
for (p = str; *p && strchr(cb32, *p); p += 8) {
for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
q += len;
slen -= 8;
slen -= BLKSIZE_ENC;
if (len < 5)
if (len < BLKSIZE_RAW)
break;
}
*q = '\0';

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -18,8 +18,7 @@
#define __BASE32_H__
struct encoder *get_base32_encoder(void);
int base32_handles_dots();
int base32_encode(char *, size_t *, const void *, size_t);
int base32_decode(void *, size_t *, const char *, size_t);
int b32_5to8(int);
int b32_8to5(int);
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -22,23 +22,31 @@
#include "common.h"
#include "base64.h"
#define BLKSIZE_RAW 3
#define BLKSIZE_ENC 4
static const char cb64[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.";
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
static unsigned char rev64[128];
static int reverse_init = 0;
static int base64_encode(char *, size_t *, const void *, size_t);
static int base64_decode(void *, size_t *, const char *, size_t);
static int base64_handles_dots();
static int base64_blksize_raw();
static int base64_blksize_enc();
#define REV64(x) rev64[(int) (x)]
#define MODE (cb64[62])
#define P62 (cb64[62])
#define P63 (cb64[63])
static struct encoder base64_encoder =
{
"BASE64",
"Base64",
base64_encode,
base64_decode,
base64_handles_dots,
base64_handles_dots
base64_handles_dots,
base64_blksize_raw,
base64_blksize_enc
};
struct encoder
@ -47,147 +55,25 @@ struct encoder
return &base64_encoder;
}
int
static int
base64_handles_dots()
{
return 0;
}
static void
findesc(int *count, unsigned char *esc, char c1, char c2, char c3, char c4)
static int
base64_blksize_raw()
{
int min1 = 0;
int min2 = 0;
int num1 = 0xFF; /* a very big number */
int num2 = 0xFE; /* a nearly as big number */
int i;
/* check if no more escapes needed */
if (count[62] == 0 && count[63] == 0) {
esc[0] = MODE;
esc[1] = MODE;
return;
}
for (i = 0; i < 62; i++) {
if (i == c1 || i == c2 || i == c3 || i == c4) {
continue;
}
if (count[i] < num1) {
min2 = min1;
num2 = num1;
min1 = i;
num1 = count[i];
} else if (count[i] < num2) {
min2 = i;
num2 = count[i];
}
}
esc[0] = cb64[min1];
esc[1] = cb64[min2];
}
static void
escape_chars(char *buf, size_t buflen)
{
int counter[64];
int escapes;
int reset;
int i;
unsigned char temp[4096];
unsigned char *r;
unsigned char *w;
unsigned char *e;
unsigned char esc[2];
memset(counter, 0, sizeof(counter));
esc[0] = P62;
esc[1] = P63;
/* first, find the number of times each token is used */
r = (unsigned char *) buf;
w = temp;
while (*r) {
counter[REV64(*r)]++;
*w++ = *r++;
}
/* check if work needed */
if (counter[62] == 0 && counter[63] == 0)
return;
r = temp;
w = (unsigned char *) buf;
reset = 1;
escapes = 0;
/* check a block for esc chars */
while (*r) {
if (reset == 0 && escapes == 0 && (
r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1])) {
/* last set of escape chars were unused.
* if we reset last escape switch then maybe we dont have to switch now */
/* change the latest escape switch to 999 (RESET) */
e[1] = MODE;
e[2] = MODE;
/* store default esc chars */
esc[0] = P62;
esc[1] = P63;
reset = 1;
}
/* these two if blocks can not be combined because a block can contain both
* char 9 and/or . and the current escape chars. */
if (r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1]) {
/* switch escape chars */
escapes = 0;
reset = 0;
/* find 2 suitable escape chars */
findesc(counter, esc, REV64(r[0]), REV64(r[1]), REV64(r[2]), REV64(r[3]));
/* store escape switch position */
e = w;
/* write new escape chars */
*w++ = MODE;
*w++ = esc[0];
*w++ = esc[1];
}
/* update counter on remaining chars */
for (i = 0; i < 4; i++) {
if (r[i])
counter[REV64(r[i])]--;
}
/* do the escaping */
for (i = 0; i < 4; i++) {
if (r[i] == P62) {
r[i] = esc[0];
escapes++;
} else if (r[i] == P63) {
r[i] = esc[1];
escapes++;
}
}
/* copy back to buf */
*w++ = *r++;
*w++ = *r++;
*w++ = *r++;
*w++ = *r++;
}
return BLKSIZE_RAW;
}
int
static int
base64_blksize_enc()
{
return BLKSIZE_ENC;
}
static int
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
{
size_t newsize;
@ -209,9 +95,9 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
}
/* how many chars can we encode within the buf */
maxsize = 3 * (*buflen / 4 - 1) - 1;
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
/* how big will the encoded data be */
newsize = 4 * (size / 3 + 1) + 1;
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
@ -220,19 +106,17 @@ base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
p = s = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=3) {
for(i=0;i<size;i+=BLKSIZE_RAW) {
p[0] = cb64[((q[0] & 0xfc) >> 2)];
p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
q += 3;
p += 4;
q += BLKSIZE_RAW;
p += BLKSIZE_ENC;
}
*p = 0;
escape_chars(buf, *buflen);
/* store number of bytes from data that was used */
*buflen = size;
@ -265,7 +149,7 @@ decode_token(const unsigned char *t, unsigned char *data, size_t len)
return 3;
}
int
static int
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{
unsigned char *q;
@ -273,9 +157,7 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
size_t maxsize;
const char *p;
unsigned char c;
unsigned char block[4];
unsigned char prot62;
unsigned char prot63;
unsigned char block[BLKSIZE_ENC];
int len;
int i;
@ -288,47 +170,26 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
}
/* chars needed to decode slen */
newsize = 3 * (slen / 4 + 1) + 1;
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
/* encoded chars that fit in buf */
maxsize = 4 * (*buflen / 3 + 1) + 1;
maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
prot62 = P62;
prot63 = P63;
q = buf;
for (p = str; *p; p += 4) {
/* handle escape instructions */
if (*p == MODE) {
p++;
if (p[0] == MODE && p[1] == MODE) {
/* reset escape chars */
prot62 = P62;
prot63 = P63;
p += 2;
} else {
prot62 = *p++;
prot63 = *p++;
}
}
for (p = str; *p; p += BLKSIZE_ENC) {
/* since the str is const, we unescape in another buf */
for (i = 0; i < 4; i++) {
for (i = 0; i < BLKSIZE_ENC; i++) {
block[i] = p[i];
if (prot62 == block[i]) {
block[i] = P62;
} else if (prot63 == block[i]) {
block[i] = P63;
}
}
len = decode_token(block, (unsigned char *) q, slen);
q += len;
slen -= 4;
slen -= BLKSIZE_ENC;
if (len < 3)
if (len < BLKSIZE_RAW)
break;
}
*q = '\0';

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -18,8 +18,5 @@
#define __BASE64_H__
struct encoder *get_base64_encoder(void);
int base64_handles_dots();
int base64_encode(char *, size_t *, const void *, size_t);
int base64_decode(void *, size_t *, const char *, size_t);
#endif

View file

@ -1,4 +1,5 @@
/* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
/* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -21,6 +22,8 @@
#endif
#include <time.h>
#include <err.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
@ -29,9 +32,56 @@
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <termios.h>
#include "common.h"
/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
#if !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
static int daemon(int nochdir, int noclose)
{
int fd, i;
switch (fork()) {
case 0:
break;
case -1:
return -1;
default:
_exit(0);
}
if (!nochdir) {
chdir("/");
}
if (setsid() < 0) {
return -1;
}
if (!noclose) {
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
for (i = 0; i < 3; i++) {
dup2(fd, i);
}
if (fd > 2) {
close(fd);
}
}
}
return 0;
}
#endif
#if defined(__BEOS__) && !defined(__HAIKU__)
int setgroups(int count, int *groups)
{
/* errno = ENOSYS; */
return -1;
}
#endif
int
open_dns(int localport, in_addr_t listen_ip)
{
@ -54,6 +104,9 @@ open_dns(int localport, in_addr_t listen_ip)
#endif
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
/* To get destination address from each UDP datagram, see iodined.c:read_dns() */
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, &flag, sizeof(flag));
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
err(1, "bind");
@ -71,13 +124,15 @@ close_dns(int fd)
void
do_chroot(char *newroot)
{
if (newroot) {
if (chroot(newroot) != 0 || chdir("/") != 0)
err(1, "%s", newroot);
#if !defined(__BEOS__) || defined(__HAIKU__)
if (chroot(newroot) != 0 || chdir("/") != 0)
err(1, "%s", newroot);
seteuid(geteuid());
setuid(getuid());
}
seteuid(geteuid());
setuid(getuid());
#else
warnx("chroot not available");
#endif
}
void
@ -88,3 +143,44 @@ do_detach()
umask(0);
alarm(0);
}
void
read_password(char *buf, size_t len)
{
struct termios old;
struct termios tp;
char pwd[80];
tcgetattr(0, &tp);
old = tp;
tp.c_lflag &= (~ECHO);
tcsetattr(0, TCSANOW, &tp);
printf("Enter password: ");
fflush(stdout);
scanf("%79s", pwd);
printf("\n");
tcsetattr(0, TCSANOW, &old);
strncpy(buf, pwd, len);
buf[len-1] = '\0';
}
int
check_topdomain(char *str)
{
int i;
if(str[0] == '.') /* special case */
return 1;
for( i = 0; i < strlen(str); i++) {
if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
continue;
else
return 1;
}
return 0;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -20,6 +20,7 @@
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@ -28,17 +29,31 @@
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define QUERY_NAME_SIZE 256
#if defined IP_RECVDSTADDR
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x))
#elif defined IP_PKTINFO
# define DSTADDR_SOCKOPT IP_PKTINFO
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
#endif
struct packet
{
int len;
int offset;
char data[64*1024];
int len; /* Total packet length */
int sentlen; /* Length of chunk currently transmitted */
int offset; /* Current offset */
char data[64*1024]; /* The data */
char seqno; /* The packet sequence number */
char fragment; /* Fragment index */
};
struct query {
char name[258];
short type;
short id;
char name[QUERY_NAME_SIZE];
unsigned short type;
unsigned short id;
struct in_addr destination;
struct sockaddr from;
int fromlen;
};
@ -49,4 +64,8 @@ void close_dns(int);
void do_chroot(char *);
void do_detach();
void read_password(char*, size_t);
int check_topdomain(char *);
#endif

139
src/dns.c
View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -61,7 +61,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
name = 0xc000 | ((p - buf) & 0x3fff);
putname(&p, 256, q->name);
putname(&p, sizeof(q->name), q->name);
putshort(&p, q->type);
putshort(&p, C_IN);
@ -78,7 +78,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
header->qdcount = htons(1);
header->arcount = htons(1);
putname(&p, 256, data);
putname(&p, datalen, data);
putshort(&p, q->type);
putshort(&p, C_IN);
@ -98,14 +98,105 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
return len;
}
int
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
{
HEADER *header;
int len;
short name;
short topname;
short nsname;
char *domain;
int domain_len;
char *p;
memset(buf, 0, buflen);
header = (HEADER*)buf;
header->id = htons(q->id);
header->qr = 1;
header->opcode = 0;
header->aa = 1;
header->tc = 0;
header->rd = 0;
header->ra = 0;
p = buf + sizeof(HEADER);
header->qdcount = htons(1);
header->ancount = htons(1);
header->arcount = htons(1);
/* pointer to start of name */
name = 0xc000 | ((p - buf) & 0x3fff);
domain = strstr(q->name, topdomain);
if (domain) {
domain_len = (int) (domain - q->name);
} else {
return -1;
}
/* pointer to start of topdomain */
topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);
/* Query section */
putname(&p, sizeof(q->name), q->name); /* Name */
putshort(&p, q->type); /* Type */
putshort(&p, C_IN); /* Class */
/* Answer section */
putshort(&p, name); /* Name */
putshort(&p, q->type); /* Type */
putshort(&p, C_IN); /* Class */
putlong(&p, 0x3ea7d011); /* TTL */
putshort(&p, 5); /* Data length */
/* pointer to ns.topdomain */
nsname = 0xc000 | ((p - buf) & 0x3fff);
putbyte(&p, 2);
putbyte(&p, 'n');
putbyte(&p, 's');
putshort(&p, topname); /* Name Server */
/* Additional data (A-record of NS server) */
putshort(&p, nsname); /* Name Server */
putshort(&p, T_A); /* Type */
putshort(&p, C_IN); /* Class */
putlong(&p, 0x3ea7d011); /* TTL */
putshort(&p, 4); /* Data length */
/* ugly hack to output IP address */
domain = (char *) &q->destination;
putbyte(&p, *domain++);
putbyte(&p, *domain++);
putbyte(&p, *domain++);
putbyte(&p, *domain);
len = p - buf;
return len;
}
short
dns_get_id(char *packet, size_t packetlen)
{
HEADER *header;
header = (HEADER*)packet;
if (packetlen < sizeof(HEADER))
return 0;
return ntohs(header->id);
}
int
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
{
char name[QUERY_NAME_SIZE];
char rdata[4*1024];
HEADER *header;
short qdcount;
short ancount;
char name[255];
uint32_t ttl;
short class;
short type;
@ -131,13 +222,35 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
ancount = ntohs(header->ancount);
id = ntohs(header->id);
id = id & 0xFFFF; /* Kill any sign extension */
rlen = 0;
switch (qr) {
case QR_ANSWER:
if(qdcount != 1 || ancount != 1) {
warnx("no query or answer in answer");
switch (header->rcode) {
case REFUSED:
warnx("Got REFUSED as reply");
break;
case NOTIMP:
warnx("Got NOTIMP as reply");
break;
case NXDOMAIN:
warnx("Got NXDOMAIN as reply");
break;
case SERVFAIL:
warnx("Got SERVFAIL as reply");
break;
case NOERROR:
default:
warnx("no query or answer in reply packet");
break;
}
return -1;
}
@ -156,28 +269,24 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
rv = MIN(rlen, sizeof(rdata));
rv = readdata(packet, &data, rdata, rv);
if(type == T_NULL && rv > 2) {
if(type == T_NULL && rv >= 2 && buf) {
rv = MIN(rv, buflen);
memcpy(buf, rdata, rv);
}
break;
case QR_QUERY:
if (qdcount != 1) {
warnx("no query on query");
warnx("no question section in name query");
return -1;
}
readname(packet, packetlen, &data, name, sizeof(name) -1);
name[256] = 0;
readname(packet, packetlen, &data, name, sizeof(name) - 1);
name[sizeof(name)-1] = '\0';
readshort(packet, &data, &type);
readshort(packet, &data, &class);
if(type != T_NULL) {
rv = 0;
break;
}
strncpy(q->name, name, 257);
strncpy(q->name, name, sizeof(q->name));
q->name[sizeof(q->name) - 1] = '\0';
q->type = type;
q->id = id;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -25,6 +25,8 @@ typedef enum {
} qr_t;
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain);
short dns_get_id(char *packet, size_t packetlen);
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
#endif /* _DNS_H_ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -35,7 +35,7 @@ inline_dotify(char *buf, size_t buflen)
char *reader, *writer;
total = strlen(buf);
dots = total / 62;
dots = total / 57;
writer = buf;
writer += total;
@ -52,12 +52,12 @@ inline_dotify(char *buf, size_t buflen)
pos = (unsigned) (reader - buf) + 1;
while (dots) {
if (pos % 62 == 0) {
*writer-- = *reader--;
pos--;
if (pos % 57 == 0) {
*writer-- = '.';
dots--;
}
*writer-- = *reader--;
pos--;
}
/* return new length of string */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -23,6 +23,8 @@ struct encoder {
int (*decode) (void *, size_t *, const char *, size_t);
int (*places_dots) (void);
int (*eats_dots) (void);
int (*blocksize_raw)(void);
int (*blocksize_encoded)(void);
};
int unpack_data(char *, size_t, char *, size_t, struct encoder *);

49
src/fw_query.c Normal file
View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "fw_query.h"
static struct fw_query fwq[FW_QUERY_CACHE_SIZE];
static int fwq_ix;
void fw_query_init()
{
memset(fwq, 0, sizeof(struct fw_query) * FW_QUERY_CACHE_SIZE);
fwq_ix = 0;
}
void fw_query_put(struct fw_query *fw_query)
{
memcpy(&(fwq[fwq_ix]), fw_query, sizeof(struct fw_query));
++fwq_ix;
if (fwq_ix >= FW_QUERY_CACHE_SIZE)
fwq_ix = 0;
}
void fw_query_get(short query_id, struct fw_query **fw_query)
{
int i;
*fw_query = NULL;
for (i = 0; i < FW_QUERY_CACHE_SIZE; i++) {
if (fwq[i].id == query_id) {
*fw_query = &(fwq[i]);
return;
}
}
}

36
src/fw_query.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FW_QUERY_H__
#define __FW_QUERY_H__
#include <sys/types.h>
#include <sys/socket.h>
#define FW_QUERY_CACHE_SIZE 16
struct fw_query {
struct sockaddr addr;
int addrlen;
short id;
};
void fw_query_init();
void fw_query_put(struct fw_query *fw_query);
void fw_query_get(short query_id, struct fw_query **fw_query);
#endif /*__FW_QUERY_H__*/

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -23,9 +23,12 @@
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <err.h>
#include <grp.h>
#include <pwd.h>
#include <arpa/inet.h>
#include <zlib.h>
@ -37,6 +40,7 @@
#include "common.h"
#include "encoding.h"
#include "base32.h"
#include "base64.h"
#include "dns.h"
#include "login.h"
#include "tun.h"
@ -46,25 +50,46 @@ static void send_ping(int fd);
static void send_chunk(int fd);
static int build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain);
const char *topdomain, struct encoder *encoder);
int running = 1;
char password[33];
static int running = 1;
static char password[33];
struct sockaddr_in peer;
static struct sockaddr_in nameserv;
static char *topdomain;
uint16_t rand_seed;
static uint16_t rand_seed;
static int downstream_seqno;
static int downstream_fragment;
static int down_ack_seqno;
static int down_ack_fragment;
/* Current IP packet */
static char activepacket[4096];
static int max_downstream_frag_size;
static int autodetect_frag_size;
/* Current up/downstream IP packet */
static struct packet outpkt;
static struct packet inpkt;
/* My userid at the server */
static char userid;
static int lastlen;
static int packetpos;
static int packetlen;
/* DNS id for next packet */
static uint16_t chunkid;
static struct encoder *enc;
/* Base32 encoder used for non-data packets */
static struct encoder *b32;
/* The encoder used for data packets
* Defaults to Base32, can be changed after handshake */
static struct encoder *dataenc;
/* result of case preservation check done after login */
static int case_preserved;
#if !defined(BSD) && !defined(__GLIBC__)
static char *__progname;
#endif
static void
sighandler(int sig)
@ -73,43 +98,49 @@ sighandler(int sig)
}
static void
send_packet(int fd, char cmd, const char *data, const size_t datalen)
send_query(int fd, char *hostname)
{
char packet[4096];
struct query q;
char buf[4096];
size_t len;
q.id = ++chunkid;
q.type = T_NULL;
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname));
sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv));
}
static void
send_packet(int fd, char cmd, const char *data, const size_t datalen)
{
char buf[4096];
buf[0] = cmd;
len = build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain);
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32);
send_query(fd, buf);
}
static int
build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain)
const char *topdomain, struct encoder *encoder)
{
int encsize;
unsigned space;
size_t space;
char *b;
space = MIN(0xFF, buflen) - strlen(topdomain) - 2;
if (!enc->places_dots())
space -= (space / 62); /* space for dots */
space = MIN(0xFF, buflen) - strlen(topdomain) - 5;
if (!encoder->places_dots())
space -= (space / 57); /* space for dots */
memset(buf, 0, buflen);
encsize = enc->encode(buf, &space, data, datalen);
encsize = encoder->encode(buf, &space, data, datalen);
if (!enc->places_dots())
if (!encoder->places_dots())
inline_dotify(buf, buflen);
b = buf;
@ -123,42 +154,62 @@ build_hostname(char *buf, size_t buflen,
return space;
}
int
static int
is_sending()
{
return (packetlen != 0);
return (outpkt.len != 0);
}
int
static int
read_dns(int fd, char *buf, int buflen)
{
struct sockaddr_in from;
char packet[64*1024];
char data[64*1024];
socklen_t addrlen;
struct query q;
int rv;
int r;
addrlen = sizeof(struct sockaddr);
if ((r = recvfrom(fd, packet, sizeof(packet), 0,
(struct sockaddr*)&from, &addrlen)) == -1) {
if ((r = recvfrom(fd, data, sizeof(data), 0,
(struct sockaddr*)&from, &addrlen)) == -1) {
warn("recvfrom");
return 0;
}
rv = dns_decode(buf, buflen, &q, QR_ANSWER, packet, r);
rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r);
/* decode the data header, update seqno and frag before next request */
if (rv >= 2) {
downstream_seqno = (buf[1] >> 5) & 7;
downstream_fragment = (buf[1] >> 1) & 15;
}
if (is_sending()) {
if (chunkid == q.id) {
/* Got ACK on sent packet */
outpkt.offset += outpkt.sentlen;
if (outpkt.offset == outpkt.len) {
/* Packet completed */
outpkt.offset = 0;
outpkt.len = 0;
outpkt.sentlen = 0;
/* If the ack contains unacked frag number but no data,
* send a ping to ack the frag number and get more data*/
if (rv == 2 && (
downstream_seqno != down_ack_seqno ||
downstream_fragment != down_ack_fragment
)) {
send_ping(fd);
}
} else {
/* More to send */
send_chunk(fd);
}
if (is_sending() && chunkid == q.id) {
/* Got ACK on sent packet */
packetpos += lastlen;
if (packetpos == packetlen) {
/* Packet completed */
packetpos = 0;
packetlen = 0;
lastlen = 0;
} else {
/* More to send */
send_chunk(fd);
}
}
return rv;
@ -181,10 +232,12 @@ tunnel_tun(int tun_fd, int dns_fd)
inlen = read;
compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
memcpy(activepacket, out, MIN(outlen, sizeof(activepacket)));
lastlen = 0;
packetpos = 0;
packetlen = outlen;
memcpy(outpkt.data, out, MIN(outlen, sizeof(outpkt.data)));
outpkt.sentlen = 0;
outpkt.offset = 0;
outpkt.len = outlen;
outpkt.seqno++;
outpkt.fragment = 0;
send_chunk(dns_fd);
@ -194,21 +247,40 @@ tunnel_tun(int tun_fd, int dns_fd)
static int
tunnel_dns(int tun_fd, int dns_fd)
{
unsigned long outlen;
unsigned long inlen;
char out[64*1024];
char in[64*1024];
unsigned long datalen;
char buf[64*1024];
size_t read;
if ((read = read_dns(dns_fd, in, sizeof(in))) <= 0)
return -1;
outlen = sizeof(out);
inlen = read;
if (uncompress((uint8_t*)out, &outlen, (uint8_t*)in, inlen) != Z_OK)
if ((read = read_dns(dns_fd, buf, sizeof(buf))) <= 2)
return -1;
write_tun(tun_fd, out, outlen);
if (downstream_seqno != inpkt.seqno) {
/* New packet */
inpkt.seqno = downstream_seqno;
inpkt.fragment = downstream_fragment;
inpkt.len = 0;
} else if (downstream_fragment <= inpkt.fragment) {
/* Duplicate fragment */
return -1;
}
inpkt.fragment = downstream_fragment;
datalen = MIN(read - 2, sizeof(inpkt.data) - inpkt.len);
/* Skip 2 byte data header and append to packet */
memcpy(&inpkt.data[inpkt.len], &buf[2], datalen);
inpkt.len += datalen;
if (buf[1] & 1) { /* If last fragment flag is set */
/* Uncompress packet and send to tun */
datalen = sizeof(buf);
if (uncompress((uint8_t*)buf, &datalen, (uint8_t*) inpkt.data, inpkt.len) == Z_OK) {
write_tun(tun_fd, buf, datalen);
}
inpkt.len = 0;
}
/* If we have nothing to send, send a ping to get more data */
if (!is_sending())
send_ping(dns_fd);
@ -229,9 +301,11 @@ tunnel(int tun_fd, int dns_fd)
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&fds);
if (!is_sending())
if (!is_sending()) {
FD_SET(tun_fd, &fds);
}
FD_SET(dns_fd, &fds);
i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
@ -263,36 +337,38 @@ static void
send_chunk(int fd)
{
char hex[] = "0123456789ABCDEF";
char packet[4096];
struct query q;
char buf[4096];
int avail;
int code;
char *p;
int len;
q.id = ++chunkid;
q.type = T_NULL;
p = outpkt.data;
p += outpkt.offset;
avail = outpkt.len - outpkt.offset;
p = activepacket;
p += packetpos;
avail = packetlen - packetpos;
outpkt.sentlen = build_hostname(buf + 4, sizeof(buf) - 4, p, avail, topdomain, dataenc);
lastlen = build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain);
/* Build upstream data header (see doc/proto_xxxxxxxx.txt) */
if (lastlen == avail)
code = 1;
else
code = 0;
code |= (userid << 1);
buf[0] = hex[code];
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
buf[0] = hex[userid & 15]; /* First byte is 4 bits userid */
sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2);
buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */
code = ((outpkt.fragment & 3) << 3) | (downstream_seqno & 7);
buf[2] = b32_5to8(code); /* Third byte is 2 bits lower fragment count, 3 bits downstream packet seqno */
code = ((downstream_fragment & 15) << 1) | (outpkt.sentlen == avail);
buf[3] = b32_5to8(code); /* Fourth byte is 4 bits downstream fragment count, 1 bit last frag flag */
down_ack_seqno = downstream_seqno;
down_ack_fragment = downstream_fragment;
outpkt.fragment++;
send_query(fd, buf);
}
void
static void
send_login(int fd, char *login, int len)
{
char data[19];
@ -312,24 +388,66 @@ send_login(int fd, char *login, int len)
static void
send_ping(int fd)
{
char data[3];
char data[4];
if (is_sending()) {
lastlen = 0;
packetpos = 0;
packetlen = 0;
outpkt.sentlen = 0;
outpkt.offset = 0;
outpkt.len = 0;
}
data[0] = userid;
data[1] = (rand_seed >> 8) & 0xff;
data[2] = (rand_seed >> 0) & 0xff;
data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15);
data[2] = (rand_seed >> 8) & 0xff;
data[3] = (rand_seed >> 0) & 0xff;
down_ack_seqno = downstream_seqno;
down_ack_fragment = downstream_fragment;
rand_seed++;
send_packet(fd, 'P', data, sizeof(data));
}
void
static void
send_fragsize_probe(int fd, int fragsize)
{
char probedata[256];
char buf[4096];
/* build a large query domain which is random and maximum size */
memset(probedata, MIN(1, rand_seed & 0xff), sizeof(probedata));
probedata[1] = MIN(1, (rand_seed >> 8) & 0xff);
rand_seed++;
build_hostname(buf + 4, sizeof(buf) - 4, probedata, sizeof(probedata), topdomain, dataenc);
fragsize &= 2047;
buf[0] = 'r'; /* Probe downstream fragsize packet */
buf[1] = b32_5to8((userid << 1) | (fragsize & 1024));
buf[2] = b32_5to8((fragsize >> 5) & 31);
buf[3] = b32_5to8(fragsize & 31);
send_query(fd, buf);
}
static void
send_set_downstream_fragsize(int fd, int fragsize)
{
char data[5];
data[0] = userid;
data[1] = (fragsize & 0xff00) >> 8;
data[2] = (fragsize & 0x00ff);
data[3] = (rand_seed >> 8) & 0xff;
data[4] = (rand_seed >> 0) & 0xff;
rand_seed++;
send_packet(fd, 'N', data, sizeof(data));
}
static void
send_version(int fd, uint32_t version)
{
char data[6];
@ -347,6 +465,29 @@ send_version(int fd, uint32_t version)
send_packet(fd, 'V', data, sizeof(data));
}
static void
send_case_check(int fd)
{
/* The '+' plus character is not allowed according to RFC.
* Expect to get SERVFAIL or similar if it is rejected.
*/
char buf[512] = "zZ+-aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY1234.";
strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf);
}
static void
send_codec_switch(int fd, int userid, int bits)
{
char buf[512] = "S__.";
buf[1] = b32_5to8(userid);
buf[2] = b32_5to8(bits);
strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf);
}
static int
handshake(int dns_fd)
{
@ -377,33 +518,36 @@ handshake(int dns_fd)
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if(read < 0) {
perror("read");
if(read <= 0) {
if (read == 0) {
warn("handshake read");
}
/* if read < 0 then warning has been printed already */
continue;
}
if (read >= 9) {
payload = (((in[4] & 0xff) << 24) |
((in[5] & 0xff) << 16) |
((in[6] & 0xff) << 8) |
((in[7] & 0xff)));
((in[5] & 0xff) << 16) |
((in[6] & 0xff) << 8) |
((in[7] & 0xff)));
if (strncmp("VACK", in, 4) == 0) {
seed = payload;
userid = in[8];
printf("Version ok, both running 0x%08x. You are user #%d\n", VERSION, userid);
printf("Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid);
goto perform_login;
} else if (strncmp("VNAK", in, 4) == 0) {
errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n",
warnx("You use protocol v 0x%08x, server uses v 0x%08x. Giving up",
VERSION, payload);
/* NOTREACHED */
return 1;
} else if (strncmp("VFUL", in, 4) == 0) {
errx(1, "server full, all %d slots are taken. try again later\n", payload);
/* NOTREACHED */
warnx("Server full, all %d slots are taken. Try again later", payload);
return 1;
}
} else
warnx("did not receive proper login challenge\n");
warnx("did not receive proper login challenge");
}
printf("Retrying version check...\n");
@ -434,17 +578,18 @@ perform_login:
}
if (read > 0) {
int netmask;
if (strncmp("LNAK", in, 4) == 0) {
printf("Bad password\n");
return 1;
} else if (sscanf(in, "%64[^-]-%64[^-]-%d",
server, client, &mtu) == 3) {
} else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d",
server, client, &mtu, &netmask) == 4) {
server[64] = 0;
client[64] = 0;
if (tun_setip(client) == 0 &&
if (tun_setip(client, netmask) == 0 &&
tun_setmtu(mtu) == 0) {
return 0;
goto perform_case_check;
} else {
warnx("Received handshake with bad data");
}
@ -456,23 +601,230 @@ perform_login:
printf("Retrying login...\n");
}
warnx("couldn't login to server");
return 1;
perform_case_check:
case_preserved = 0;
for (i=0; running && i<5 ;i++) {
tv.tv_sec = i + 1;
tv.tv_usec = 0;
send_case_check(dns_fd);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if (read > 0) {
if (in[0] == 'z' || in[0] == 'Z') {
if (read < (27 * 2)) {
printf("Received short case check reply. Will use base32 encoder\n");
goto switch_codec;
} else {
int k;
/* TODO enhance this, base128 is probably also possible */
case_preserved = 1;
for (k = 0; k < 27 && case_preserved; k += 2) {
if (in[k] == in[k+1]) {
/* test string: zZ+-aAbBcCdDeE... */
case_preserved = 0;
}
}
goto switch_codec;
}
} else {
printf("Received bad case check reply\n");
}
} else {
printf("Got error on case check, will use base32\n");
goto switch_codec;
}
}
printf("Retrying case check...\n");
}
printf("No reply on case check, continuing\n");
switch_codec:
if (!case_preserved)
goto autodetect_max_fragsize;
dataenc = get_base64_encoder();
printf("Switching to %s codec\n", dataenc->name);
/* Send to server that this user will use base64 from now on */
for (i=0; running && i<5 ;i++) {
int bits;
tv.tv_sec = i + 1;
tv.tv_usec = 0;
bits = 6; /* base64 = 6 bits per byte */
send_codec_switch(dns_fd, userid, bits);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if (read > 0) {
if (strncmp("BADLEN", in, 6) == 0) {
printf("Server got bad message length. ");
goto codec_revert;
} else if (strncmp("BADIP", in, 5) == 0) {
printf("Server rejected sender IP address. ");
goto codec_revert;
} else if (strncmp("BADCODEC", in, 8) == 0) {
printf("Server rejected the selected codec. ");
goto codec_revert;
}
in[read] = 0; /* zero terminate */
printf("Server switched to codec %s\n", in);
goto autodetect_max_fragsize;
}
}
printf("Retrying codec switch...\n");
}
printf("No reply from server on codec switch. ");
codec_revert:
printf("Falling back to base32\n");
dataenc = get_base32_encoder();
autodetect_max_fragsize:
if (autodetect_frag_size) {
int proposed_fragsize = 768;
int range = 768;
max_downstream_frag_size = 0;
printf("Autoprobing max downstream fragment size... (skip with -m fragsize)\n");
while (running && range > 0 && (range >= 8 || !max_downstream_frag_size)) {
for (i=0; running && i<3 ;i++) {
tv.tv_sec = 1;
tv.tv_usec = 0;
send_fragsize_probe(dns_fd, proposed_fragsize);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if (read > 0) {
/* We got a reply */
int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
if (acked_fragsize == proposed_fragsize) {
printf("%d ok.. ", acked_fragsize);
fflush(stdout);
max_downstream_frag_size = acked_fragsize;
range >>= 1;
proposed_fragsize += range;
continue;
}
}
}
}
printf("%d not ok.. ", proposed_fragsize);
fflush(stdout);
range >>= 1;
proposed_fragsize -= range;
}
if (!running) {
printf("\n");
warnx("stopped while autodetecting fragment size (Try probing manually with -m)");
return 1;
}
if (range == 0) {
/* Tried all the way down to 2 and found no good size */
printf("\n");
warnx("found no accepted fragment size. (Try probing manually with -m)");
return 1;
}
printf("will use %d\n", max_downstream_frag_size);
}
printf("Setting downstream fragment size to max %d...\n", max_downstream_frag_size);
for (i=0; running && i<5 ;i++) {
tv.tv_sec = i + 1;
tv.tv_usec = 0;
send_set_downstream_fragsize(dns_fd, max_downstream_frag_size);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if (read > 0) {
int accepted_fragsize;
if (strncmp("BADFRAG", in, 7) == 0) {
printf("Server rejected fragsize. Keeping default.");
goto done;
} else if (strncmp("BADIP", in, 5) == 0) {
printf("Server rejected sender IP address.\n");
goto done;
}
accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff);
goto done;
}
}
printf("Retrying set fragsize...\n");
}
printf("No reply from server when setting fragsize. Keeping default.\n");
done:
return 0;
}
static void
set_target(const char *host)
static char *
get_resolvconf_addr()
{
struct hostent *h;
static char addr[16];
char buf[80];
char *rv;
FILE *fp;
rv = NULL;
h = gethostbyname(host);
if (!h)
err(1, "couldn't resolve name %s", host);
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
err(1, "/etc/resolve.conf");
while (feof(fp) == 0) {
fgets(buf, sizeof(buf), fp);
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_port = htons(53);
peer.sin_addr = *((struct in_addr *) h->h_addr);
if (sscanf(buf, "nameserver %15s", addr) == 1) {
rv = addr;
break;
}
}
fclose(fp);
return rv;
}
static void
set_nameserver(const char *cp)
{
struct in_addr addr;
if (inet_aton(cp, &addr) != 1)
errx(1, "error parsing nameserver address: '%s'", cp);
memset(&nameserv, 0, sizeof(nameserv));
nameserv.sin_family = AF_INET;
nameserv.sin_port = htons(53);
nameserv.sin_addr = addr;
}
static void
@ -480,7 +832,7 @@ usage() {
extern char *__progname;
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"nameserver topdomain\n", __progname);
"[-P password] [-m maxfragsize] [nameserver] topdomain\n", __progname);
exit(2);
}
@ -490,7 +842,7 @@ help() {
printf("iodine IP over DNS tunneling client\n");
printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
"[-P password] nameserver topdomain\n", __progname);
"[-P password] [-m maxfragsize] [nameserver] topdomain\n", __progname);
printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n");
printf(" -f to keep running in foreground\n");
@ -498,7 +850,8 @@ help() {
printf(" -t dir to chroot to directory dir\n");
printf(" -d device to set tunnel device name\n");
printf(" -P password used for authentication (max 32 chars will be used)\n");
printf("nameserver is the IP number of the relaying nameserver\n");
printf(" -m maxfragsize, to limit size of downstream packets\n");
printf("nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
exit(0);
@ -506,12 +859,8 @@ help() {
static void
version() {
char *svnver;
svnver = "$Rev$ from $Date$";
printf("iodine IP over DNS tunneling client\n");
printf("SVN version: %s\n", svnver);
printf("version: 0.5.0 from 2009-01-23\n");
exit(0);
}
@ -519,6 +868,7 @@ version() {
int
main(int argc, char **argv)
{
char *nameserv_addr;
struct passwd *pw;
char *username;
int foreground;
@ -535,18 +885,35 @@ main(int argc, char **argv)
device = NULL;
chunkid = 0;
enc = get_base32_encoder();
outpkt.seqno = 0;
inpkt.len = 0;
autodetect_frag_size = 1;
max_downstream_frag_size = 3072;
b32 = get_base32_encoder();
dataenc = get_base32_encoder();
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
#if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/');
if (__progname == NULL)
__progname = argv[0];
else
__progname++;
#endif
while ((choice = getopt(argc, argv, "vfhu:t:d:P:m:")) != -1) {
switch(choice) {
case 'v':
version();
/* NOTREACHED */
break;
case 'f':
foreground = 1;
break;
case 'h':
help();
/* NOTREACHED */
break;
case 'u':
username = optarg;
@ -558,8 +925,15 @@ main(int argc, char **argv)
device = optarg;
break;
case 'P':
strncpy(password, optarg, 32);
password[32] = 0;
strncpy(password, optarg, sizeof(password));
password[sizeof(password)-1] = 0;
/* XXX: find better way of cleaning up ps(1) */
memset(optarg, 0, strlen(optarg));
break;
case 'm':
autodetect_frag_size = 0;
max_downstream_frag_size = atoi(optarg);
break;
default:
usage();
@ -568,37 +942,63 @@ main(int argc, char **argv)
}
if (geteuid() != 0) {
printf("Run as root and you'll be happy.\n");
warnx("Run as root and you'll be happy.\n");
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
if (argc != 2)
switch (argc) {
case 1:
nameserv_addr = get_resolvconf_addr();
topdomain = strdup(argv[0]);
break;
case 2:
nameserv_addr = argv[0];
topdomain = strdup(argv[1]);
break;
default:
usage();
/* NOTREACHED */
}
topdomain = strdup(argv[1]);
if (max_downstream_frag_size < 1 || max_downstream_frag_size > 0xffff) {
warnx("Use a max frag size between 1 and 65535 bytes.\n");
usage();
/* NOTREACHED */
}
if(username) {
pw = getpwnam(username);
if (!pw) {
printf("User %s does not exist!\n", username);
set_nameserver(nameserv_addr);
if(strlen(topdomain) <= 128) {
if(check_topdomain(topdomain)) {
warnx("Topdomain contains invalid characters.\n");
usage();
/* NOTREACHED */
}
} else {
warnx("Use a topdomain max 128 chars long.\n");
usage();
/* NOTREACHED */
}
if (username != NULL) {
if ((pw = getpwnam(username)) == NULL) {
warnx("User %s does not exist!\n", username);
usage();
/* NOTREACHED */
}
}
if (strlen(password) == 0) {
printf("Enter password on stdin:\n");
scanf("%32s", password);
password[32] = 0;
}
if (strlen(password) == 0)
read_password(password, sizeof(password));
if ((tun_fd = open_tun(device)) == -1)
goto cleanup1;
if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
goto cleanup2;
set_target(argv[0]);
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
@ -606,21 +1006,29 @@ main(int argc, char **argv)
if(handshake(dns_fd))
goto cleanup2;
printf("Sending queries for %s to %s\n", argv[1], argv[0]);
printf("Sending queries for %s to %s\n", topdomain, nameserv_addr);
do_chroot(newroot);
if (foreground == 0)
do_detach();
if (newroot != NULL)
do_chroot(newroot);
if (username) {
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
printf("Could not switch to user %s!\n", username);
if (username != NULL) {
gid_t gids[1];
gids[0] = pw->pw_gid;
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
warnx("Could not switch to user %s!\n", username);
usage();
/* NOTREACHED */
}
}
if (!foreground) {
do_detach();
}
downstream_seqno = 0;
downstream_fragment = 0;
down_ack_seqno = 0;
down_ack_fragment = 0;
tunnel(tun_fd, dns_fd);
cleanup2:

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

27
src/osflags Executable file
View file

@ -0,0 +1,27 @@
#!/bin/sh
case $1 in
link)
case `uname` in
SunOS | solaris)
echo '-lsocket -lnsl';
;;
BeOS)
echo '-lsocket -lbind -lbsd';
;;
Haiku)
echo '-lnetwork';
;;
esac
;;
cflags)
case `uname` in
BeOS)
echo '-Dsocklen_t=int';
;;
esac
;;
*)
;;
esac

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -58,7 +58,9 @@ open_tun(const char *tun_device)
if (tun_device != NULL) {
strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ);
ifreq.ifr_name[IFNAMSIZ-1] = '\0';
strncpy(if_name, tun_device, sizeof(if_name));
if_name[sizeof(if_name)-1] = '\0';
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
printf("Opened %s\n", ifreq.ifr_name);
@ -102,6 +104,7 @@ open_tun(const char *tun_device)
if (tun_device != NULL) {
snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
strncpy(if_name, tun_device, sizeof(if_name));
if_name[sizeof(if_name)-1] = '\0';
if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
warn("open_tun: %s: %s", tun_name, strerror(errno));
@ -140,7 +143,7 @@ close_tun(int tun_fd)
}
int
write_tun(int tun_fd, char *data, int len)
write_tun(int tun_fd, char *data, size_t len)
{
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
data += 4;
@ -166,8 +169,8 @@ write_tun(int tun_fd, char *data, int len)
return 0;
}
int
read_tun(int tun_fd, char *buf, int len)
ssize_t
read_tun(int tun_fd, char *buf, size_t len)
{
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD)
/* FreeBSD/Darwin/NetBSD has no header */
@ -178,30 +181,42 @@ read_tun(int tun_fd, char *buf, int len)
}
int
tun_setip(const char *ip)
tun_setip(const char *ip, int netbits)
{
char cmdline[512];
int netmask;
struct in_addr net;
int i;
#ifndef LINUX
int r;
#endif
netmask = 0;
for (i = 0; i < netbits; i++) {
netmask = (netmask << 1) | 1;
}
netmask <<= (32 - netbits);
net.s_addr = htonl(netmask);
if (inet_addr(ip) != INADDR_NONE) {
snprintf(cmdline, sizeof(cmdline),
"/sbin/ifconfig %s %s %s netmask 255.255.255.0",
"/sbin/ifconfig %s %s %s netmask %s",
if_name,
ip,
ip);
ip,
inet_ntoa(net));
printf("Setting IP of %s to %s\n", if_name, ip);
#ifndef LINUX
int r;
r = system(cmdline);
if(r != 0) {
return r;
} else {
snprintf(cmdline, sizeof(cmdline),
"/sbin/route add %s/24 %s",
ip, ip);
"/sbin/route add %s/%d %s",
ip, netbits, ip);
}
printf("Adding route %s/24 to %s\n", ip, ip);
printf("Adding route %s/%d to %s\n", ip, netbits, ip);
#endif
return system(cmdline);
} else {
@ -212,20 +227,20 @@ tun_setip(const char *ip)
}
int
tun_setmtu(const int mtu)
tun_setmtu(const unsigned mtu)
{
char cmdline[512];
if (mtu > 200 && mtu < 1500) {
snprintf(cmdline, sizeof(cmdline),
"/sbin/ifconfig %s mtu %d",
"/sbin/ifconfig %s mtu %u",
if_name,
mtu);
printf("Setting MTU of %s to %d\n", if_name, mtu);
printf("Setting MTU of %s to %u\n", if_name, mtu);
return system(cmdline);
} else {
warn("MTU out of range: %d\n", mtu);
warn("MTU out of range: %u\n", mtu);
}
return 1;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -19,9 +19,9 @@
int open_tun(const char *);
void close_tun(int);
int write_tun(int, char *, int);
int read_tun(int, char *, int);
int tun_setip(const char *);
int tun_setmtu(const int);
int write_tun(int, char *, size_t);
ssize_t read_tun(int, char *, size_t);
int tun_setip(const char *, int);
int tun_setmtu(const unsigned);
#endif /* _TUN_H_ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -14,13 +14,20 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <err.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "common.h"
#include "encoding.h"
@ -28,22 +35,59 @@
struct user users[USERS];
void
init_users(in_addr_t my_ip)
int
init_users(in_addr_t my_ip, int netbits)
{
int i;
int skip = 0;
char newip[16];
int created_users = 0;
int maxusers;
in_addr_t netmask = 0;
struct in_addr net;
struct in_addr ipstart;
for (i = 0; i < netbits; i++) {
netmask = (netmask << 1) | 1;
}
netmask <<= (32 - netbits);
net.s_addr = htonl(netmask);
ipstart.s_addr = my_ip & net.s_addr;
maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */
memset(users, 0, USERS * sizeof(struct user));
for (i = 0; i < USERS; i++) {
in_addr_t ip;
users[i].id = i;
snprintf(newip, sizeof(newip), "0.0.0.%d", i + 1);
users[i].tun_ip = my_ip + inet_addr(newip);;
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
ip = ipstart.s_addr + inet_addr(newip);
if (ip == my_ip && skip == 0) {
/* This IP was taken by iodined */
skip++;
snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
ip = ipstart.s_addr + inet_addr(newip);
}
users[i].tun_ip = ip;
net.s_addr = ip;
if (maxusers-- < 1) {
users[i].disabled = 1;
} else {
users[i].disabled = 0;
created_users++;
}
users[i].inpacket.len = 0;
users[i].inpacket.offset = 0;
users[i].outpacket.len = 0;
users[i].q.id = 0;
users[i].out_acked_seqno = 0;
users[i].out_acked_fragment = 0;
users[i].fragsize = 4096;
}
return created_users;
}
int
@ -54,7 +98,8 @@ users_waiting_on_reply()
ret = 0;
for (i = 0; i < USERS; i++) {
if (users[i].active && users[i].last_pkt + 60 > time(NULL) &&
if (users[i].active && !users[i].disabled &&
users[i].last_pkt + 60 > time(NULL) &&
users[i].q.id != 0) {
ret++;
}
@ -71,7 +116,8 @@ find_user_by_ip(uint32_t ip)
ret = -1;
for (i = 0; i < USERS; i++) {
if (users[i].active && users[i].last_pkt + 60 > time(NULL) &&
if (users[i].active && !users[i].disabled &&
users[i].last_pkt + 60 > time(NULL) &&
ip == users[i].tun_ip) {
ret = i;
break;
@ -90,7 +136,8 @@ all_users_waiting_to_send()
ret = 1;
now = time(NULL);
for (i = 0; i < USERS; i++) {
if (users[i].active && users[i].last_pkt + 60 > now &&
if (users[i].active && !users[i].disabled &&
users[i].last_pkt + 60 > now &&
users[i].outpacket.len == 0) {
ret = 0;
break;
@ -106,7 +153,7 @@ find_available_user()
int i;
for (i = 0; i < USERS; i++) {
/* Not used at all or not used in one minute */
if (!users[i].active || users[i].last_pkt + 60 < time(NULL)) {
if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {
users[i].active = 1;
users[i].last_pkt = time(NULL);
ret = i;
@ -116,3 +163,11 @@ find_available_user()
return ret;
}
void
user_switch_codec(int userid, struct encoder *enc)
{
if (userid < 0 || userid >= USERS)
return;
users[userid].encoder = enc;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,28 +17,32 @@
#ifndef __USER_H__
#define __USER_H__
#define USERS 8
#define USERS 16
struct user {
char id;
int active;
int disabled;
time_t last_pkt;
int seed;
in_addr_t tun_ip;
struct sockaddr host;
int addrlen;
struct in_addr host;
struct query q;
struct packet inpacket;
struct packet outpacket;
struct encoder *encoder;
int out_acked_seqno;
int out_acked_fragment;
int fragsize;
};
extern struct user users[USERS];
void init_users(in_addr_t);
int init_users(in_addr_t, int);
int users_waiting_on_reply();
int find_user_by_ip(uint32_t);
int all_users_waiting_to_send();
int find_available_user();
void user_switch_codec(int userid, struct encoder *enc);
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -19,7 +19,7 @@
/* This is the version of the network protocol
It is usually equal to the latest iodine version number */
#define VERSION 0x00000401
#define VERSION 0x00000500
#endif /* _VERSION_H_ */

View file

@ -5,11 +5,12 @@ SRCOBJS = ../src/base32.o ../src/base64.o ../src/read.o ../src/dns.o ../src/enc
OS = `uname | tr "a-z" "A-Z"`
LDFLAGS = -L/usr/local/lib -lcheck
CFLAGS = -g -Wall -D$(OS) -I../src -I/usr/local/include -pedantic
CHECK_PATH = /usr/local
LDFLAGS = -L$(CHECK_PATH)/lib -lcheck `../src/osflags link`
CFLAGS = -g -Wall -D$(OS) -I../src -I$(CHECK_PATH)/include -pedantic `../src/osflags cflags`
all: $(TEST)
@./$(TEST)
@LD_LIBRARY_PATH=${CHECK_PATH}/lib ./$(TEST)
$(TEST): $(OBJS) $(SRCOBJS)
@echo LD $(TEST)
@ -21,6 +22,6 @@ $(TEST): $(OBJS) $(SRCOBJS)
clean:
@echo "Cleaning..."
@echo "Cleaning tests/"
@rm -f *~ *.core $(TEST) $(OBJS)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -31,23 +31,26 @@ static struct tuple
} testpairs[] = {
{ "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
{ "abc123", "mfrggmjsgm" },
{ NULL, NULL }
{ NULL, NULL }
};
START_TEST(test_base32_encode)
{
size_t len;
char buf[4096];
struct encoder *b32;
int val;
int i;
b32 = get_base32_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base32_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
val = b32->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].b));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
}
END_TEST
@ -56,17 +59,32 @@ START_TEST(test_base32_decode)
{
size_t len;
char buf[4096];
struct encoder *b32;
int val;
int i;
b32 = get_base32_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base32_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
val = b32->decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a));
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
}
END_TEST
START_TEST(test_base32_5to8_8to5)
{
int i;
int c;
for (i = 0; i < 32; i++) {
c = b32_5to8(i);
fail_unless(b32_8to5(c) == i);
}
}
END_TEST
@ -79,6 +97,7 @@ test_base32_create_tests()
tc = tcase_create("Base32");
tcase_add_test(tc, test_base32_encode);
tcase_add_test(tc, test_base32_decode);
tcase_add_test(tc, test_base32_5to8_8to5);
return tc;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -30,8 +30,8 @@ static struct tuple
char *b;
} testpairs[] = {
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
{ "abc123", "ywjJmtiZ" },
{
{ "abc1231", "ywjJmtiZmq" },
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
@ -41,11 +41,11 @@ static struct tuple
"\xBE\xEB\x6C\xAE\xAA\x68\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58"
"\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40",
"9abba876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfe999dcbapZ"
"776543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9abba87654"
"3210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfe999dcba"
"+9876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ"
"776543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654"
"3210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
},
{
{
"\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70\xBE\xEB\x6C\xAE\xAA\x68"
"\x9E\x69\x64\x8E\x28\x60\x7D\xE7\x5C\x6D\xA6\x58\x5D\x65\x54\x4D\x24\x50"
"\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40\x3F\x3F\x3C\xEF\xAE\x78"
@ -55,27 +55,30 @@ static struct tuple
"\xBE\xEB\x6C\xAE\xA1\x61\x91\x61\x61\x81\x28\x60\x7D\xE7\x5C\x6D\xA6\x58"
"\x5D\x65\x54\x4D\x24\x50\x3C\xE3\x4C\x2C\xA2\x48\x1C\x61\x44\x0C\x20\x40",
"9IJJI876543210-ZYXWVUTSRQPONMLK9LMJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ"
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcbaML87654321"
"+9876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ"
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654321"
"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
},
{ NULL, NULL }
{ NULL, NULL }
};
START_TEST(test_base64_encode)
{
size_t len;
char buf[4096];
struct encoder *b64;
int val;
int i;
b64 = get_base64_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
val = b64->encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a));
fail_unless(val > 0, strerror(errno));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].b));
fail_unless(strcmp(buf, testpairs[i].b) == 0,
"'%s' != '%s'", buf, testpairs[i].b);
}
}
END_TEST
@ -84,17 +87,20 @@ START_TEST(test_base64_decode)
{
size_t len;
char buf[4096];
struct encoder *b64;
int val;
int i;
b64 = get_base64_encoder();
for (i = 0; testpairs[i].a != NULL; i++) {
len = sizeof(buf);
val = base64_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
val = b64->decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b));
fail_unless(val > 0, strerror(errno));
fail_unless(buf != NULL, "buf == NULL");
fail_unless(strcmp(buf, testpairs[i].a) == 0,
va_str("'%s' != '%s'", buf, testpairs[i].a));
fail_unless(strcmp(buf, testpairs[i].a) == 0,
"'%s' != '%s'", buf, testpairs[i].a);
}
}
END_TEST

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -33,24 +33,31 @@
static void dump_packet(char *, size_t);
static char queryPacket[] =
static char queryPacket[] =
"\x05\x39\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\x2D\x41\x6A\x62\x63"
"\x75\x79\x74\x63\x70\x65\x62\x30\x67\x71\x30\x6C\x74\x65\x62\x75\x78"
"\x67\x69\x64\x75\x6E\x62\x73\x73\x61\x33\x64\x66\x6F\x6E\x30\x63\x61"
"\x7A\x64\x62\x6F\x72\x71\x71\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00"
"\x0A\x00\x01\x00\x00\x29\x10\x00\x00\x00\x80\x00\x00\x00";
static char answerPacket[] =
static char answerPacket[] =
"\x05\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
"\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20"
"\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
"\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
static char answerPacketHighTransId[] =
"\x85\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x05\x73\x69\x6C\x6C"
"\x79\x04\x68\x6F\x73\x74\x02\x6F\x66\x06\x69\x6F\x64\x69\x6E\x65\x04"
"\x63\x6F\x64\x65\x04\x6B\x72\x79\x6F\x02\x73\x65\x00\x00\x0A\x00\x01"
"\xC0\x0C\x00\x0A\x00\x01\x00\x00\x00\x00\x00\x23\x74\x68\x69\x73\x20"
"\x69\x73\x20\x74\x68\x65\x20\x6D\x65\x73\x73\x61\x67\x65\x20\x74\x6F"
"\x20\x62\x65\x20\x64\x65\x6C\x69\x76\x65\x72\x65\x64";
static char *msgData = "this is the message to be delivered";
static char *topdomain = "kryo.se";
static char *innerData = "HELLO this is the test data";
START_TEST(test_encode_query)
@ -88,7 +95,7 @@ START_TEST(test_encode_query)
dump_packet(buf, ret);
}
fail_unless(strncmp(queryPacket, buf, sizeof(queryPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
@ -112,7 +119,7 @@ START_TEST(test_decode_query)
unpack_data(buf, len, &(q.name[1]), (int) (domain - q.name) - 1, enc);
fail_unless(strncmp(buf, innerData, strlen(innerData)) == 0, "Did not extract expected host: '%s'", buf);
fail_unless(strlen(buf) == strlen(innerData), va_str("Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf));
fail_unless(strlen(buf) == strlen(innerData), "Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf);
}
END_TEST
@ -135,25 +142,43 @@ START_TEST(test_encode_response)
len = sizeof(answerPacket) - 1; /* Skip extra null character */
fail_unless(strncmp(answerPacket, buf, sizeof(answerPacket)) == 0, "Did not compile expected packet");
fail_unless(ret == len, va_str("Bad packet length: %d, expected %d", ret, len));
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
}
END_TEST
START_TEST(test_decode_response)
{
char buf[512];
struct query q;
int len;
int ret;
len = sizeof(buf);
memset(&buf, 0, sizeof(buf));
ret = dns_decode(buf, len, NULL, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacket, sizeof(answerPacket)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), va_str("Bad data length: %d, expected %d", ret, strlen(msgData)));
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
fail_unless(q.id == 0x0539);
}
END_TEST
START_TEST(test_decode_response_with_high_trans_id)
{
char buf[512];
struct query q;
int len;
int ret;
len = sizeof(buf);
memset(&buf, 0, sizeof(buf));
ret = dns_decode(buf, len, &q, QR_ANSWER, answerPacketHighTransId, sizeof(answerPacketHighTransId)-1);
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539);
}
END_TEST
static void
dump_packet(char *buf, size_t len)
{
@ -183,6 +208,7 @@ test_dns_create_tests()
tcase_add_test(tc, test_decode_query);
tcase_add_test(tc, test_encode_response);
tcase_add_test(tc, test_decode_response);
tcase_add_test(tc, test_decode_response_with_high_trans_id);
return tc;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -27,10 +27,12 @@ struct tuple
char *a;
char *b;
} dottests[] = {
{ "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a"},
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
{ "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaa"},
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
{ "abc123", "abc123" },
{ NULL, NULL }
};
@ -41,6 +43,7 @@ START_TEST(test_inline_dotify)
char temp[1024];
char *b;
i = 0;
while (dottests[i].a) {
memset(temp, 0, sizeof(temp));
strcpy(temp, dottests[i].a);
@ -48,7 +51,7 @@ START_TEST(test_inline_dotify)
inline_dotify(b, sizeof(temp));
fail_unless(strcmp(dottests[i].b, temp) == 0,
va_str("'%s' != '%s'", temp, dottests[i].b));
"'%s' != '%s'", temp, dottests[i].b);
i++;
}
}
@ -60,6 +63,7 @@ START_TEST(test_inline_undotify)
char temp[1024];
char *b;
i = 0;
while (dottests[i].a) {
memset(temp, 0, sizeof(temp));
strcpy(temp, dottests[i].b);
@ -67,7 +71,7 @@ START_TEST(test_inline_undotify)
inline_undotify(b, sizeof(temp));
fail_unless(strcmp(dottests[i].a, temp) == 0,
va_str("'%s' != '%s'", temp, dottests[i].a));
"'%s' != '%s'", temp, dottests[i].a);
i++;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -33,7 +33,7 @@
#include "dns.h"
#include "read.h"
#include "test.h"
START_TEST(test_read_putshort)
{
unsigned short k;
@ -44,15 +44,15 @@ START_TEST(test_read_putshort)
for (i = 0; i < 65536; i++) {
p = (char*)&k;
putshort(&p, i);
fail_unless(ntohs(k) == i,
va_str("Bad value on putshort for %d: %d != %d",
i, ntohs(k), i));
fail_unless(ntohs(k) == i,
"Bad value on putshort for %d: %d != %d",
i, ntohs(k), i);
p = (char*)&k;
readshort(NULL, &p, (short *) &l);
fail_unless(l == i,
va_str("Bad value on readshort for %d: %d != %d",
i, l, i));
"Bad value on readshort for %d: %d != %d",
i, l, i);
}
}
END_TEST
@ -71,14 +71,14 @@ START_TEST(test_read_putlong)
putlong(&p, j);
fail_unless(ntohl(k) == j,
va_str("Bad value on putlong for %d: %d != %d", i, ntohl(j), j));
fail_unless(ntohl(k) == j,
"Bad value on putlong for %d: %d != %d", i, ntohl(j), j);
p = (char*)&k;
readlong(NULL, &p, &l);
fail_unless(l == j,
va_str("Bad value on readlong for %d: %d != %d", i, l, j));
"Bad value on readlong for %d: %d != %d", i, l, j);
}
}
END_TEST
@ -87,11 +87,11 @@ START_TEST(test_read_name)
{
unsigned char emptyloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char infloop[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char longname[] =
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
unsigned char longname[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
@ -100,15 +100,15 @@ START_TEST(test_read_name)
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
"\x00\x00\x01\x00\x01";
unsigned char onejump[] =
unsigned char onejump[] =
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
"\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
unsigned char badjump[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
unsigned char badjump2[] = {
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
unsigned char *jumper;
char buf[1024];
char *data;
@ -119,13 +119,13 @@ START_TEST(test_read_name)
buf[1023] = 'A';
rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
fail_unless(buf[1023] == 'A', NULL);
memset(buf, 0, sizeof(buf));
data = (char*) infloop + sizeof(HEADER);
buf[4] = '\a';
rv = readname((char*) infloop, sizeof(infloop), &data, buf, 4);
fail_unless(buf[4] == '\a', NULL);
memset(buf, 0, sizeof(buf));
data = (char*) longname + sizeof(HEADER);
buf[256] = '\a';
@ -136,7 +136,7 @@ START_TEST(test_read_name)
data = (char*) onejump + sizeof(HEADER);
rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);
fail_unless(rv == 9, NULL);
/* These two tests use malloc to cause segfault if jump is executed */
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump));
@ -149,7 +149,7 @@ START_TEST(test_read_name)
fail_unless(buf[0] == 0, NULL);
}
free(jumper);
memset(buf, 0, sizeof(buf));
jumper = malloc(sizeof(badjump2));
if (jumper) {
@ -158,8 +158,8 @@ START_TEST(test_read_name)
rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
fail_unless(rv == 4, NULL);
fail_unless(strcmp("BA.", buf) == 0,
va_str("buf is not BA: %s", buf));
fail_unless(strcmp("BA.", buf) == 0,
"buf is not BA: %s", buf);
}
free(jumper);
}
@ -184,11 +184,11 @@ START_TEST(test_putname)
fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
}
END_TEST
START_TEST(test_putname_nodot)
{
char buf[256];
char *nodot =
char *nodot =
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *b;
@ -205,11 +205,11 @@ START_TEST(test_putname_nodot)
fail_unless(b == buf, NULL);
}
END_TEST
START_TEST(test_putname_toolong)
{
char buf[256];
char *toolong =
char *toolong =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -22,20 +22,6 @@
#include "test.h"
char *
va_str(const char *fmt, ...)
{
static char buf[512];
va_list ap;
memset(buf, 0, sizeof(buf));
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
int
main()
{
@ -68,7 +54,7 @@ main()
suite_add_tcase(iodine, test);
runner = srunner_create(iodine);
srunner_run_all(runner, CK_VERBOSE);
srunner_run_all(runner, CK_NORMAL);
failed = srunner_ntests_failed(runner);
srunner_free(runner);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -34,7 +34,7 @@ START_TEST(test_init_users)
int i;
ip = inet_addr("127.0.0.1");
init_users(ip);
init_users(ip, 27);
for (i = 0; i < USERS; i++) {
fail_unless(users[i].id == i);
fail_unless(users[i].q.id == 0);
@ -51,7 +51,7 @@ START_TEST(test_users_waiting)
in_addr_t ip;
ip = inet_addr("127.0.0.1");
init_users(ip);
init_users(ip, 27);
fail_unless(users_waiting_on_reply() == 0);
@ -75,7 +75,7 @@ START_TEST(test_find_user_by_ip)
unsigned int testip;
ip = inet_addr("127.0.0.1");
init_users(ip);
init_users(ip, 27);
testip = (unsigned int) inet_addr("10.0.0.1");
fail_unless(find_user_by_ip(testip) == -1);
@ -100,7 +100,7 @@ START_TEST(test_all_users_waiting_to_send)
in_addr_t ip;
ip = inet_addr("127.0.0.1");
init_users(ip);
init_users(ip, 27);
fail_unless(all_users_waiting_to_send() == 1);
@ -124,7 +124,7 @@ START_TEST(test_find_available_user)
int i;
ip = inet_addr("127.0.0.1");
init_users(ip);
init_users(ip, 27);
for (i = 0; i < USERS; i++) {
fail_unless(find_available_user() == i);
@ -146,6 +146,34 @@ START_TEST(test_find_available_user)
}
END_TEST
START_TEST(test_find_available_user_small_net)
{
in_addr_t ip;
int i;
ip = inet_addr("127.0.0.1");
init_users(ip, 29); /* this should result in 5 enabled users */
for (i = 0; i < 5; i++) {
fail_unless(find_available_user() == i);
}
for (i = 0; i < USERS; i++) {
fail_unless(find_available_user() == -1);
}
users[3].active = 0;
fail_unless(find_available_user() == 3);
fail_unless(find_available_user() == -1);
users[3].last_pkt = 55;
fail_unless(find_available_user() == 3);
fail_unless(find_available_user() == -1);
}
END_TEST
TCase *
test_user_create_tests()
{
@ -157,6 +185,7 @@ test_user_create_tests()
tcase_add_test(tc, test_find_user_by_ip);
tcase_add_test(tc, test_all_users_waiting_to_send);
tcase_add_test(tc, test_find_available_user);
tcase_add_test(tc, test_find_available_user_small_net);
return tc;
}