mirror of
https://github.com/yarrick/iodine.git
synced 2025-04-10 12:31:00 +00:00
Compare commits
163 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f41c4bb9f3 | ||
|
30a3bb9445 | ||
|
134fa90727 | ||
|
46293b51b1 | ||
|
fa9b145af1 | ||
|
2b7bf00e1a | ||
|
7a1733ae82 | ||
|
d7f07d2f1f | ||
|
db13d81caf | ||
|
9a139b7005 | ||
|
49e448fb19 | ||
|
9f3e397475 | ||
|
3ac090f847 | ||
|
ab75dae208 | ||
|
168b05e3f7 | ||
|
9f2730cb9a | ||
|
dfd6f9aa90 | ||
|
0ed202dd18 | ||
|
78aaf26369 | ||
|
20cfb002c3 | ||
|
d5f0dac459 | ||
|
55d9ddb8dd | ||
|
7dd38fec17 | ||
|
f8eb4c952b | ||
|
f5e58e6527 | ||
|
3f79d948bf | ||
|
c742fe79c3 | ||
|
7791035364 | ||
|
58f789307b | ||
|
d027a60859 | ||
|
da6eee279a | ||
|
b66dc4ea51 | ||
|
3b4cc0989c | ||
|
7335940130 | ||
|
18e0042ce4 | ||
|
89fdbc104b | ||
|
458b5af003 | ||
|
9d8e9a7d18 | ||
|
e06ce0a213 | ||
|
a83164fad8 | ||
|
c7d1620cad | ||
|
fbb874c1ab | ||
|
48df1d896a | ||
|
b639436375 | ||
|
33b5ef9bf9 | ||
|
5450372a75 | ||
|
900a0e8df7 | ||
|
46f7eccf54 | ||
|
3740894350 | ||
|
cb0fa56232 | ||
|
55176af538 | ||
|
2eb78f9e8c | ||
|
b4893e8a8b | ||
|
4203f115f5 | ||
|
e8ee981f97 | ||
|
524522d00a | ||
|
de2912c089 | ||
|
6f097a4cb3 | ||
|
4c805fef6a | ||
|
d40c464ac1 | ||
|
8eccbf097a | ||
|
63d65bb30e | ||
|
e359f64003 | ||
|
6ca1b992bb | ||
|
d4e1eef6d5 | ||
|
c96b83e3d2 | ||
|
b619662201 | ||
|
fb3fa24edb | ||
|
6531d5e72b | ||
|
edf7e5a565 | ||
|
2270063464 | ||
|
55a689e759 | ||
|
188e69aa1f | ||
|
798bbb64db | ||
|
9c74eb09a7 | ||
|
d2b11c44b1 | ||
|
ad8afce8e1 | ||
|
9019b0639d | ||
|
dce8f8352b | ||
|
fc6106153f | ||
|
9fa70acc69 | ||
|
2ab94a7991 | ||
|
468bd706cb | ||
|
7b90054346 | ||
|
4d79bf6368 | ||
|
e4e23275c9 | ||
|
d6ec29be4d | ||
|
6d1a003c1e | ||
|
30014e6433 | ||
|
f2596cef24 | ||
|
71c5fe99ce | ||
|
adabd28b46 | ||
|
3f4852edab | ||
|
bc76b588c9 | ||
|
e7de432088 | ||
|
321781ad85 | ||
|
ddaebb0074 | ||
|
cb3115865d | ||
|
b121f638d0 | ||
|
ac46718c16 | ||
|
98061ccc0e | ||
|
5460c8eb0a | ||
|
29b2348ca6 | ||
|
6fa0d98c99 | ||
|
9ca4130e9a | ||
|
3eb835afe7 | ||
|
fd45a20f30 | ||
|
4c6aae9e90 | ||
|
de4a726cb9 | ||
|
317e1efbd6 | ||
|
c8726f2c5d | ||
|
3b7927b2dc | ||
|
9e60b36430 | ||
|
fc632e6311 | ||
|
d12d0fcff5 | ||
|
7f48d0d99f | ||
|
212a3b93e6 | ||
|
b55c3f432b | ||
|
c4a2b0c27f | ||
|
2d8b2655ea | ||
|
fe75007109 | ||
|
509f445c1e | ||
|
f47c750c98 | ||
|
f265e4637f | ||
|
b6340acfb3 | ||
|
3b43db2529 | ||
|
bd2ed87022 | ||
|
5adeafddfa | ||
|
c22752d1f5 | ||
|
488412d4e6 | ||
|
b0c6924a8e | ||
|
32bd132d43 | ||
|
643178b207 | ||
|
e6286cc03c | ||
|
e5ee739537 | ||
|
0b9a532bbe | ||
|
d9ca124e18 | ||
|
c6f46ebaf9 | ||
|
e889185aca | ||
|
1f9a0273db | ||
|
04487efe96 | ||
|
f6735782b1 | ||
|
d5ffc25557 | ||
|
aae94200a5 | ||
|
17c41d87bc | ||
|
4e582e98c6 | ||
|
11748b2963 | ||
|
5f6b7131cc | ||
|
ea30edd76f | ||
|
a4684f5ebf | ||
|
83f2e56426 | ||
|
639fb5f6aa | ||
|
bb74190ed5 | ||
|
acc8b798e3 | ||
|
d978ed47bc | ||
|
d679babb67 | ||
|
63f9098aa0 | ||
|
42fcc07379 | ||
|
9b7863a668 | ||
|
502205f1a1 | ||
|
854c7ed1c1 | ||
|
4d079b95f2 | ||
|
5c9ff9ba06 |
41 changed files with 2413 additions and 775 deletions
52
CHANGELOG
52
CHANGELOG
|
@ -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)
|
||||
|
|
38
Makefile
38
Makefile
|
@ -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
46
README
|
@ -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
61
doc/proto_00000402.txt
Normal 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
112
doc/proto_00000500.txt
Normal 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.
|
86
man/iodine.8
86
man/iodine.8
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
81
src/base32.c
81
src/base32.c
|
@ -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';
|
||||
|
|
|
@ -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
|
||||
|
|
217
src/base64.c
217
src/base64.c
|
@ -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';
|
||||
|
|
|
@ -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
|
||||
|
|
110
src/common.c
110
src/common.c
|
@ -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;
|
||||
}
|
||||
|
|
33
src/common.h
33
src/common.h
|
@ -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
139
src/dns.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
49
src/fw_query.c
Normal 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
36
src/fw_query.h
Normal 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__*/
|
||||
|
702
src/iodine.c
702
src/iodine.c
|
@ -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:
|
||||
|
|
938
src/iodined.c
938
src/iodined.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
|
@ -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
27
src/osflags
Executable 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
47
src/tun.c
47
src/tun.c
|
@ -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;
|
||||
|
|
10
src/tun.h
10
src/tun.h
|
@ -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_ */
|
||||
|
|
77
src/user.c
77
src/user.c
|
@ -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;
|
||||
}
|
||||
|
|
14
src/user.h
14
src/user.h
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
46
tests/dns.c
46
tests/dns.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
54
tests/read.c
54
tests/read.c
|
@ -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."
|
||||
|
|
18
tests/test.c
18
tests/test.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
41
tests/user.c
41
tests/user.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue