new branch
This commit is contained in:
commit
cf92d48f61
|
@ -21,6 +21,15 @@ CHANGES:
|
||||||
- Do not overwrite users CC/CFLAGS/LDFLAGS, only add to them.
|
- Do not overwrite users CC/CFLAGS/LDFLAGS, only add to them.
|
||||||
- Added -F option to write pidfile, based on patch from
|
- Added -F option to write pidfile, based on patch from
|
||||||
misc at mandriva.org. Fixes #70.
|
misc at mandriva.org. Fixes #70.
|
||||||
|
- Allow password to be set via environment variable, fixes #77.
|
||||||
|
Based on patch by logix.
|
||||||
|
- Client now prints server tunnel IP, fixes #78. Patch by logix.
|
||||||
|
- Fix build error on Mac OS X 10.6, patch by G. Rischard. #79.
|
||||||
|
- Added support for CNAME/TXT/A/MX query types, fixes #75.
|
||||||
|
Patch by Anne Bezemer, merge help by logix.
|
||||||
|
- Merged low-latency patch from Anne Bezemer, fixes #76.
|
||||||
|
- Resolve client nameserver argument if given as hostname, fixes #82.
|
||||||
|
- Open log before chroot, fixes #86: logging on FreeBSD.
|
||||||
|
|
||||||
2009-06-01: 0.5.2 "WifiFree"
|
2009-06-01: 0.5.2 "WifiFree"
|
||||||
- Fixed client segfault on OS X, #57
|
- Fixed client segfault on OS X, #57
|
||||||
|
|
314
README
314
README
|
@ -11,12 +11,12 @@ firewalled, but DNS queries are allowed.
|
||||||
QUICKSTART:
|
QUICKSTART:
|
||||||
|
|
||||||
Try it out within your own LAN! Follow these simple steps:
|
Try it out within your own LAN! Follow these simple steps:
|
||||||
- On your server, run: ./iodined -f 10.0.0.1 test.asdf
|
- On your server, run: ./iodined -f 10.0.0.1 test.com
|
||||||
(If you already use the 10.0.0.0 network, use another internal net like
|
(If you already use the 10.0.0.0 network, use another internal net like
|
||||||
172.16.0.0)
|
172.16.0.0)
|
||||||
- Enter a password
|
- Enter a password
|
||||||
- On the client, run: ./iodine -f 192.168.0.1 test.asdf
|
- On the client, run: ./iodine -f -r 192.168.0.1 test.com
|
||||||
(Replace 192.168.0.1 with the server's ip address)
|
(Replace 192.168.0.1 with your server's ip address)
|
||||||
- Enter the same password
|
- Enter the same password
|
||||||
- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
|
- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
|
||||||
- Try pinging each other through the tunnel
|
- Try pinging each other through the tunnel
|
||||||
|
@ -26,69 +26,196 @@ To actually use it through a relaying nameserver, see below.
|
||||||
|
|
||||||
HOW TO USE:
|
HOW TO USE:
|
||||||
|
|
||||||
|
Note: server and client are required to speak the exact same protocol. In most
|
||||||
|
cases, this means running the same iodine version. Unfortunately, implementing
|
||||||
|
backward and forward protocol compatibility is usually not feasible.
|
||||||
|
|
||||||
Server side:
|
Server side:
|
||||||
To use this tunnel, you need control over a real domain (like mytunnel.com),
|
To use this tunnel, you need control over a real domain (like mydomain.com),
|
||||||
and a server with a public IP number. If the server already runs a DNS
|
and a server with a public IP address to run iodined on. If this server
|
||||||
server, change the listening port and then use the -b option to let
|
already runs a DNS program, change its listening port and then use iodined's
|
||||||
iodined forward the DNS requests. Then, delegate a subdomain
|
-b option to let iodined forward the DNS requests. (Note that this procedure
|
||||||
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
|
is not advised in production environments, because iodined's DNS forwarding
|
||||||
add these lines to the zone file:
|
is not completely transparent.)
|
||||||
|
|
||||||
tunnel1host IN A 10.15.213.99
|
Then, delegate a subdomain (say, t1.mydomain.com) to the iodined server.
|
||||||
tunnel1 IN NS tunnel1host.mytunnel.com.
|
If you use BIND for your domain, add two lines like these to the zone file:
|
||||||
|
|
||||||
Do not use CNAME instead of A above.
|
t1 IN NS t1ns.mydomain.com. ; note the dot!
|
||||||
If your server has a dynamic IP, use a dynamic dns provider:
|
t1ns IN A 10.15.213.99
|
||||||
|
|
||||||
tunnel1 IN NS tunnel1host.mydyndnsprovider.com
|
The "NS" line is all that's needed to route queries for the "t1" subdomain
|
||||||
|
to the "t1ns" server. We use a short name for the subdomain, to keep as much
|
||||||
|
space as possible available for the data traffic. At the end of the "NS" line
|
||||||
|
is the name of your iodined server. This can be any name, pointing anywhere,
|
||||||
|
but in this case it's easily kept in the same zone file. It must be a name
|
||||||
|
(not an IP address), and that name itself must have an A record (not a CNAME).
|
||||||
|
|
||||||
Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent
|
If your iodined server has a dynamic IP, use a dynamic dns provider. Simply
|
||||||
to your server. Start iodined on the server. The first argument is the tunnel
|
point the "NS" line to it, and leave the "A" line out:
|
||||||
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
|
t1 IN NS myname.mydyndnsprovider.com. ; note the dot!
|
||||||
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
|
Then reload or restart your nameserver program. Now any DNS queries for
|
||||||
password on the commandline (-P pass) or after the server has started. Now
|
domains ending in t1.mydomain.com will be sent to your iodined server.
|
||||||
everything is ready for the client.
|
|
||||||
|
Finally start iodined on your server. The first argument is the IP address
|
||||||
|
inside the tunnel, which can be from any range that you don't use yet (for
|
||||||
|
example 192.168.99.1), and the second argument is the assigned domain (in this
|
||||||
|
case t1.mydomain.com). Using the -f option will keep iodined running in the
|
||||||
|
foreground, which helps when testing. iodined will open a virtual interface
|
||||||
|
("tun device"), and will 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 everything is ready for the client.
|
||||||
|
|
||||||
|
If there is a chance you'll be using an iodine tunnel from unexpected
|
||||||
|
environments, start iodined with a -c option.
|
||||||
|
|
||||||
|
Resulting commandline in this example situation:
|
||||||
|
./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com
|
||||||
|
|
||||||
Client side:
|
Client side:
|
||||||
All the setup is done, just start iodine. It takes up to two arguments, the
|
All the setup is done, just start iodine. It takes one or two arguments, the
|
||||||
first is the local relaying DNS server (optional) and the second is the domain
|
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
|
you used (t1.mydomain.com). If you don't specify the first argument, the
|
||||||
can use the tunnel endpoint (example: 10.15.213.99 or tunnel1host.mytunnel.com)
|
system's current DNS setting will be consulted.
|
||||||
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
|
If DNS queries are allowed to any computer, you can directly give the iodined
|
||||||
the server either by argument or after the client has started. Now you should
|
server's address as first argument (in the example: t1ns.mydomain.com or
|
||||||
be able to ping the other end of the tunnel from either side.
|
10.15.213.99). In that case, it may also happen that _any_ traffic is allowed
|
||||||
|
to the DNS port (53 UDP) of any computer. Iodine will detect this, and switch
|
||||||
|
to raw UDP tunneling if possible. To force DNS tunneling in any case, use the
|
||||||
|
-r option (especially useful when testing within your own network).
|
||||||
|
|
||||||
|
The client's tunnel interface will get an IP close to the server's (in this
|
||||||
|
case 192.168.99.2 or .3 etc.) and a suitable MTU. Enter the same password as
|
||||||
|
on the server either as commandline option or after the client has started.
|
||||||
|
Using the -f option will keep the iodine client running in the foreground.
|
||||||
|
|
||||||
|
Resulting commandline in this example situation:
|
||||||
|
./iodine -f -P secretpassword t1.mydomain.com
|
||||||
|
(add -r to force DNS tunneling even if raw UDP tunneling would be possible)
|
||||||
|
|
||||||
|
From either side, you should now be able to ping the IP address on the other
|
||||||
|
end of the tunnel. In this case, ping 192.168.99.1 from the iodine client, and
|
||||||
|
192.168.99.2 or .3 etc. from the iodine server.
|
||||||
|
|
||||||
|
|
||||||
MISC. INFO:
|
MISC. INFO:
|
||||||
|
|
||||||
Routing:
|
Routing:
|
||||||
The normal case is to route all traffic through the DNS tunnel. To do this, first
|
It is possible to route all traffic through the DNS tunnel. To do this, first
|
||||||
add a route to the nameserver you use with the default gateway as gateway. Then
|
add a host route to the nameserver used by iodine over the wired/wireless
|
||||||
replace the default gateway with the servers IP address within the DNS tunnel,
|
interface with the default gateway as gateway. Then replace the default
|
||||||
and configure the server to do NAT.
|
gateway with the iodined server's IP address inside the DNS tunnel, and
|
||||||
|
configure the server to do NAT.
|
||||||
|
|
||||||
MTU issues:
|
However, note that the tunneled data traffic is not encrypted at all, and can
|
||||||
These issues should be solved now, with automatic fragmentation of downstream
|
be read and changed by external parties relatively easily. For maximum
|
||||||
packets. There should be no need to set the MTU explicitly on the server.
|
security, run a VPN through the DNS tunnel (=double tunneling), or use secure
|
||||||
|
shell (SSH) access, possibly with port forwarding. The latter can also be used
|
||||||
|
for web browsing, when you run a web proxy (for example Privoxy) on your
|
||||||
|
server.
|
||||||
|
|
||||||
|
Testing:
|
||||||
|
The iodined server replies to NS requests sent for subdomains of the tunnel
|
||||||
|
domain. If your iodined subdomain is t1.mydomain.com, send a NS request for
|
||||||
|
foo123.t1.mydomain.com to see if the delegation works. dig is a good tool
|
||||||
|
for this:
|
||||||
|
dig -t NS foo123.t1.mydomain.com
|
||||||
|
|
||||||
|
Also, the iodined server will answer requests starting with 'z' for any of the
|
||||||
|
supported request types, for example:
|
||||||
|
dig -t TXT z456.t1.mydomain.com
|
||||||
|
dig -t SRV z456.t1.mydomain.com
|
||||||
|
dig -t CNAME z456.t1.mydomain.com
|
||||||
|
The reply should look like garbled text in all these cases.
|
||||||
|
|
||||||
|
Operational info:
|
||||||
|
The DNS-response fragment size is normally autoprobed to get maximum bandwidth.
|
||||||
|
To force a specific value (and speed things up), use the -m option.
|
||||||
|
|
||||||
|
The DNS hostnames are normally used up to their maximum length, 255 characters.
|
||||||
|
Some DNS relays have been found that answer full-length queries rather
|
||||||
|
unreliably, giving widely varying (and mostly very bad) results of the
|
||||||
|
fragment size autoprobe on repeated tries. In these cases, use the -M switch
|
||||||
|
to reduce the DNS hostname length to for example 200 characters, which makes
|
||||||
|
these DNS relays much more stable. This is also useful on some "de-optimizing"
|
||||||
|
DNS relays that stuff the response with two full copies of the query, leaving
|
||||||
|
very little space for downstream data (also not capable of EDNS0). The -M
|
||||||
|
switch can trade some upstream bandwidth for downstream bandwidth. Note that
|
||||||
|
the minimum -M value is about 100, since the protocol can split packets (1200
|
||||||
|
bytes max) in only 16 fragments, requiring at least 75 real data bytes per
|
||||||
|
fragment.
|
||||||
|
|
||||||
|
The upstream data is sent gzipped encoded with Base32; or Base64 if the relay
|
||||||
|
server supports mixed case and '+' in domain names; or Base64u if '_' is
|
||||||
|
supported instead; or Base128 if high-byte-value characters are supported.
|
||||||
|
This upstream encoding is autodetected. The 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.
|
||||||
|
|
||||||
|
Several DNS request types are supported, with the NULL type expected to provide
|
||||||
|
the largest downstream bandwidth. Other available types are TXT, SRV, MX,
|
||||||
|
CNAME and A (returning CNAME), in decreasing bandwidth order. Normally the
|
||||||
|
"best" request type is autodetected and used. However, DNS relays may impose
|
||||||
|
limits on for example NULL and TXT, making SRV or MX actually the best choice.
|
||||||
|
This is not autodetected, but can be forced using the -T option. It is
|
||||||
|
advisable to try various alternatives especially when the autodetected request
|
||||||
|
type provides a downstream fragment size of less than 200 bytes.
|
||||||
|
|
||||||
|
Note that SRV, MX and A (returning CNAME) queries may/will cause additional
|
||||||
|
lookups by "smart" caching nameservers to get an actual IP address, which may
|
||||||
|
either slow down or fail completely.
|
||||||
|
|
||||||
|
DNS responses for non-NULL queries can be encoded with the same set of codecs
|
||||||
|
as upstream data. This is normally also autodetected, but no fully exhaustive
|
||||||
|
tests are done, so some problems may not be noticed when selecting more
|
||||||
|
advanced codecs. In that case, you'll see failures/corruption in the fragment
|
||||||
|
size autoprobe. In particular, several DNS relays have been found that change
|
||||||
|
replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when that
|
||||||
|
hostname exceeds ca. 180 characters. In these and similar cases, use the -O
|
||||||
|
option to try other downstream codecs; Base32 should always work.
|
||||||
|
|
||||||
|
Normal operation now is for the server to _not_ answer a DNS request until
|
||||||
|
the next DNS request has come in, a.k.a. being "lazy". This way, the server
|
||||||
|
will always have a DNS request handy when new downstream data has to be sent.
|
||||||
|
This greatly improves (interactive) performance and latency, and allows to
|
||||||
|
slow down the quiescent ping requests to 4 second intervals by default, and
|
||||||
|
possibly much slower. In fact, the main purpose of the pings now is to force
|
||||||
|
a reply to the previous ping, and prevent DNS server timeouts (usually at
|
||||||
|
least 5-10 seconds per RFC1035). Some DNS servers are more impatient and will
|
||||||
|
give SERVFAIL errors (timeouts) in periods without tunneled data traffic. All
|
||||||
|
data should still get through in these cases, but iodine will reduce the ping
|
||||||
|
interval to 1 second anyway (-I1) to reduce the number of error messages. This
|
||||||
|
may not help for very impatient DNS relays like dnsadvantage.com (ultradns),
|
||||||
|
which time out in 1 second or even less. Yet data will still get trough, and
|
||||||
|
you can ignore the SERVFAIL errors.
|
||||||
|
|
||||||
|
If you are running on a local network without any DNS server in-between, try
|
||||||
|
-I 50 (iodine and iodined close the connection after 60 seconds of silence).
|
||||||
|
The only time you'll notice a slowdown, is when DNS reply packets go missing;
|
||||||
|
the iodined server then has to wait for a new ping to re-send the data. You can
|
||||||
|
speed this up by generating some upstream traffic (keypress, ping). If this
|
||||||
|
happens often, check your network for bottlenecks and/or run with -I1.
|
||||||
|
|
||||||
|
The delayed answering in lazy mode will cause some "carrier grade" commercial
|
||||||
|
DNS relays to repeatedly re-send the same DNS query to the iodined server.
|
||||||
|
If the DNS relay is actually implemented as a pool of parallel servers,
|
||||||
|
duplicate requests may even arrive from multiple sources. This effect will
|
||||||
|
only be visible in the network traffic at the iodined server, and will not
|
||||||
|
affect the client's connection. Iodined will notice these duplicates, and send
|
||||||
|
the same answer (when its time has come) to both the original query and the
|
||||||
|
latest duplicate. After that, the full answer is cached for a short while.
|
||||||
|
Delayed duplicates that arrive at the server even later, get a reply that the
|
||||||
|
iodine client will ignore (if it ever arrives there).
|
||||||
|
|
||||||
If you have problems, try inspecting the traffic with network monitoring tools
|
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
|
like tcpdump or ethereal/wireshark, and make sure that the relaying DNS server
|
||||||
cached error message could mean that you started the client before the server.
|
has not cached the response. A cached error message could mean that you
|
||||||
The -D option on the server can also show received and sent queries.
|
started the client before the server. The -D (and -DD) option on the server
|
||||||
|
can also show received and sent queries.
|
||||||
The iodined server replies to NS requests sent for subdomains of the tunnel
|
|
||||||
domain. If your domain is tunnel.com, send a NS request for foo.tunnel.com
|
|
||||||
to see if the delegation works. dig is a good tool for this:
|
|
||||||
dig -t NS foo123.tunnel.com
|
|
||||||
|
|
||||||
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:
|
TIPS & TRICKS:
|
||||||
|
@ -99,6 +226,92 @@ use for instance iptables (on Linux) to forward the traffic:
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
|
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
|
||||||
(Sent in by Tom Schouten)
|
(Sent in by Tom Schouten)
|
||||||
|
|
||||||
|
Iodined will reject data from clients that have not been active (data/pings)
|
||||||
|
for more than 60 seconds. Similarly, iodine will exit when no downstream
|
||||||
|
data has been received for 60 seconds. In case of a long network outage or
|
||||||
|
similar, just restart iodine (re-login), possibly multiple times until you get
|
||||||
|
your old IP address back. Once that's done, just wait a while, and you'll
|
||||||
|
eventually see the tunneled TCP traffic continue to flow from where it left
|
||||||
|
off before the outage.
|
||||||
|
|
||||||
|
With the introduction of the downstream packet queue in the server, its memory
|
||||||
|
usage has increased with several megabytes in the default configuration.
|
||||||
|
For use in low-memory environments (e.g. running on your DSL router), you can
|
||||||
|
decrease USERS and undefine OUTPACKETQ_LEN in user.h without any ill conse-
|
||||||
|
quence, assuming at most one client will be connected at any time. A small
|
||||||
|
DNSCACHE_LEN is still advised, preferably 2 or higher, however you can also
|
||||||
|
undefine it to save a few more kilobytes.
|
||||||
|
|
||||||
|
|
||||||
|
PERFORMANCE:
|
||||||
|
|
||||||
|
This section tabulates some performance measurements. To view properly, use
|
||||||
|
a fixed-width font like Courier.
|
||||||
|
|
||||||
|
Measurements were done in protocol 00000502 in lazy mode; upstream encoding
|
||||||
|
always Base128; iodine -M255; iodined -m1130. Network conditions were not
|
||||||
|
extremely favorable; results are not benchmarks but a realistic indication of
|
||||||
|
real-world performance that can be expected in similar situations.
|
||||||
|
|
||||||
|
Upstream/downstream throughput was measured by scp'ing a file previously
|
||||||
|
read from /dev/urandom (i.e. incompressible), and measuring size with
|
||||||
|
"ls -l ; sleep 30 ; ls -l" on a separate non-tunneled connection. Given the
|
||||||
|
large scp block size of 16 kB, this gives a resolution of 4.3 kbit/s, which
|
||||||
|
explains why some values are exactly equal.
|
||||||
|
Ping round-trip times measured with "ping -c100", presented are average rtt
|
||||||
|
and mean deviation (indicating spread around the average), in milliseconds.
|
||||||
|
|
||||||
|
|
||||||
|
Situation 1:
|
||||||
|
Laptop -> Wifi AP -> Home server -> DSL provider -> Datacenter
|
||||||
|
iodine DNS "relay" bind9 DNS cache iodined
|
||||||
|
|
||||||
|
downstr. upstream downstr. ping-up ping-down
|
||||||
|
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
iodine -> Wifi AP :53
|
||||||
|
-Tnull (= -Oraw) 982 43.6 131.0 28.0 4.6 26.8 3.4
|
||||||
|
|
||||||
|
iodine -> Home server :53
|
||||||
|
-Tnull (= -Oraw) 1174 48.0 305.8 26.6 5.0 26.9 8.4
|
||||||
|
|
||||||
|
iodine -> DSL provider :53
|
||||||
|
-Tnull (= -Oraw) 1174 56.7 367.0 20.6 3.1 21.2 4.4
|
||||||
|
-Ttxt -Obase32 730 56.7 174.7*
|
||||||
|
-Ttxt -Obase64 874 56.7 174.7
|
||||||
|
-Ttxt -Obase128 1018 56.7 174.7
|
||||||
|
-Ttxt -Oraw 1162 56.7 358.2
|
||||||
|
-Tsrv -Obase128 910 56.7 174.7
|
||||||
|
-Tcname -Obase32 151 56.7 43.6
|
||||||
|
-Tcname -Obase128 212 56.7 52.4
|
||||||
|
|
||||||
|
iodine -> DSL provider :53
|
||||||
|
wired (no Wifi) -Tnull 1174 74.2 585.4 20.2 5.6 19.6 3.4
|
||||||
|
|
||||||
|
[174.7* : these all have 2frag/packet]
|
||||||
|
|
||||||
|
|
||||||
|
Situation 2:
|
||||||
|
Laptop -> Wifi+vpn / wired -> Home server
|
||||||
|
iodine iodined
|
||||||
|
|
||||||
|
downstr. upstream downstr. ping-up ping-down
|
||||||
|
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
wifi + openvpn -Tnull 1186 166.0 1022.3 6.3 1.3 6.6 1.6
|
||||||
|
|
||||||
|
wired -Tnull 1186 677.2 2464.1 1.3 0.2 1.3 0.1
|
||||||
|
|
||||||
|
|
||||||
|
Performance is strongly coupled to low ping times, as iodine requires
|
||||||
|
confirmation for every data fragment before moving on to the next. Allowing
|
||||||
|
multiple fragments in-flight like TCP could possibly increase performance,
|
||||||
|
but it would likely cause serious overload for the intermediary DNS servers.
|
||||||
|
The current protocol scales performance with DNS responsivity, since the
|
||||||
|
DNS servers are on average handling at most one DNS request per client.
|
||||||
|
|
||||||
|
|
||||||
PORTABILITY:
|
PORTABILITY:
|
||||||
|
|
||||||
|
@ -125,6 +338,7 @@ THANKS:
|
||||||
AUTHORS & LICENSE:
|
AUTHORS & LICENSE:
|
||||||
|
|
||||||
Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
||||||
|
Also major contributions by Anne Bezemer.
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any purpose
|
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
|
with or without fee is hereby granted, provided that the above copyright notice
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
Detailed specification of protocol in version 00000501
|
|
||||||
======================================================
|
|
||||||
|
|
||||||
Note: work in progress!!
|
|
||||||
|
|
||||||
======================================================
|
|
||||||
1. DNS protocol
|
|
||||||
======================================================
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
IP Request:
|
|
||||||
Client sends:
|
|
||||||
First byte i or I
|
|
||||||
5 bits coded as Base32 char, meaning userid
|
|
||||||
CMC
|
|
||||||
Server replies
|
|
||||||
BADIP if bad userid, or
|
|
||||||
I and then 4 bytes network order external IP address of iodined server
|
|
||||||
|
|
||||||
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
|
|
||||||
CMC
|
|
||||||
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
|
|
||||||
BADLEN if length of query is too short
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
======================================================
|
|
||||||
2. Raw UDP protocol
|
|
||||||
======================================================
|
|
||||||
|
|
||||||
All Raw UDP protcol messages start with a 3 byte header: 0x10d19e
|
|
||||||
This is not the start of a valid DNS message so it is easy to identify.
|
|
||||||
The fourth byte contains the command and the user id.
|
|
||||||
|
|
||||||
7654 3210
|
|
||||||
+----+----+
|
|
||||||
|CCCC|UUUU|
|
|
||||||
+----+----+
|
|
||||||
|
|
||||||
Login message (command = 1):
|
|
||||||
The header is followed by a MD5 hash with the same password as in the DNS
|
|
||||||
login. The client starts the raw mode by sending this message, and uses
|
|
||||||
the login challenge +1, and the server responds using the login challenge -1.
|
|
||||||
After the login message has been exchanged, both the server and the client
|
|
||||||
switch to raw udp mode for the rest of the connection.
|
|
||||||
|
|
||||||
Data message (command = 2):
|
|
||||||
After the header comes the payload data, which may be compressed.
|
|
||||||
|
|
||||||
Ping message (command = 3):
|
|
||||||
Sent from client to server and back to keep session open. Has no payload.
|
|
||||||
|
|
142
iodine/CHANGELOG
142
iodine/CHANGELOG
|
@ -1,142 +0,0 @@
|
||||||
|
|
||||||
iodine - http://code.kryo.se/iodine
|
|
||||||
|
|
||||||
***********************************
|
|
||||||
|
|
||||||
CHANGES:
|
|
||||||
|
|
||||||
20xx-xx-xx: x.y.z "Hotspotify"
|
|
||||||
- Fixed tunnel not working on Windows.
|
|
||||||
- Any device name is now supported on Windows, fixes #47.
|
|
||||||
- Multiple installed TAP32 interfaces are now supported, fixes #46.
|
|
||||||
- Return nonzero if tunnel fails to open, fixes #62.
|
|
||||||
- Support for setting a SELinux context, based on patch by
|
|
||||||
Sebastien Raveau. Sample context file in doc/iodine.te
|
|
||||||
- Allow listen port and DNS forward port to be the same if listen IP
|
|
||||||
does not include localhost.
|
|
||||||
- The client will now exit if configuring IP or MTU fails.
|
|
||||||
- The starting cache miss value is randomized at startup, fixes #65.
|
|
||||||
- Raw UDP mode added. If the iodined server is reachable directly,
|
|
||||||
packets can be sent to it without DNS encoding. Fixes #36.
|
|
||||||
- Do not overwrite users CC/CFLAGS/LDFLAGS, only add to them.
|
|
||||||
- Added -F option to write pidfile, based on patch from
|
|
||||||
misc at mandriva.org. Fixes #70.
|
|
||||||
- Allow password to be set via environment variable, fixes #77.
|
|
||||||
Based on patch by logix.
|
|
||||||
- Client now prints server tunnel IP, fixes #78. Patch by logix.
|
|
||||||
- Fix build error on Mac OS X 10.6, patch by G. Rischard. #79.
|
|
||||||
- Added support for CNAME/TXT/A/MX query types, fixes #75.
|
|
||||||
Patch by Anne Bezemer, merge help by logix.
|
|
||||||
- Merged low-latency patch from Anne Bezemer, fixes #76.
|
|
||||||
- Resolve client nameserver argument if given as hostname, fixes #82.
|
|
||||||
- Open log before chroot, fixes #86: logging on FreeBSD.
|
|
||||||
|
|
||||||
2009-06-01: 0.5.2 "WifiFree"
|
|
||||||
- Fixed client segfault on OS X, #57
|
|
||||||
- Added check that nameserver lookup was successful
|
|
||||||
- Fixed ENOTSOCK error on OS X and FreeBSD, #58.
|
|
||||||
|
|
||||||
2009-03-21: 0.5.1 "Boringo"
|
|
||||||
- Added initial Windows support, fixes #43.
|
|
||||||
- Added length check of autoprobe responses
|
|
||||||
- Refactored and added unit tests
|
|
||||||
- Added syslog logging for iodined on version and login packets
|
|
||||||
- Fixed segfault when encoding just one block, fixes #51.
|
|
||||||
The normal code was never affected by this.
|
|
||||||
- Added win32 code to read DNS server from system, fixes #45.
|
|
||||||
- Disabled password echo on win32, fixes #44.
|
|
||||||
- Fix encoding error making all autoprobing > 1024 bytes fail, #52.
|
|
||||||
- Increase default interface MTU to 1200.
|
|
||||||
- Fix autoprobing error making every third probe fail, set IP flag
|
|
||||||
Dont-Fragment where supported. Fixes #54.
|
|
||||||
- Added TAP32 version 0901 as accepted (#53).
|
|
||||||
|
|
||||||
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)
|
|
||||||
- Added manpage
|
|
||||||
- Added install/uninstall make target
|
|
||||||
- Cleanup of dns code, more test cases, use check library
|
|
||||||
- Changed directory structure
|
|
||||||
|
|
||||||
2006-11-08: 0.3.4
|
|
||||||
- Fixed handshake() buffer overflow
|
|
||||||
(Found by poplix, Secunia: SA22674 / FrSIRT/ADV-2006-4333)
|
|
||||||
- Added more tests
|
|
||||||
- More name parsing enhancements
|
|
||||||
- Now runs on Linux/AMD64
|
|
||||||
- Added setting to change server port
|
|
||||||
|
|
||||||
2006-11-05: 0.3.3
|
|
||||||
- Fixed possible buffer overflow
|
|
||||||
(Found by poplix, Bugtraq ID: 20883)
|
|
||||||
- Reworked dns hostname encoding
|
|
||||||
|
|
||||||
2006-09-11: 0.3.2
|
|
||||||
- Support for NetBSD
|
|
||||||
- Fixed potential security problems
|
|
||||||
- Name parsing routines rewritten, added regression tests
|
|
||||||
- New encoding, 25% more peak upstream throughput
|
|
||||||
- New -l option to set local ip to listen to on server
|
|
||||||
|
|
||||||
2006-07-11: 0.3.1
|
|
||||||
- Add Mac OSX support
|
|
||||||
- Add setting device name
|
|
||||||
- Use compression of domain name in reply (should allow setting MTU
|
|
||||||
approx 200 bytes higher)
|
|
||||||
|
|
||||||
2006-06-24: 0.3.0
|
|
||||||
- First public release
|
|
||||||
- Support for Linux, FreeBSD, OpenBSD
|
|
|
@ -1,62 +0,0 @@
|
||||||
prefix=/usr/local
|
|
||||||
sbindir=$(prefix)/sbin
|
|
||||||
datadir=$(prefix)/share
|
|
||||||
mandir=$(datadir)/man
|
|
||||||
|
|
||||||
DESTDIR=
|
|
||||||
|
|
||||||
INSTALL=install
|
|
||||||
INSTALL_FLAGS=
|
|
||||||
|
|
||||||
MKDIR=mkdir
|
|
||||||
MKDIR_FLAGS=-p
|
|
||||||
|
|
||||||
RM=rm
|
|
||||||
RM_FLAGS=-f
|
|
||||||
|
|
||||||
TARGETOS = `uname`
|
|
||||||
|
|
||||||
all:
|
|
||||||
@(cd src; $(MAKE) TARGETOS=$(TARGETOS) all)
|
|
||||||
|
|
||||||
cross-mingw:
|
|
||||||
@(cd src; $(MAKE) TARGETOS=windows32 CC=i686-mingw32-gcc all)
|
|
||||||
|
|
||||||
cross-mingw-dist: cross-mingw
|
|
||||||
@rm -rf iodine-latest-win32*
|
|
||||||
@mkdir -p iodine-latest-win32/bin
|
|
||||||
@for i in `ls bin`; do cp bin/$$i iodine-latest-win32/bin/$$i.exe; done
|
|
||||||
@cp /usr/i686-mingw32/usr/bin/zlib1.dll iodine-latest-win32/bin
|
|
||||||
@cp README* CH* TO* iodine-latest-win32
|
|
||||||
@echo "Create date: " > iodine-latest-win32/VERSION
|
|
||||||
@date >> iodine-latest-win32/VERSION
|
|
||||||
@echo "SVN version: " >> iodine-latest-win32/VERSION
|
|
||||||
@svnversion >> iodine-latest-win32/VERSION
|
|
||||||
@zip -r iodine-latest-win32.zip iodine-latest-win32
|
|
||||||
|
|
||||||
install: all
|
|
||||||
$(MKDIR) $(MKDIR_FLAGS) $(DESTDIR)$(sbindir)
|
|
||||||
$(INSTALL) $(INSTALL_FLAGS) bin/iodine $(DESTDIR)$(sbindir)/iodine
|
|
||||||
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) $(DESTDIR)$(sbindir)/iodine
|
|
||||||
$(RM) $(RM_FLAGS) $(DESTDIR)$(sbindir)/iodined
|
|
||||||
$(RM) $(RM_FLAGS) $(DESTDIR)$(mandir)/man8/iodine.8
|
|
||||||
|
|
||||||
test: all
|
|
||||||
@echo "!! The check library is required for compiling and running the tests"
|
|
||||||
@echo "!! Get it at http://check.sf.net"
|
|
||||||
@(cd tests; $(MAKE) TARGETOS=$(TARGETOS) all)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@echo "Cleaning..."
|
|
||||||
@(cd src; $(MAKE) clean)
|
|
||||||
@(cd tests; $(MAKE) clean)
|
|
||||||
@rm -rf bin iodine-latest-win32*
|
|
||||||
|
|
357
iodine/README
357
iodine/README
|
@ -1,357 +0,0 @@
|
||||||
|
|
||||||
iodine - http://code.kryo.se/iodine
|
|
||||||
|
|
||||||
***********************************
|
|
||||||
|
|
||||||
This is a piece of software that lets you tunnel IPv4 data through a DNS
|
|
||||||
server. This can be usable in different situations where internet access is
|
|
||||||
firewalled, but DNS queries are allowed.
|
|
||||||
|
|
||||||
|
|
||||||
QUICKSTART:
|
|
||||||
|
|
||||||
Try it out within your own LAN! Follow these simple steps:
|
|
||||||
- On your server, run: ./iodined -f 10.0.0.1 test.com
|
|
||||||
(If you already use the 10.0.0.0 network, use another internal net like
|
|
||||||
172.16.0.0)
|
|
||||||
- Enter a password
|
|
||||||
- On the client, run: ./iodine -f -r 192.168.0.1 test.com
|
|
||||||
(Replace 192.168.0.1 with your server's ip address)
|
|
||||||
- Enter the same password
|
|
||||||
- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
|
|
||||||
- Try pinging each other through the tunnel
|
|
||||||
- Done! :)
|
|
||||||
To actually use it through a relaying nameserver, see below.
|
|
||||||
|
|
||||||
|
|
||||||
HOW TO USE:
|
|
||||||
|
|
||||||
Note: server and client are required to speak the exact same protocol. In most
|
|
||||||
cases, this means running the same iodine version. Unfortunately, implementing
|
|
||||||
backward and forward protocol compatibility is usually not feasible.
|
|
||||||
|
|
||||||
Server side:
|
|
||||||
To use this tunnel, you need control over a real domain (like mydomain.com),
|
|
||||||
and a server with a public IP address to run iodined on. If this server
|
|
||||||
already runs a DNS program, change its listening port and then use iodined's
|
|
||||||
-b option to let iodined forward the DNS requests. (Note that this procedure
|
|
||||||
is not advised in production environments, because iodined's DNS forwarding
|
|
||||||
is not completely transparent.)
|
|
||||||
|
|
||||||
Then, delegate a subdomain (say, t1.mydomain.com) to the iodined server.
|
|
||||||
If you use BIND for your domain, add two lines like these to the zone file:
|
|
||||||
|
|
||||||
t1 IN NS t1ns.mydomain.com. ; note the dot!
|
|
||||||
t1ns IN A 10.15.213.99
|
|
||||||
|
|
||||||
The "NS" line is all that's needed to route queries for the "t1" subdomain
|
|
||||||
to the "t1ns" server. We use a short name for the subdomain, to keep as much
|
|
||||||
space as possible available for the data traffic. At the end of the "NS" line
|
|
||||||
is the name of your iodined server. This can be any name, pointing anywhere,
|
|
||||||
but in this case it's easily kept in the same zone file. It must be a name
|
|
||||||
(not an IP address), and that name itself must have an A record (not a CNAME).
|
|
||||||
|
|
||||||
If your iodined server has a dynamic IP, use a dynamic dns provider. Simply
|
|
||||||
point the "NS" line to it, and leave the "A" line out:
|
|
||||||
|
|
||||||
t1 IN NS myname.mydyndnsprovider.com. ; note the dot!
|
|
||||||
|
|
||||||
Then reload or restart your nameserver program. Now any DNS queries for
|
|
||||||
domains ending in t1.mydomain.com will be sent to your iodined server.
|
|
||||||
|
|
||||||
Finally start iodined on your server. The first argument is the IP address
|
|
||||||
inside the tunnel, which can be from any range that you don't use yet (for
|
|
||||||
example 192.168.99.1), and the second argument is the assigned domain (in this
|
|
||||||
case t1.mydomain.com). Using the -f option will keep iodined running in the
|
|
||||||
foreground, which helps when testing. iodined will open a virtual interface
|
|
||||||
("tun device"), and will 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 everything is ready for the client.
|
|
||||||
|
|
||||||
If there is a chance you'll be using an iodine tunnel from unexpected
|
|
||||||
environments, start iodined with a -c option.
|
|
||||||
|
|
||||||
Resulting commandline in this example situation:
|
|
||||||
./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com
|
|
||||||
|
|
||||||
Client side:
|
|
||||||
All the setup is done, just start iodine. It takes one or two arguments, the
|
|
||||||
first is the local relaying DNS server (optional) and the second is the domain
|
|
||||||
you used (t1.mydomain.com). If you don't specify the first argument, the
|
|
||||||
system's current DNS setting will be consulted.
|
|
||||||
|
|
||||||
If DNS queries are allowed to any computer, you can directly give the iodined
|
|
||||||
server's address as first argument (in the example: t1ns.mydomain.com or
|
|
||||||
10.15.213.99). In that case, it may also happen that _any_ traffic is allowed
|
|
||||||
to the DNS port (53 UDP) of any computer. Iodine will detect this, and switch
|
|
||||||
to raw UDP tunneling if possible. To force DNS tunneling in any case, use the
|
|
||||||
-r option (especially useful when testing within your own network).
|
|
||||||
|
|
||||||
The client's tunnel interface will get an IP close to the server's (in this
|
|
||||||
case 192.168.99.2 or .3 etc.) and a suitable MTU. Enter the same password as
|
|
||||||
on the server either as commandline option or after the client has started.
|
|
||||||
Using the -f option will keep the iodine client running in the foreground.
|
|
||||||
|
|
||||||
Resulting commandline in this example situation:
|
|
||||||
./iodine -f -P secretpassword t1.mydomain.com
|
|
||||||
(add -r to force DNS tunneling even if raw UDP tunneling would be possible)
|
|
||||||
|
|
||||||
From either side, you should now be able to ping the IP address on the other
|
|
||||||
end of the tunnel. In this case, ping 192.168.99.1 from the iodine client, and
|
|
||||||
192.168.99.2 or .3 etc. from the iodine server.
|
|
||||||
|
|
||||||
|
|
||||||
MISC. INFO:
|
|
||||||
|
|
||||||
Routing:
|
|
||||||
It is possible to route all traffic through the DNS tunnel. To do this, first
|
|
||||||
add a host route to the nameserver used by iodine over the wired/wireless
|
|
||||||
interface with the default gateway as gateway. Then replace the default
|
|
||||||
gateway with the iodined server's IP address inside the DNS tunnel, and
|
|
||||||
configure the server to do NAT.
|
|
||||||
|
|
||||||
However, note that the tunneled data traffic is not encrypted at all, and can
|
|
||||||
be read and changed by external parties relatively easily. For maximum
|
|
||||||
security, run a VPN through the DNS tunnel (=double tunneling), or use secure
|
|
||||||
shell (SSH) access, possibly with port forwarding. The latter can also be used
|
|
||||||
for web browsing, when you run a web proxy (for example Privoxy) on your
|
|
||||||
server.
|
|
||||||
|
|
||||||
Testing:
|
|
||||||
The iodined server replies to NS requests sent for subdomains of the tunnel
|
|
||||||
domain. If your iodined subdomain is t1.mydomain.com, send a NS request for
|
|
||||||
foo123.t1.mydomain.com to see if the delegation works. dig is a good tool
|
|
||||||
for this:
|
|
||||||
dig -t NS foo123.t1.mydomain.com
|
|
||||||
|
|
||||||
Also, the iodined server will answer requests starting with 'z' for any of the
|
|
||||||
supported request types, for example:
|
|
||||||
dig -t TXT z456.t1.mydomain.com
|
|
||||||
dig -t SRV z456.t1.mydomain.com
|
|
||||||
dig -t CNAME z456.t1.mydomain.com
|
|
||||||
The reply should look like garbled text in all these cases.
|
|
||||||
|
|
||||||
Operational info:
|
|
||||||
The DNS-response fragment size is normally autoprobed to get maximum bandwidth.
|
|
||||||
To force a specific value (and speed things up), use the -m option.
|
|
||||||
|
|
||||||
The DNS hostnames are normally used up to their maximum length, 255 characters.
|
|
||||||
Some DNS relays have been found that answer full-length queries rather
|
|
||||||
unreliably, giving widely varying (and mostly very bad) results of the
|
|
||||||
fragment size autoprobe on repeated tries. In these cases, use the -M switch
|
|
||||||
to reduce the DNS hostname length to for example 200 characters, which makes
|
|
||||||
these DNS relays much more stable. This is also useful on some "de-optimizing"
|
|
||||||
DNS relays that stuff the response with two full copies of the query, leaving
|
|
||||||
very little space for downstream data (also not capable of EDNS0). The -M
|
|
||||||
switch can trade some upstream bandwidth for downstream bandwidth. Note that
|
|
||||||
the minimum -M value is about 100, since the protocol can split packets (1200
|
|
||||||
bytes max) in only 16 fragments, requiring at least 75 real data bytes per
|
|
||||||
fragment.
|
|
||||||
|
|
||||||
The upstream data is sent gzipped encoded with Base32; or Base64 if the relay
|
|
||||||
server supports mixed case and '+' in domain names; or Base64u if '_' is
|
|
||||||
supported instead; or Base128 if high-byte-value characters are supported.
|
|
||||||
This upstream encoding is autodetected. The 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.
|
|
||||||
|
|
||||||
Several DNS request types are supported, with the NULL type expected to provide
|
|
||||||
the largest downstream bandwidth. Other available types are TXT, SRV, MX,
|
|
||||||
CNAME and A (returning CNAME), in decreasing bandwidth order. Normally the
|
|
||||||
"best" request type is autodetected and used. However, DNS relays may impose
|
|
||||||
limits on for example NULL and TXT, making SRV or MX actually the best choice.
|
|
||||||
This is not autodetected, but can be forced using the -T option. It is
|
|
||||||
advisable to try various alternatives especially when the autodetected request
|
|
||||||
type provides a downstream fragment size of less than 200 bytes.
|
|
||||||
|
|
||||||
Note that SRV, MX and A (returning CNAME) queries may/will cause additional
|
|
||||||
lookups by "smart" caching nameservers to get an actual IP address, which may
|
|
||||||
either slow down or fail completely.
|
|
||||||
|
|
||||||
DNS responses for non-NULL queries can be encoded with the same set of codecs
|
|
||||||
as upstream data. This is normally also autodetected, but no fully exhaustive
|
|
||||||
tests are done, so some problems may not be noticed when selecting more
|
|
||||||
advanced codecs. In that case, you'll see failures/corruption in the fragment
|
|
||||||
size autoprobe. In particular, several DNS relays have been found that change
|
|
||||||
replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when that
|
|
||||||
hostname exceeds ca. 180 characters. In these and similar cases, use the -O
|
|
||||||
option to try other downstream codecs; Base32 should always work.
|
|
||||||
|
|
||||||
Normal operation now is for the server to _not_ answer a DNS request until
|
|
||||||
the next DNS request has come in, a.k.a. being "lazy". This way, the server
|
|
||||||
will always have a DNS request handy when new downstream data has to be sent.
|
|
||||||
This greatly improves (interactive) performance and latency, and allows to
|
|
||||||
slow down the quiescent ping requests to 4 second intervals by default, and
|
|
||||||
possibly much slower. In fact, the main purpose of the pings now is to force
|
|
||||||
a reply to the previous ping, and prevent DNS server timeouts (usually at
|
|
||||||
least 5-10 seconds per RFC1035). Some DNS servers are more impatient and will
|
|
||||||
give SERVFAIL errors (timeouts) in periods without tunneled data traffic. All
|
|
||||||
data should still get through in these cases, but iodine will reduce the ping
|
|
||||||
interval to 1 second anyway (-I1) to reduce the number of error messages. This
|
|
||||||
may not help for very impatient DNS relays like dnsadvantage.com (ultradns),
|
|
||||||
which time out in 1 second or even less. Yet data will still get trough, and
|
|
||||||
you can ignore the SERVFAIL errors.
|
|
||||||
|
|
||||||
If you are running on a local network without any DNS server in-between, try
|
|
||||||
-I 50 (iodine and iodined close the connection after 60 seconds of silence).
|
|
||||||
The only time you'll notice a slowdown, is when DNS reply packets go missing;
|
|
||||||
the iodined server then has to wait for a new ping to re-send the data. You can
|
|
||||||
speed this up by generating some upstream traffic (keypress, ping). If this
|
|
||||||
happens often, check your network for bottlenecks and/or run with -I1.
|
|
||||||
|
|
||||||
The delayed answering in lazy mode will cause some "carrier grade" commercial
|
|
||||||
DNS relays to repeatedly re-send the same DNS query to the iodined server.
|
|
||||||
If the DNS relay is actually implemented as a pool of parallel servers,
|
|
||||||
duplicate requests may even arrive from multiple sources. This effect will
|
|
||||||
only be visible in the network traffic at the iodined server, and will not
|
|
||||||
affect the client's connection. Iodined will notice these duplicates, and send
|
|
||||||
the same answer (when its time has come) to both the original query and the
|
|
||||||
latest duplicate. After that, the full answer is cached for a short while.
|
|
||||||
Delayed duplicates that arrive at the server even later, get a reply that the
|
|
||||||
iodine client will ignore (if it ever arrives there).
|
|
||||||
|
|
||||||
If you have problems, try inspecting the traffic with network monitoring tools
|
|
||||||
like tcpdump or ethereal/wireshark, 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 -D (and -DD) option on the server
|
|
||||||
can also show received and sent queries.
|
|
||||||
|
|
||||||
|
|
||||||
TIPS & TRICKS:
|
|
||||||
|
|
||||||
If your port 53 is taken on a specific interface by an application that does
|
|
||||||
not use it, use -p on iodined to specify an alternate port (like -p 5353) and
|
|
||||||
use for instance iptables (on Linux) to forward the traffic:
|
|
||||||
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353
|
|
||||||
(Sent in by Tom Schouten)
|
|
||||||
|
|
||||||
Iodined will reject data from clients that have not been active (data/pings)
|
|
||||||
for more than 60 seconds. Similarly, iodine will exit when no downstream
|
|
||||||
data has been received for 60 seconds. In case of a long network outage or
|
|
||||||
similar, just restart iodine (re-login), possibly multiple times until you get
|
|
||||||
your old IP address back. Once that's done, just wait a while, and you'll
|
|
||||||
eventually see the tunneled TCP traffic continue to flow from where it left
|
|
||||||
off before the outage.
|
|
||||||
|
|
||||||
With the introduction of the downstream packet queue in the server, its memory
|
|
||||||
usage has increased with several megabytes in the default configuration.
|
|
||||||
For use in low-memory environments (e.g. running on your DSL router), you can
|
|
||||||
decrease USERS and undefine OUTPACKETQ_LEN in user.h without any ill conse-
|
|
||||||
quence, assuming at most one client will be connected at any time. A small
|
|
||||||
DNSCACHE_LEN is still advised, preferably 2 or higher, however you can also
|
|
||||||
undefine it to save a few more kilobytes.
|
|
||||||
|
|
||||||
|
|
||||||
PERFORMANCE:
|
|
||||||
|
|
||||||
This section tabulates some performance measurements. To view properly, use
|
|
||||||
a fixed-width font like Courier.
|
|
||||||
|
|
||||||
Measurements were done in protocol 00000502 in lazy mode; upstream encoding
|
|
||||||
always Base128; iodine -M255; iodined -m1130. Network conditions were not
|
|
||||||
extremely favorable; results are not benchmarks but a realistic indication of
|
|
||||||
real-world performance that can be expected in similar situations.
|
|
||||||
|
|
||||||
Upstream/downstream throughput was measured by scp'ing a file previously
|
|
||||||
read from /dev/urandom (i.e. incompressible), and measuring size with
|
|
||||||
"ls -l ; sleep 30 ; ls -l" on a separate non-tunneled connection. Given the
|
|
||||||
large scp block size of 16 kB, this gives a resolution of 4.3 kbit/s, which
|
|
||||||
explains why some values are exactly equal.
|
|
||||||
Ping round-trip times measured with "ping -c100", presented are average rtt
|
|
||||||
and mean deviation (indicating spread around the average), in milliseconds.
|
|
||||||
|
|
||||||
|
|
||||||
Situation 1:
|
|
||||||
Laptop -> Wifi AP -> Home server -> DSL provider -> Datacenter
|
|
||||||
iodine DNS "relay" bind9 DNS cache iodined
|
|
||||||
|
|
||||||
downstr. upstream downstr. ping-up ping-down
|
|
||||||
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
iodine -> Wifi AP :53
|
|
||||||
-Tnull (= -Oraw) 982 43.6 131.0 28.0 4.6 26.8 3.4
|
|
||||||
|
|
||||||
iodine -> Home server :53
|
|
||||||
-Tnull (= -Oraw) 1174 48.0 305.8 26.6 5.0 26.9 8.4
|
|
||||||
|
|
||||||
iodine -> DSL provider :53
|
|
||||||
-Tnull (= -Oraw) 1174 56.7 367.0 20.6 3.1 21.2 4.4
|
|
||||||
-Ttxt -Obase32 730 56.7 174.7*
|
|
||||||
-Ttxt -Obase64 874 56.7 174.7
|
|
||||||
-Ttxt -Obase128 1018 56.7 174.7
|
|
||||||
-Ttxt -Oraw 1162 56.7 358.2
|
|
||||||
-Tsrv -Obase128 910 56.7 174.7
|
|
||||||
-Tcname -Obase32 151 56.7 43.6
|
|
||||||
-Tcname -Obase128 212 56.7 52.4
|
|
||||||
|
|
||||||
iodine -> DSL provider :53
|
|
||||||
wired (no Wifi) -Tnull 1174 74.2 585.4 20.2 5.6 19.6 3.4
|
|
||||||
|
|
||||||
[174.7* : these all have 2frag/packet]
|
|
||||||
|
|
||||||
|
|
||||||
Situation 2:
|
|
||||||
Laptop -> Wifi+vpn / wired -> Home server
|
|
||||||
iodine iodined
|
|
||||||
|
|
||||||
downstr. upstream downstr. ping-up ping-down
|
|
||||||
fragsize kbit/s kbit/s avg +/-mdev avg +/-mdev
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
wifi + openvpn -Tnull 1186 166.0 1022.3 6.3 1.3 6.6 1.6
|
|
||||||
|
|
||||||
wired -Tnull 1186 677.2 2464.1 1.3 0.2 1.3 0.1
|
|
||||||
|
|
||||||
|
|
||||||
Performance is strongly coupled to low ping times, as iodine requires
|
|
||||||
confirmation for every data fragment before moving on to the next. Allowing
|
|
||||||
multiple fragments in-flight like TCP could possibly increase performance,
|
|
||||||
but it would likely cause serious overload for the intermediary DNS servers.
|
|
||||||
The current protocol scales performance with DNS responsivity, since the
|
|
||||||
DNS servers are on average handling at most one DNS request per client.
|
|
||||||
|
|
||||||
|
|
||||||
PORTABILITY:
|
|
||||||
|
|
||||||
iodine has been tested on Linux (arm, ia64, x86, AMD64 and SPARC64), FreeBSD
|
|
||||||
(ia64, x86), OpenBSD (x86), NetBSD (x86), MacOS X (ppc and x86, with
|
|
||||||
http://tuntaposx.sourceforge.net/). and Windows (with OpenVPN TAP32 driver, see
|
|
||||||
win32 readme file). 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:
|
|
||||||
|
|
||||||
The name iodine was chosen since it starts with IOD (IP Over DNS) and since
|
|
||||||
iodine has atomic number 53, which happens to be the DNS port number.
|
|
||||||
|
|
||||||
|
|
||||||
THANKS:
|
|
||||||
|
|
||||||
- To kuxien for FreeBSD and OS X testing
|
|
||||||
- To poplix for code audit
|
|
||||||
|
|
||||||
|
|
||||||
AUTHORS & LICENSE:
|
|
||||||
|
|
||||||
Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
|
||||||
Also major contributions by Anne Bezemer.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any purpose
|
|
||||||
with or without fee is hereby granted, provided that the above copyright notice
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
MD5 implementation by L. Peter Deutsch (license and source in src/md5.[ch])
|
|
||||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
|
|
@ -1,62 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
iodine - http://code.kryo.se/iodine
|
|
||||||
|
|
||||||
***********************************
|
|
||||||
|
|
||||||
Extra README file for Win32 related stuff
|
|
||||||
|
|
||||||
|
|
||||||
== Running iodine on Windows:
|
|
||||||
1. Install the TAP32 driver
|
|
||||||
http://openvpn.net/index.php/open-source/downloads.html
|
|
||||||
Choose OpenVPN 2.0.9 Windows Installer, when installing you can
|
|
||||||
select to install only the TAP driver.
|
|
||||||
|
|
||||||
2. Have at least one TAP32 interface installed. There are scripts for adding
|
|
||||||
and removing in the OpenVPN bin directory. If you have more than one
|
|
||||||
installed, use -d to specify which. Use double quotes if you have spaces,
|
|
||||||
example: iodine.exe -d "Local Area Connection 4" abc.ab
|
|
||||||
|
|
||||||
3. Make sure the interface you want to use does not have a default gateway set.
|
|
||||||
|
|
||||||
4. Run iodine/iodined as normal (see the main README file).
|
|
||||||
You may have to run it as administrator depending on user privileges.
|
|
||||||
|
|
||||||
5. Enjoy!
|
|
||||||
|
|
||||||
|
|
||||||
== Building on Windows:
|
|
||||||
You need:
|
|
||||||
MinGW, MSYS, GCC, zlib
|
|
||||||
|
|
||||||
Then just run make
|
|
||||||
|
|
||||||
|
|
||||||
== Cross-compiling for MinGW:
|
|
||||||
You need:
|
|
||||||
MinGW crosscompiler, crosscompiled zlib
|
|
||||||
|
|
||||||
Then run "make cross-mingw"
|
|
||||||
Note that the binaries will not get a .exe suffix
|
|
||||||
|
|
||||||
|
|
||||||
== Zlib download
|
|
||||||
You can get zlib for MinGW here (both for native and crosscompile):
|
|
||||||
http://code.kryo.se/iodine/deps/zlib.zip
|
|
||||||
Unzip it in your MinGW directory on Windows or in $ROOT/usr for
|
|
||||||
cross-compile.
|
|
||||||
|
|
||||||
|
|
||||||
== Results of crappy Win32 API:
|
|
||||||
The following fixable limitations apply:
|
|
||||||
- Server cannot read packet destination address
|
|
||||||
|
|
||||||
The following (probably) un-fixable limitations apply:
|
|
||||||
- A password entered as -P argument can be shown in process list
|
|
||||||
- Priviligies cannot be dropped
|
|
||||||
- chroot() cannot be used
|
|
||||||
- Detaching from terminal not possible
|
|
||||||
- Server on windows must be run with /30 netmask
|
|
||||||
- Client can only talk to server, not other clients
|
|
||||||
|
|
12
iodine/TODO
12
iodine/TODO
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
iodine - http://code.kryo.se/iodine
|
|
||||||
|
|
||||||
***********************************
|
|
||||||
|
|
||||||
The TODO list is now located at
|
|
||||||
|
|
||||||
http://dev.kryo.se/iodine/
|
|
||||||
|
|
||||||
The list is under the "View tickets" page
|
|
||||||
|
|
||||||
Feel free to add your own wishes and bug reports
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Sample post-initialization SELinux policy for Iodine
|
|
||||||
policy_module(iodine, 1.1)
|
|
||||||
|
|
||||||
require {
|
|
||||||
type init_t;
|
|
||||||
type initrc_t;
|
|
||||||
type unconfined_t;
|
|
||||||
type unlabeled_t;
|
|
||||||
class udp_socket { read write };
|
|
||||||
class rawip_socket { write read };
|
|
||||||
class association recvfrom;
|
|
||||||
class unix_dgram_socket { create connect };
|
|
||||||
}
|
|
||||||
|
|
||||||
type iodine_t;
|
|
||||||
domain_type(iodine_t)
|
|
||||||
domain_dyntrans_type(initrc_t)
|
|
||||||
allow initrc_t iodine_t:process dyntransition;
|
|
||||||
|
|
||||||
allow iodine_t unconfined_t:udp_socket { read write };
|
|
||||||
allow iodine_t unconfined_t:rawip_socket { write read };
|
|
||||||
allow iodine_t unlabeled_t:association recvfrom;
|
|
||||||
allow iodine_t self:unix_dgram_socket { create connect };
|
|
||||||
corenet_raw_receive_generic_node(iodine_t)
|
|
||||||
corenet_rw_tun_tap_dev(iodine_t)
|
|
|
@ -1,61 +0,0 @@
|
||||||
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.
|
|
|
@ -1,112 +0,0 @@
|
||||||
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.
|
|
|
@ -1,338 +0,0 @@
|
||||||
.\" groff -man -Tascii iodine.8
|
|
||||||
.TH IODINE 8 "DEC 2009" "User Manuals"
|
|
||||||
.SH NAME
|
|
||||||
iodine, iodined \- tunnel IPv4 over DNS
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B iodine [-v]
|
|
||||||
|
|
||||||
.B iodine [-h]
|
|
||||||
|
|
||||||
.B iodine [-f] [-r] [-u
|
|
||||||
.I user
|
|
||||||
.B ] [-P
|
|
||||||
.I password
|
|
||||||
.B ] [-m
|
|
||||||
.I fragsize
|
|
||||||
.B ] [-t
|
|
||||||
.I chrootdir
|
|
||||||
.B ] [-d
|
|
||||||
.I device
|
|
||||||
.B ] [-m
|
|
||||||
.I fragsize
|
|
||||||
.B ] [-M
|
|
||||||
.I namelen
|
|
||||||
.B ] [-z
|
|
||||||
.I context
|
|
||||||
.B ] [-F
|
|
||||||
.I pidfile
|
|
||||||
.B ] [-T
|
|
||||||
.I dnstype
|
|
||||||
.B ] [-O
|
|
||||||
.I downenc
|
|
||||||
.B ] [-L
|
|
||||||
.I 0|1
|
|
||||||
.B ] [-I
|
|
||||||
.I interval
|
|
||||||
.B ]
|
|
||||||
.B [
|
|
||||||
.I nameserver
|
|
||||||
.B ]
|
|
||||||
.I topdomain
|
|
||||||
|
|
||||||
.B iodined [-v]
|
|
||||||
|
|
||||||
.B iodined [-h]
|
|
||||||
|
|
||||||
.B iodined [-c] [-s] [-f] [-D] [-u
|
|
||||||
.I user
|
|
||||||
.B ] [-t
|
|
||||||
.I chrootdir
|
|
||||||
.B ] [-d
|
|
||||||
.I device
|
|
||||||
.B ] [-m
|
|
||||||
.I mtu
|
|
||||||
.B ] [-l
|
|
||||||
.I listen_ip
|
|
||||||
.B ] [-p
|
|
||||||
.I port
|
|
||||||
.B ] [-n
|
|
||||||
.I external_ip
|
|
||||||
.B ] [-b
|
|
||||||
.I dnsport
|
|
||||||
.B ] [-P
|
|
||||||
.I password
|
|
||||||
.B ] [-z
|
|
||||||
.I context
|
|
||||||
.B ] [-F
|
|
||||||
.I pidfile
|
|
||||||
.B ]
|
|
||||||
.I tunnel_ip
|
|
||||||
.B [
|
|
||||||
.I /netmask
|
|
||||||
.B ]
|
|
||||||
.I topdomain
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.B iodine
|
|
||||||
lets you tunnel IPv4 data through a DNS
|
|
||||||
server. This can be useful in situations where Internet access is firewalled,
|
|
||||||
but DNS queries are allowed. It needs a TUN/TAP device to operate. The
|
|
||||||
bandwidth is asymmetrical,
|
|
||||||
with a measured maximum of 680 kbit/s upstream and 2.3 Mbit/s
|
|
||||||
downstream in a wired LAN test network.
|
|
||||||
Realistic sustained throughput on a Wifi network using a carrier-grade
|
|
||||||
DNS cache has been measured at some 50 kbit/s upstream and over 200 kbit/s
|
|
||||||
downstream.
|
|
||||||
.B iodine
|
|
||||||
is the client application,
|
|
||||||
.B iodined
|
|
||||||
is the server.
|
|
||||||
|
|
||||||
Note: server and client are required to speak the exact same protocol. In most
|
|
||||||
cases, this means running the same iodine version. Unfortunately, implementing
|
|
||||||
backward and forward protocol compatibility is usually not feasible.
|
|
||||||
.SH OPTIONS
|
|
||||||
.SS Common Options:
|
|
||||||
.TP
|
|
||||||
.B -v
|
|
||||||
Print version info and exit.
|
|
||||||
.TP
|
|
||||||
.B -h
|
|
||||||
Print usage info and exit.
|
|
||||||
.TP
|
|
||||||
.B -f
|
|
||||||
Keep running in foreground.
|
|
||||||
.TP
|
|
||||||
.B -u user
|
|
||||||
Drop privileges and run as user 'user' after setting up tunnel.
|
|
||||||
.TP
|
|
||||||
.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.
|
|
||||||
.TP
|
|
||||||
.B -z context
|
|
||||||
Apply SELinux 'context' after initialization.
|
|
||||||
.TP
|
|
||||||
.B -F pidfile
|
|
||||||
Create 'pidfile' and write process id in it.
|
|
||||||
.SS Client Options:
|
|
||||||
.TP
|
|
||||||
.B -r
|
|
||||||
Skip raw UDP mode. If not used, iodine will try getting the public IP address
|
|
||||||
of the iodined host and test if it is reachable directly. If it is, traffic
|
|
||||||
will be sent to the server instead of the DNS relay.
|
|
||||||
.TP
|
|
||||||
.B -m fragsize
|
|
||||||
Force maximum downstream fragment size. Not setting this will cause the
|
|
||||||
client to automatically probe the maximum accepted downstream fragment size.
|
|
||||||
.TP
|
|
||||||
.B -M namelen
|
|
||||||
Maximum length of upstream hostnames, default 255.
|
|
||||||
Usable range ca. 100 to 255.
|
|
||||||
Use this option to scale back upstream bandwidth in favor of downstream
|
|
||||||
bandwidth.
|
|
||||||
Also useful for DNS servers that perform unreliably when using full-length
|
|
||||||
hostnames, noticable when fragment size autoprobe returns very
|
|
||||||
different results each time.
|
|
||||||
.TP
|
|
||||||
.B -T dnstype
|
|
||||||
DNS request type override.
|
|
||||||
By default, autodetection will probe for working DNS request types, and
|
|
||||||
will select the request type that is expected to provide the most bandwidth.
|
|
||||||
However, it may turn out that a DNS relay imposes limits that skew the
|
|
||||||
picture, which may lead to an "unexpected" DNS request type providing
|
|
||||||
more bandwidth.
|
|
||||||
In that case, use this option to override the autodetection.
|
|
||||||
In (expected) decreasing bandwidth order, the supported DNS request types are:
|
|
||||||
.IR NULL ,
|
|
||||||
.IR TXT ,
|
|
||||||
.IR SRV ,
|
|
||||||
.IR MX ,
|
|
||||||
.I CNAME
|
|
||||||
and
|
|
||||||
.I A
|
|
||||||
(returning CNAME).
|
|
||||||
Note that
|
|
||||||
.IR SRV ,
|
|
||||||
.I MX
|
|
||||||
and
|
|
||||||
.I A
|
|
||||||
may/will cause additional lookups by "smart" caching
|
|
||||||
nameservers to get an actual IP address, which may either slow down or fail
|
|
||||||
completely.
|
|
||||||
.TP
|
|
||||||
.B -O downenc
|
|
||||||
Force downstream encoding type for all query type responses except NULL.
|
|
||||||
Default is autodetected, but may not spot all problems for the more advanced
|
|
||||||
codecs.
|
|
||||||
Use this option to override the autodetection.
|
|
||||||
.I Base32
|
|
||||||
is the lowest-grade codec and should always work; this is used when
|
|
||||||
autodetection fails.
|
|
||||||
.I Base64
|
|
||||||
provides more bandwidth, but may not work on all nameservers.
|
|
||||||
.I Base64u
|
|
||||||
is equal to Base64 except in using underscore ('_')
|
|
||||||
instead of plus sign ('+'), possibly working where
|
|
||||||
.I Base64
|
|
||||||
does not.
|
|
||||||
.I Base128
|
|
||||||
uses high byte values (mostly accented letters in iso8859-1),
|
|
||||||
which might work with some nameservers.
|
|
||||||
For TXT queries,
|
|
||||||
.I Raw
|
|
||||||
will provide maximum performance, but this will only work if the nameserver
|
|
||||||
path is fully 8-bit-clean for responses that are assumed to be "legible text".
|
|
||||||
.TP
|
|
||||||
.B -L 0|1
|
|
||||||
Lazy-mode switch.
|
|
||||||
\-L1 (default): Use lazy mode for improved performance and decreased latency.
|
|
||||||
A very small minority of DNS relays appears to be unable to handle the
|
|
||||||
lazy mode traffic pattern, resulting in no or very little data coming through.
|
|
||||||
The iodine client will detect this and try to switch back to legacy mode,
|
|
||||||
but this may not always work.
|
|
||||||
In these situations use \-L0 to force running in legacy mode
|
|
||||||
(implies \-I1).
|
|
||||||
.TP
|
|
||||||
.B -I interval
|
|
||||||
Maximum interval between requests (pings) so that intermediate DNS
|
|
||||||
servers will not time out. Default is 4 in lazy mode, which will work
|
|
||||||
fine in most cases. When too many SERVFAIL errors occur, iodine
|
|
||||||
will automatically reduce this to 1.
|
|
||||||
To get absolute minimum DNS traffic,
|
|
||||||
increase well above 4, but not so high that SERVFAIL errors start to occur.
|
|
||||||
There are some DNS relays with very small timeouts,
|
|
||||||
notably dnsadvantage.com (ultradns), that will give
|
|
||||||
SERVFAIL errors even with \-I1; data will still get trough,
|
|
||||||
and these errors can be ignored.
|
|
||||||
Maximum useful value is 59, since iodined will close a client's
|
|
||||||
connection after 60 seconds of inactivity.
|
|
||||||
.SS Server Options:
|
|
||||||
.TP
|
|
||||||
.B -c
|
|
||||||
Disable checking the client IP address on all incoming requests.
|
|
||||||
By default, requests originating from non-matching IP adresses will be
|
|
||||||
rejected, however this will cause problems when requests are routed
|
|
||||||
via a cluster of DNS servers.
|
|
||||||
.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.
|
|
||||||
Implies the
|
|
||||||
.B -f
|
|
||||||
option.
|
|
||||||
On level 2 (-DD) or higher, DNS queries will be printed literally.
|
|
||||||
When using Base128 upstream encoding, this is best viewed as
|
|
||||||
ISO Latin-1 text instead of (illegal) UTF-8.
|
|
||||||
This is easily done with : "LC_ALL=C luit iodined -DD ..."
|
|
||||||
(see luit(1)).
|
|
||||||
.TP
|
|
||||||
.B -m mtu
|
|
||||||
Set 'mtu' as mtu size for the tun device.
|
|
||||||
This will be sent to the client on login, and the client will use the same mtu
|
|
||||||
for its tun device. Default 1130. Note that the DNS traffic will be
|
|
||||||
automatically fragmented when needed.
|
|
||||||
.TP
|
|
||||||
.B -l listen_ip
|
|
||||||
Make the server listen only on 'listen_ip' for incoming requests.
|
|
||||||
By default, incoming requests are accepted from all interfaces.
|
|
||||||
.TP
|
|
||||||
.B -p port
|
|
||||||
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.
|
|
||||||
.B Note:
|
|
||||||
The forwarding is not fully transparent, and not advised for use
|
|
||||||
in production environments.
|
|
||||||
.SS Client Arguments:
|
|
||||||
.TP
|
|
||||||
.B nameserver
|
|
||||||
The nameserver to use to relay the dns traffic. This can be any relaying
|
|
||||||
nameserver or the server running iodined if reachable. This field can be
|
|
||||||
given as an IP address, or as a hostname. This argument is optional, and
|
|
||||||
if not specified a nameserver will be read from the
|
|
||||||
.I /etc/resolv.conf
|
|
||||||
file.
|
|
||||||
.TP
|
|
||||||
.B topdomain
|
|
||||||
The dns traffic will be sent as queries for subdomains under
|
|
||||||
\'topdomain'. This is normally a subdomain to a domain you own. Use a short
|
|
||||||
domain name to get better throughput. If
|
|
||||||
.B nameserver
|
|
||||||
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[/netmask]
|
|
||||||
This is the server's ip address on the tun interface. The client will be
|
|
||||||
given the next ip number in the range. It is recommended to use the
|
|
||||||
10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden
|
|
||||||
by specifying it here. Using a smaller network will limit the number of
|
|
||||||
concurrent users.
|
|
||||||
.TP
|
|
||||||
.B topdomain
|
|
||||||
The dns traffic is expected to arrive as queries for
|
|
||||||
subdomains under 'topdomain'. This is normally a subdomain to a domain you
|
|
||||||
own. Use a short domain name to get better throughput. This argument must be
|
|
||||||
the same on both the client and the server. Queries for domains other
|
|
||||||
than 'topdomain' will be forwarded when the \-b option is given, otherwise
|
|
||||||
they will be dropped.
|
|
||||||
.SH EXAMPLES
|
|
||||||
See the README file for both a quick test scenario, and a detailed description
|
|
||||||
of real-world deployment.
|
|
||||||
.SH SECURITY
|
|
||||||
Login is a relatively secure challenge-response MD5 hash, with the
|
|
||||||
password never passing the wire.
|
|
||||||
However, all other data is
|
|
||||||
.B NOT
|
|
||||||
encrypted in any way. The DNS traffic is also vulnerable to replay,
|
|
||||||
injection and man-in-the-middle attacks, especially when iodined is used
|
|
||||||
with the \-c option. Use of ssh or vpn tunneling is strongly recommended.
|
|
||||||
On both server and client, use
|
|
||||||
.IR iptables ,
|
|
||||||
.I pf
|
|
||||||
or other firewalls to block all traffic coming in from the tun interfaces,
|
|
||||||
except to the used ssh or vpn ports.
|
|
||||||
.SH ENVIRONMENT
|
|
||||||
.SS IODINE_PASS
|
|
||||||
If the environment variable
|
|
||||||
.B IODINE_PASS
|
|
||||||
is set, iodine will use the value it is set to as password instead of asking
|
|
||||||
for one. The
|
|
||||||
.B -P
|
|
||||||
option still has precedence.
|
|
||||||
.SS IODINED_PASS
|
|
||||||
If the environment variable
|
|
||||||
.B IODINED_PASS
|
|
||||||
is set, iodined will use the value it is set to as password instead of asking
|
|
||||||
for one. The
|
|
||||||
.B -P
|
|
||||||
option still has precedence.
|
|
||||||
.El
|
|
||||||
.SH SEE ALSO
|
|
||||||
The README file in the source distribution contains some more elaborate
|
|
||||||
information.
|
|
||||||
.SH BUGS
|
|
||||||
File bugs at http://dev.kryo.se/iodine/
|
|
||||||
.SH AUTHORS
|
|
||||||
Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>. Major
|
|
||||||
contributions by Anne Bezemer.
|
|
|
@ -1,46 +0,0 @@
|
||||||
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o base64u.o base128.o md5.o common.o
|
|
||||||
CLIENTOBJS = iodine.o client.o util.o
|
|
||||||
CLIENT = ../bin/iodine
|
|
||||||
SERVEROBJS = iodined.o user.o fw_query.o
|
|
||||||
SERVER = ../bin/iodined
|
|
||||||
|
|
||||||
OS = `echo $(TARGETOS) | tr "a-z" "A-Z"`
|
|
||||||
ARCH = `uname -m`
|
|
||||||
|
|
||||||
LIBPATH = -L.
|
|
||||||
LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH)
|
|
||||||
CFLAGS += -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags`
|
|
||||||
|
|
||||||
all: stateos $(CLIENT) $(SERVER)
|
|
||||||
|
|
||||||
stateos:
|
|
||||||
@echo OS is $(OS), arch is $(ARCH)
|
|
||||||
|
|
||||||
$(CLIENT): $(COMMONOBJS) $(CLIENTOBJS)
|
|
||||||
@echo LD $@
|
|
||||||
@mkdir -p ../bin
|
|
||||||
@$(CC) $(COMMONOBJS) $(CLIENTOBJS) -o $(CLIENT) $(LDFLAGS)
|
|
||||||
|
|
||||||
$(SERVER): $(COMMONOBJS) $(SERVEROBJS)
|
|
||||||
@echo LD $@
|
|
||||||
@mkdir -p ../bin
|
|
||||||
@$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS)
|
|
||||||
|
|
||||||
.c.o:
|
|
||||||
@echo CC $<
|
|
||||||
@$(CC) $(CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
base64u.o client.o iodined.o: base64u.h
|
|
||||||
base64u.c: base64.c
|
|
||||||
@echo Making $@
|
|
||||||
@echo '/* No use in editing, produced by Makefile! */' > $@
|
|
||||||
@sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < base64.c >> $@
|
|
||||||
base64u.h: base64.h
|
|
||||||
@echo Making $@
|
|
||||||
@echo '/* No use in editing, produced by Makefile! */' > $@
|
|
||||||
@sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < base64.h >> $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@echo "Cleaning src/"
|
|
||||||
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.*
|
|
||||||
|
|
|
@ -1,270 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
|
||||||
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "base32.h"
|
|
||||||
|
|
||||||
#define BLKSIZE_RAW 5
|
|
||||||
#define BLKSIZE_ENC 8
|
|
||||||
|
|
||||||
static const char cb32[] =
|
|
||||||
"abcdefghijklmnopqrstuvwxyz012345";
|
|
||||||
static const char cb32_ucase[] =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
|
|
||||||
static unsigned char rev32[256];
|
|
||||||
static int reverse_init = 0;
|
|
||||||
|
|
||||||
static int base32_encode(char *, size_t *, const void *, size_t);
|
|
||||||
static int base32_decode(void *, size_t *, const char *, size_t);
|
|
||||||
static int base32_handles_dots();
|
|
||||||
static int base32_blksize_raw();
|
|
||||||
static int base32_blksize_enc();
|
|
||||||
|
|
||||||
static struct encoder base32_encoder =
|
|
||||||
{
|
|
||||||
"Base32",
|
|
||||||
base32_encode,
|
|
||||||
base32_decode,
|
|
||||||
base32_handles_dots,
|
|
||||||
base32_handles_dots,
|
|
||||||
base32_blksize_raw,
|
|
||||||
base32_blksize_enc
|
|
||||||
};
|
|
||||||
|
|
||||||
struct encoder
|
|
||||||
*get_base32_encoder()
|
|
||||||
{
|
|
||||||
return &base32_encoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base32_handles_dots()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base32_blksize_raw()
|
|
||||||
{
|
|
||||||
return BLKSIZE_RAW;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base32_blksize_enc()
|
|
||||||
{
|
|
||||||
return BLKSIZE_ENC;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void
|
|
||||||
base32_reverse_init()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
if (!reverse_init) {
|
|
||||||
memset (rev32, 0, 256);
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
c = cb32[i];
|
|
||||||
rev32[(int) c] = i;
|
|
||||||
c = cb32_ucase[i];
|
|
||||||
rev32[(int) c] = i;
|
|
||||||
}
|
|
||||||
reverse_init = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
b32_5to8(int in)
|
|
||||||
{
|
|
||||||
return cb32[in & 31];
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
b32_8to5(int in)
|
|
||||||
{
|
|
||||||
base32_reverse_init();
|
|
||||||
return rev32[in];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
|
||||||
/*
|
|
||||||
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
|
|
||||||
*
|
|
||||||
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
|
||||||
* to hold the trailing '\0'.
|
|
||||||
*
|
|
||||||
* return value : #bytes filled in buf (excluding \0)
|
|
||||||
* sets *buflen to : #bytes encoded from data
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned char *udata = (unsigned char *) data;
|
|
||||||
int iout = 0; /* to-be-filled output char */
|
|
||||||
int iin = 0; /* one more than last input byte that can be
|
|
||||||
successfully decoded */
|
|
||||||
|
|
||||||
/* Note: Don't bother to optimize manually. GCC optimizes
|
|
||||||
better(!) when using simplistic array indexing. */
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size) {
|
|
||||||
iout--; /* previous char is useless */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0xc0) >> 6) : 0)];
|
|
||||||
iin++; /* 0 complete, iin=1 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size) {
|
|
||||||
iout--; /* previous char is useless */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0xf0) >> 4) : 0)];
|
|
||||||
iin++; /* 1 complete, iin=2 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0x80) >> 7) : 0)];
|
|
||||||
iin++; /* 2 complete, iin=3 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size) {
|
|
||||||
iout--; /* previous char is useless */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0xe0) >> 5) : 0)];
|
|
||||||
iin++; /* 3 complete, iin=4 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb32[((udata[iin] & 0x1f))];
|
|
||||||
iin++; /* 4 complete, iin=5 */
|
|
||||||
iout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[iout] = '\0';
|
|
||||||
|
|
||||||
/* store number of bytes from data that was used */
|
|
||||||
*buflen = iin;
|
|
||||||
|
|
||||||
return iout;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define REV32(x) rev32[(int) (x)]
|
|
||||||
|
|
||||||
static int
|
|
||||||
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
|
||||||
/*
|
|
||||||
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
|
|
||||||
* Decoding stops early when *str contains \0.
|
|
||||||
* Illegal encoded chars are assumed to decode to zero.
|
|
||||||
*
|
|
||||||
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
|
||||||
* to hold a trailing '\0' that is added (though *buf will usually
|
|
||||||
* contain full-binary data).
|
|
||||||
*
|
|
||||||
* return value : #bytes filled in buf (excluding \0)
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned char *ubuf = (unsigned char *) buf;
|
|
||||||
int iout = 0; /* to-be-filled output byte */
|
|
||||||
int iin = 0; /* next input char to use in decoding */
|
|
||||||
|
|
||||||
base32_reverse_init ();
|
|
||||||
|
|
||||||
/* Note: Don't bother to optimize manually. GCC optimizes
|
|
||||||
better(!) when using simplistic array indexing. */
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
|
|
||||||
((REV32(str[iin + 1]) & 0x1c) >> 2);
|
|
||||||
iin++; /* 0 used up, iin=1 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 2 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0' ||
|
|
||||||
str[iin + 2] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
|
|
||||||
((REV32(str[iin + 1]) & 0x1f) << 1) |
|
|
||||||
((REV32(str[iin + 2]) & 0x10) >> 4);
|
|
||||||
iin += 2; /* 1,2 used up, iin=3 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |
|
|
||||||
((REV32(str[iin + 1]) & 0x1e) >> 1);
|
|
||||||
iin++; /* 3 used up, iin=4 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 2 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0' ||
|
|
||||||
str[iin + 2] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |
|
|
||||||
((REV32(str[iin + 1]) & 0x1f) << 2) |
|
|
||||||
((REV32(str[iin + 2]) & 0x18) >> 3);
|
|
||||||
iin += 2; /* 4,5 used up, iin=6 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |
|
|
||||||
((REV32(str[iin + 1]) & 0x1f));
|
|
||||||
iin += 2; /* 6,7 used up, iin=8 */
|
|
||||||
iout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubuf[iout] = '\0';
|
|
||||||
|
|
||||||
return iout;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __BASE32_H__
|
|
||||||
#define __BASE32_H__
|
|
||||||
|
|
||||||
struct encoder *get_base32_encoder(void);
|
|
||||||
|
|
||||||
int b32_5to8(int);
|
|
||||||
int b32_8to5(int);
|
|
||||||
#endif
|
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
|
||||||
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
|
|
||||||
*
|
|
||||||
* 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "base64.h"
|
|
||||||
|
|
||||||
#define BLKSIZE_RAW 3
|
|
||||||
#define BLKSIZE_ENC 4
|
|
||||||
|
|
||||||
/* Note: the "unofficial" char is last here, which means that the \377 pattern
|
|
||||||
in DOWNCODECCHECK1 ('Y' request) will properly test it. */
|
|
||||||
static const char cb64[] =
|
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
|
|
||||||
static unsigned char rev64[256];
|
|
||||||
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();
|
|
||||||
|
|
||||||
static struct encoder base64_encoder =
|
|
||||||
{
|
|
||||||
"Base64",
|
|
||||||
base64_encode,
|
|
||||||
base64_decode,
|
|
||||||
base64_handles_dots,
|
|
||||||
base64_handles_dots,
|
|
||||||
base64_blksize_raw,
|
|
||||||
base64_blksize_enc
|
|
||||||
};
|
|
||||||
|
|
||||||
struct encoder
|
|
||||||
*get_base64_encoder()
|
|
||||||
{
|
|
||||||
return &base64_encoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_handles_dots()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_blksize_raw()
|
|
||||||
{
|
|
||||||
return BLKSIZE_RAW;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_blksize_enc()
|
|
||||||
{
|
|
||||||
return BLKSIZE_ENC;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void
|
|
||||||
base64_reverse_init()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
if (!reverse_init) {
|
|
||||||
memset (rev64, 0, 256);
|
|
||||||
for (i = 0; i < 64; i++) {
|
|
||||||
c = cb64[i];
|
|
||||||
rev64[(int) c] = i;
|
|
||||||
}
|
|
||||||
reverse_init = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
|
||||||
/*
|
|
||||||
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
|
|
||||||
*
|
|
||||||
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
|
||||||
* to hold the trailing '\0'.
|
|
||||||
*
|
|
||||||
* return value : #bytes filled in buf (excluding \0)
|
|
||||||
* sets *buflen to : #bytes encoded from data
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned char *udata = (unsigned char *) data;
|
|
||||||
int iout = 0; /* to-be-filled output char */
|
|
||||||
int iin = 0; /* one more than last input byte that can be
|
|
||||||
successfully decoded */
|
|
||||||
|
|
||||||
/* Note: Don't bother to optimize manually. GCC optimizes
|
|
||||||
better(!) when using simplistic array indexing. */
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)];
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size) {
|
|
||||||
iout--; /* previous char is useless */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[iout] = cb64[((udata[iin] & 0x03) << 4) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0xf0) >> 4) : 0)];
|
|
||||||
iin++; /* 0 complete, iin=1 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) |
|
|
||||||
((iin + 1 < size) ?
|
|
||||||
((udata[iin + 1] & 0xc0) >> 6) : 0)];
|
|
||||||
iin++; /* 1 complete, iin=2 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin >= size)
|
|
||||||
break;
|
|
||||||
buf[iout] = cb64[(udata[iin] & 0x3f)];
|
|
||||||
iin++; /* 2 complete, iin=3 */
|
|
||||||
iout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[iout] = '\0';
|
|
||||||
|
|
||||||
/* store number of bytes from data that was used */
|
|
||||||
*buflen = iin;
|
|
||||||
|
|
||||||
return iout;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define REV64(x) rev64[(int) (x)]
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
|
||||||
/*
|
|
||||||
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
|
|
||||||
* Decoding stops early when *str contains \0.
|
|
||||||
* Illegal encoded chars are assumed to decode to zero.
|
|
||||||
*
|
|
||||||
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
|
||||||
* to hold a trailing '\0' that is added (though *buf will usually
|
|
||||||
* contain full-binary data).
|
|
||||||
*
|
|
||||||
* return value : #bytes filled in buf (excluding \0)
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned char *ubuf = (unsigned char *) buf;
|
|
||||||
int iout = 0; /* to-be-filled output byte */
|
|
||||||
int iin = 0; /* next input char to use in decoding */
|
|
||||||
|
|
||||||
base64_reverse_init ();
|
|
||||||
|
|
||||||
/* Note: Don't bother to optimize manually. GCC optimizes
|
|
||||||
better(!) when using simplistic array indexing. */
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |
|
|
||||||
((REV64(str[iin + 1]) & 0x30) >> 4);
|
|
||||||
iin++; /* 0 used up, iin=1 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |
|
|
||||||
((REV64(str[iin + 1]) & 0x3c) >> 2);
|
|
||||||
iin++; /* 1 used up, iin=2 */
|
|
||||||
iout++;
|
|
||||||
|
|
||||||
if (iout >= *buflen || iin + 1 >= slen ||
|
|
||||||
str[iin] == '\0' || str[iin + 1] == '\0')
|
|
||||||
break;
|
|
||||||
ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) |
|
|
||||||
(REV64(str[iin + 1]) & 0x3f);
|
|
||||||
iin += 2; /* 2,3 used up, iin=4 */
|
|
||||||
iout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubuf[iout] = '\0';
|
|
||||||
|
|
||||||
return iout;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __BASE64_H__
|
|
||||||
#define __BASE64_H__
|
|
||||||
|
|
||||||
struct encoder *get_base64_encoder(void);
|
|
||||||
|
|
||||||
#endif
|
|
2514
iodine/src/client.c
2514
iodine/src/client.c
File diff suppressed because it is too large
Load Diff
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __CLIENT_H__
|
|
||||||
#define __CLIENT_H__
|
|
||||||
|
|
||||||
void client_init();
|
|
||||||
void client_stop();
|
|
||||||
|
|
||||||
enum connection client_get_conn();
|
|
||||||
const char *client_get_raw_addr();
|
|
||||||
|
|
||||||
void client_set_nameserver(const char *cp, int port);
|
|
||||||
void client_set_topdomain(const char *cp);
|
|
||||||
void client_set_password(const char *cp);
|
|
||||||
void set_qtype(char *qtype);
|
|
||||||
char *get_qtype();
|
|
||||||
void set_downenc(char *encoding);
|
|
||||||
void client_set_selecttimeout(int select_timeout);
|
|
||||||
void client_set_lazymode(int lazy_mode);
|
|
||||||
void client_set_hostname_maxlen(int i);
|
|
||||||
|
|
||||||
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize);
|
|
||||||
int client_tunnel(int tun_fd, int dns_fd);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,350 +0,0 @@
|
||||||
/* 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
|
|
||||||
* 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 <time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <conio.h>
|
|
||||||
#else
|
|
||||||
#include <arpa/nameser.h>
|
|
||||||
#ifdef DARWIN
|
|
||||||
#define BIND_8_COMPAT
|
|
||||||
#include <arpa/nameser_compat.h>
|
|
||||||
#endif
|
|
||||||
#include <termios.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SETCON
|
|
||||||
# include <selinux/selinux.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
/* The raw header used when not using DNS protocol */
|
|
||||||
const unsigned char raw_header[RAW_HDR_LEN] = { 0x10, 0xd1, 0x9e, 0x00 };
|
|
||||||
|
|
||||||
/* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
|
|
||||||
#if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
check_superuser(void (*usage_fn)(void))
|
|
||||||
{
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
if (geteuid() != 0) {
|
|
||||||
warnx("Run as root and you'll be happy.\n");
|
|
||||||
usage_fn();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
open_dns(int localport, in_addr_t listen_ip)
|
|
||||||
{
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
int flag = 1;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons(localport);
|
|
||||||
/* listen_ip already in network byte order from inet_addr, or 0 */
|
|
||||||
addr.sin_addr.s_addr = listen_ip;
|
|
||||||
|
|
||||||
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
||||||
fprintf(stderr, "got fd %d\n", fd);
|
|
||||||
err(1, "socket");
|
|
||||||
}
|
|
||||||
|
|
||||||
flag = 1;
|
|
||||||
#ifdef SO_REUSEPORT
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));
|
|
||||||
#endif
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
|
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
/* To get destination address from each UDP datagram, see iodined.c:read_dns() */
|
|
||||||
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef IP_OPT_DONT_FRAG
|
|
||||||
/* Set dont-fragment ip header flag */
|
|
||||||
flag = DONT_FRAG_VALUE;
|
|
||||||
setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
|
||||||
err(1, "bind");
|
|
||||||
|
|
||||||
fprintf(stderr, "Opened UDP socket\n");
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
close_dns(int fd)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_chroot(char *newroot)
|
|
||||||
{
|
|
||||||
#if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))
|
|
||||||
if (chroot(newroot) != 0 || chdir("/") != 0)
|
|
||||||
err(1, "%s", newroot);
|
|
||||||
|
|
||||||
seteuid(geteuid());
|
|
||||||
setuid(getuid());
|
|
||||||
#else
|
|
||||||
warnx("chroot not available");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_setcon(char *context)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_SETCON
|
|
||||||
if (-1 == setcon(context))
|
|
||||||
err(1, "%s", context);
|
|
||||||
#else
|
|
||||||
warnx("No SELinux support built in");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_pidfile(char *pidfile)
|
|
||||||
{
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
if ((file = fopen(pidfile, "w")) == NULL) {
|
|
||||||
syslog(LOG_ERR, "Cannot write pidfile to %s, exiting", pidfile);
|
|
||||||
err(1, "do_pidfile: Can not write pidfile to %s", pidfile);
|
|
||||||
} else {
|
|
||||||
fprintf(file, "%d\n", (int)getpid());
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "Windows version does not support pid file\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_detach()
|
|
||||||
{
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
fprintf(stderr, "Detaching from terminal...\n");
|
|
||||||
daemon(0, 0);
|
|
||||||
umask(0);
|
|
||||||
alarm(0);
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "Windows version does not support detaching\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
read_password(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
char pwd[80];
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
struct termios old;
|
|
||||||
struct termios tp;
|
|
||||||
|
|
||||||
tcgetattr(0, &tp);
|
|
||||||
old = tp;
|
|
||||||
|
|
||||||
tp.c_lflag &= (~ECHO);
|
|
||||||
tcsetattr(0, TCSANOW, &tp);
|
|
||||||
#else
|
|
||||||
int i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fprintf(stderr, "Enter password: ");
|
|
||||||
fflush(stderr);
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
scanf("%79s", pwd);
|
|
||||||
#else
|
|
||||||
for (i = 0; i < sizeof(pwd); i++) {
|
|
||||||
pwd[i] = getch();
|
|
||||||
if (pwd[i] == '\r' || pwd[i] == '\n') {
|
|
||||||
pwd[i] = 0;
|
|
||||||
break;
|
|
||||||
} else if (pwd[i] == '\b') {
|
|
||||||
i--; /* Remove the \b char */
|
|
||||||
if (i >=0) i--; /* If not first char, remove one more */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
tcsetattr(0, TCSANOW, &old);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
int
|
|
||||||
inet_aton(const char *cp, struct in_addr *inp)
|
|
||||||
{
|
|
||||||
inp->s_addr = inet_addr(cp);
|
|
||||||
return inp->s_addr != INADDR_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
warn(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
|
|
||||||
va_start(list, fmt);
|
|
||||||
if (fmt) fprintf(stderr, fmt, list);
|
|
||||||
if (errno == 0) {
|
|
||||||
fprintf(stderr, ": WSA error %d\n", WSAGetLastError());
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, ": %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
va_end(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
warnx(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
|
|
||||||
va_start(list, fmt);
|
|
||||||
if (fmt) fprintf(stderr, fmt, list);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
va_end(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
err(int eval, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
|
|
||||||
va_start(list, fmt);
|
|
||||||
warn(fmt, list);
|
|
||||||
va_end(list);
|
|
||||||
exit(eval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
errx(int eval, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list list;
|
|
||||||
|
|
||||||
va_start(list, fmt);
|
|
||||||
warnx(fmt, list);
|
|
||||||
va_end(list);
|
|
||||||
exit(eval);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int recent_seqno(int ourseqno, int gotseqno)
|
|
||||||
/* Return 1 if we've seen gotseqno recently (current or up to 3 back).
|
|
||||||
Return 0 if gotseqno is new (or very old).
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 4; i++, ourseqno--) {
|
|
||||||
if (ourseqno < 0)
|
|
||||||
ourseqno = 7;
|
|
||||||
if (gotseqno == ourseqno)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __COMMON_H__
|
|
||||||
#define __COMMON_H__
|
|
||||||
|
|
||||||
/* Last byte of raw header is the command */
|
|
||||||
#define RAW_HDR_LEN 4
|
|
||||||
#define RAW_HDR_IDENT_LEN 3
|
|
||||||
#define RAW_HDR_CMD 3
|
|
||||||
#define RAW_HDR_CMD_LOGIN 0x10
|
|
||||||
#define RAW_HDR_CMD_DATA 0x20
|
|
||||||
#define RAW_HDR_CMD_PING 0x30
|
|
||||||
|
|
||||||
#define RAW_HDR_CMD_MASK 0xF0
|
|
||||||
#define RAW_HDR_USR_MASK 0x0F
|
|
||||||
#define RAW_HDR_GET_CMD(x) ((x)[RAW_HDR_CMD] & RAW_HDR_CMD_MASK)
|
|
||||||
#define RAW_HDR_GET_USR(x) ((x)[RAW_HDR_CMD] & RAW_HDR_USR_MASK)
|
|
||||||
extern const unsigned char raw_header[RAW_HDR_LEN];
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include "windows.h"
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DNS_PORT 53
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
|
||||||
#endif
|
|
||||||
#ifndef MAX
|
|
||||||
#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
|
|
||||||
|
|
||||||
#if defined IP_MTU_DISCOVER
|
|
||||||
/* Linux */
|
|
||||||
# define IP_OPT_DONT_FRAG IP_MTU_DISCOVER
|
|
||||||
# define DONT_FRAG_VALUE IP_PMTUDISC_DO
|
|
||||||
#elif defined IP_DONTFRAG
|
|
||||||
/* FreeBSD */
|
|
||||||
# define IP_OPT_DONT_FRAG IP_DONTFRAG
|
|
||||||
# define DONT_FRAG_VALUE 1
|
|
||||||
#elif defined IP_DONTFRAGMENT
|
|
||||||
/* Winsock2 */
|
|
||||||
# define IP_OPT_DONT_FRAG IP_DONTFRAGMENT
|
|
||||||
# define DONT_FRAG_VALUE 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define T_UNSET 65432
|
|
||||||
/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */
|
|
||||||
|
|
||||||
struct packet
|
|
||||||
{
|
|
||||||
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[QUERY_NAME_SIZE];
|
|
||||||
unsigned short type;
|
|
||||||
unsigned short rcode;
|
|
||||||
unsigned short id;
|
|
||||||
struct in_addr destination;
|
|
||||||
struct sockaddr from;
|
|
||||||
int fromlen;
|
|
||||||
unsigned short id2;
|
|
||||||
struct sockaddr from2;
|
|
||||||
int fromlen2;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum connection {
|
|
||||||
CONN_RAW_UDP,
|
|
||||||
CONN_DNS_NULL,
|
|
||||||
CONN_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
void check_superuser(void (*usage_fn)(void));
|
|
||||||
int open_dns(int, in_addr_t);
|
|
||||||
void close_dns(int);
|
|
||||||
|
|
||||||
void do_chroot(char *);
|
|
||||||
void do_setcon(char *);
|
|
||||||
void do_detach();
|
|
||||||
void do_pidfile(char *);
|
|
||||||
|
|
||||||
void read_password(char*, size_t);
|
|
||||||
|
|
||||||
int check_topdomain(char *);
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
int inet_aton(const char *cp, struct in_addr *inp);
|
|
||||||
|
|
||||||
void err(int eval, const char *fmt, ...);
|
|
||||||
void warn(const char *fmt, ...);
|
|
||||||
void errx(int eval, const char *fmt, ...);
|
|
||||||
void warnx(const char *fmt, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int recent_seqno(int , int);
|
|
||||||
|
|
||||||
#endif
|
|
610
iodine/src/dns.c
610
iodine/src/dns.c
|
@ -1,610 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include "windows.h"
|
|
||||||
#else
|
|
||||||
#include <arpa/nameser.h>
|
|
||||||
#ifdef DARWIN
|
|
||||||
#define BIND_8_COMPAT
|
|
||||||
#include <arpa/nameser_compat.h>
|
|
||||||
#endif
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <err.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "dns.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "read.h"
|
|
||||||
|
|
||||||
int dnsc_use_edns0 = 1;
|
|
||||||
|
|
||||||
#define CHECKLEN(x) if (buflen - (p-buf) < (x)) return 0
|
|
||||||
|
|
||||||
int
|
|
||||||
dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
|
|
||||||
{
|
|
||||||
HEADER *header;
|
|
||||||
short name;
|
|
||||||
char *p;
|
|
||||||
int len;
|
|
||||||
int ancnt;
|
|
||||||
|
|
||||||
if (buflen < sizeof(HEADER))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(buf, 0, buflen);
|
|
||||||
|
|
||||||
header = (HEADER*)buf;
|
|
||||||
|
|
||||||
header->id = htons(q->id);
|
|
||||||
header->qr = (qr == QR_ANSWER);
|
|
||||||
header->opcode = 0;
|
|
||||||
header->aa = (qr == QR_ANSWER);
|
|
||||||
header->tc = 0;
|
|
||||||
header->rd = (qr == QR_QUERY);
|
|
||||||
header->ra = 0;
|
|
||||||
|
|
||||||
p = buf + sizeof(HEADER);
|
|
||||||
|
|
||||||
switch (qr) {
|
|
||||||
case QR_ANSWER:
|
|
||||||
header->qdcount = htons(1);
|
|
||||||
|
|
||||||
name = 0xc000 | ((p - buf) & 0x3fff);
|
|
||||||
|
|
||||||
/* Question section */
|
|
||||||
putname(&p, buflen - (p - buf), q->name);
|
|
||||||
|
|
||||||
CHECKLEN(4);
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
|
|
||||||
/* Answer section */
|
|
||||||
|
|
||||||
if (q->type == T_CNAME || q->type == T_A) {
|
|
||||||
/* data is expected to be like "Hblabla.host.name.com\0" */
|
|
||||||
|
|
||||||
char *startp;
|
|
||||||
int namelen;
|
|
||||||
|
|
||||||
CHECKLEN(10);
|
|
||||||
putshort(&p, name);
|
|
||||||
if (q->type == T_A)
|
|
||||||
/* answer CNAME to A question */
|
|
||||||
putshort(&p, T_CNAME);
|
|
||||||
else
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
putlong(&p, 0); /* TTL */
|
|
||||||
|
|
||||||
startp = p;
|
|
||||||
p += 2; /* skip 2 bytes length */
|
|
||||||
putname(&p, buflen - (p - buf), data);
|
|
||||||
CHECKLEN(0);
|
|
||||||
namelen = p - startp;
|
|
||||||
namelen -= 2;
|
|
||||||
putshort(&startp, namelen);
|
|
||||||
ancnt = 1;
|
|
||||||
} else if (q->type == T_MX || q->type == T_SRV) {
|
|
||||||
/* Data is expected to be like
|
|
||||||
"Hblabla.host.name.com\0Hanother.com\0\0"
|
|
||||||
For SRV, see RFC2782.
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *mxdata = data;
|
|
||||||
char *startp;
|
|
||||||
int namelen;
|
|
||||||
|
|
||||||
ancnt = 1;
|
|
||||||
while (1) {
|
|
||||||
CHECKLEN(10);
|
|
||||||
putshort(&p, name);
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
putlong(&p, 0); /* TTL */
|
|
||||||
|
|
||||||
startp = p;
|
|
||||||
p += 2; /* skip 2 bytes length */
|
|
||||||
CHECKLEN(2);
|
|
||||||
putshort(&p, 10 * ancnt); /* preference */
|
|
||||||
|
|
||||||
if (q->type == T_SRV) {
|
|
||||||
/* weight, port (5060 = SIP) */
|
|
||||||
CHECKLEN(4);
|
|
||||||
putshort(&p, 10);
|
|
||||||
putshort(&p, 5060);
|
|
||||||
}
|
|
||||||
|
|
||||||
putname(&p, buflen - (p - buf), mxdata);
|
|
||||||
CHECKLEN(0);
|
|
||||||
namelen = p - startp;
|
|
||||||
namelen -= 2;
|
|
||||||
putshort(&startp, namelen);
|
|
||||||
|
|
||||||
mxdata = mxdata + strlen(mxdata) + 1;
|
|
||||||
if (*mxdata == '\0')
|
|
||||||
break;
|
|
||||||
|
|
||||||
ancnt++;
|
|
||||||
}
|
|
||||||
} else if (q->type == T_TXT) {
|
|
||||||
/* TXT has binary or base-X data */
|
|
||||||
char *startp;
|
|
||||||
int txtlen;
|
|
||||||
|
|
||||||
CHECKLEN(10);
|
|
||||||
putshort(&p, name);
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
putlong(&p, 0); /* TTL */
|
|
||||||
|
|
||||||
startp = p;
|
|
||||||
p += 2; /* skip 2 bytes length */
|
|
||||||
puttxtbin(&p, buflen - (p - buf), data, datalen);
|
|
||||||
CHECKLEN(0);
|
|
||||||
txtlen = p - startp;
|
|
||||||
txtlen -= 2;
|
|
||||||
putshort(&startp, txtlen);
|
|
||||||
ancnt = 1;
|
|
||||||
} else {
|
|
||||||
/* NULL has raw binary data */
|
|
||||||
|
|
||||||
CHECKLEN(10);
|
|
||||||
putshort(&p, name);
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
putlong(&p, 0); /* TTL */
|
|
||||||
|
|
||||||
datalen = MIN(datalen, buflen - (p - buf));
|
|
||||||
CHECKLEN(2);
|
|
||||||
putshort(&p, datalen);
|
|
||||||
CHECKLEN(datalen);
|
|
||||||
putdata(&p, data, datalen);
|
|
||||||
CHECKLEN(0);
|
|
||||||
ancnt = 1;
|
|
||||||
}
|
|
||||||
header->ancount = htons(ancnt);
|
|
||||||
break;
|
|
||||||
case QR_QUERY:
|
|
||||||
/* Note that iodined also uses this for forward queries */
|
|
||||||
|
|
||||||
header->qdcount = htons(1);
|
|
||||||
|
|
||||||
datalen = MIN(datalen, buflen - (p - buf));
|
|
||||||
putname(&p, datalen, data);
|
|
||||||
|
|
||||||
CHECKLEN(4);
|
|
||||||
putshort(&p, q->type);
|
|
||||||
putshort(&p, C_IN);
|
|
||||||
|
|
||||||
/* EDNS0 to advertise maximum response length
|
|
||||||
(even CNAME/A/MX, 255+255+header would be >512) */
|
|
||||||
if (dnsc_use_edns0) {
|
|
||||||
header->arcount = htons(1);
|
|
||||||
/*XXX START adjust indent 1 tab forward*/
|
|
||||||
CHECKLEN(11);
|
|
||||||
putbyte(&p, 0x00); /* Root */
|
|
||||||
putshort(&p, 0x0029); /* OPT */
|
|
||||||
putshort(&p, 0x1000); /* Payload size: 4096 */
|
|
||||||
putshort(&p, 0x0000); /* Higher bits/edns version */
|
|
||||||
putshort(&p, 0x8000); /* Z */
|
|
||||||
putshort(&p, 0x0000); /* Data length */
|
|
||||||
/*XXX END adjust indent 1 tab forward*/
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = p - buf;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
|
|
||||||
/* Only used when iodined gets an NS type query */
|
|
||||||
/* Mostly same as dns_encode_a_response() below */
|
|
||||||
{
|
|
||||||
HEADER *header;
|
|
||||||
int len;
|
|
||||||
short name;
|
|
||||||
short topname;
|
|
||||||
short nsname;
|
|
||||||
char *ipp;
|
|
||||||
int domain_len;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
if (buflen < sizeof(HEADER))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
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_len = strlen(q->name) - strlen(topdomain);
|
|
||||||
if (domain_len < 0 || domain_len == 1)
|
|
||||||
return -1;
|
|
||||||
if (strcasecmp(q->name + domain_len, topdomain))
|
|
||||||
return -1;
|
|
||||||
if (domain_len >= 1 && q->name[domain_len - 1] != '.')
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* pointer to start of topdomain; instead of dots at the end
|
|
||||||
we have length-bytes in front, so total length is the same */
|
|
||||||
topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);
|
|
||||||
|
|
||||||
/* Query section */
|
|
||||||
putname(&p, buflen - (p - buf), q->name); /* Name */
|
|
||||||
CHECKLEN(4);
|
|
||||||
putshort(&p, q->type); /* Type */
|
|
||||||
putshort(&p, C_IN); /* Class */
|
|
||||||
|
|
||||||
/* Answer section */
|
|
||||||
CHECKLEN(12);
|
|
||||||
putshort(&p, name); /* Name */
|
|
||||||
putshort(&p, q->type); /* Type */
|
|
||||||
putshort(&p, C_IN); /* Class */
|
|
||||||
putlong(&p, 3600); /* TTL */
|
|
||||||
putshort(&p, 5); /* Data length */
|
|
||||||
|
|
||||||
/* pointer to ns.topdomain */
|
|
||||||
nsname = 0xc000 | ((p - buf) & 0x3fff);
|
|
||||||
CHECKLEN(5);
|
|
||||||
putbyte(&p, 2);
|
|
||||||
putbyte(&p, 'n');
|
|
||||||
putbyte(&p, 's');
|
|
||||||
putshort(&p, topname); /* Name Server */
|
|
||||||
|
|
||||||
/* Additional data (A-record of NS server) */
|
|
||||||
CHECKLEN(12);
|
|
||||||
putshort(&p, nsname); /* Name Server */
|
|
||||||
putshort(&p, T_A); /* Type */
|
|
||||||
putshort(&p, C_IN); /* Class */
|
|
||||||
putlong(&p, 3600); /* TTL */
|
|
||||||
putshort(&p, 4); /* Data length */
|
|
||||||
|
|
||||||
/* ugly hack to output IP address */
|
|
||||||
ipp = (char *) &q->destination;
|
|
||||||
CHECKLEN(4);
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *ipp);
|
|
||||||
|
|
||||||
len = p - buf;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
|
||||||
/* Only used when iodined gets an A type query for ns.topdomain or www.topdomain */
|
|
||||||
/* Mostly same as dns_encode_ns_response() above */
|
|
||||||
{
|
|
||||||
HEADER *header;
|
|
||||||
int len;
|
|
||||||
short name;
|
|
||||||
char *ipp;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
if (buflen < sizeof(HEADER))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* pointer to start of name */
|
|
||||||
name = 0xc000 | ((p - buf) & 0x3fff);
|
|
||||||
|
|
||||||
/* Query section */
|
|
||||||
putname(&p, buflen - (p - buf), q->name); /* Name */
|
|
||||||
CHECKLEN(4);
|
|
||||||
putshort(&p, q->type); /* Type */
|
|
||||||
putshort(&p, C_IN); /* Class */
|
|
||||||
|
|
||||||
/* Answer section */
|
|
||||||
CHECKLEN(12);
|
|
||||||
putshort(&p, name); /* Name */
|
|
||||||
putshort(&p, q->type); /* Type */
|
|
||||||
putshort(&p, C_IN); /* Class */
|
|
||||||
putlong(&p, 3600); /* TTL */
|
|
||||||
putshort(&p, 4); /* Data length */
|
|
||||||
|
|
||||||
/* ugly hack to output IP address */
|
|
||||||
ipp = (char *) &q->destination;
|
|
||||||
CHECKLEN(4);
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *(ipp++));
|
|
||||||
putbyte(&p, *ipp);
|
|
||||||
|
|
||||||
len = p - buf;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CHECKLEN
|
|
||||||
|
|
||||||
unsigned short
|
|
||||||
dns_get_id(char *packet, size_t packetlen)
|
|
||||||
{
|
|
||||||
HEADER *header;
|
|
||||||
header = (HEADER*)packet;
|
|
||||||
|
|
||||||
if (packetlen < sizeof(HEADER))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ntohs(header->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECKLEN(x) if (packetlen - (data-packet) < (x)) return 0
|
|
||||||
|
|
||||||
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;
|
|
||||||
uint32_t ttl;
|
|
||||||
short class;
|
|
||||||
short type;
|
|
||||||
char *data;
|
|
||||||
short rlen;
|
|
||||||
int id;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
q->id2 = 0;
|
|
||||||
rv = 0;
|
|
||||||
header = (HEADER*)packet;
|
|
||||||
|
|
||||||
/* Reject short packets */
|
|
||||||
if (packetlen < sizeof(HEADER))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (header->qr != qr) {
|
|
||||||
warnx("header->qr does not match the requested qr");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = packet + sizeof(HEADER);
|
|
||||||
qdcount = ntohs(header->qdcount);
|
|
||||||
ancount = ntohs(header->ancount);
|
|
||||||
|
|
||||||
id = ntohs(header->id);
|
|
||||||
id = id & 0xFFFF; /* Kill any sign extension */
|
|
||||||
|
|
||||||
rlen = 0;
|
|
||||||
|
|
||||||
if (q != NULL)
|
|
||||||
q->rcode = header->rcode;
|
|
||||||
|
|
||||||
switch (qr) {
|
|
||||||
case QR_ANSWER:
|
|
||||||
if(qdcount < 1) {
|
|
||||||
/* We need a question */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (q != NULL)
|
|
||||||
q->id = id;
|
|
||||||
|
|
||||||
/* Read name even if no answer, to give better error message */
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
|
||||||
CHECKLEN(4);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
|
|
||||||
/* if CHECKLEN okay, then we're sure to have a proper name */
|
|
||||||
if (q != NULL) {
|
|
||||||
/* We only need the first char to check it */
|
|
||||||
q->name[0] = name[0];
|
|
||||||
q->name[1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ancount < 1) {
|
|
||||||
/* DNS errors like NXDOMAIN have ancount=0 and
|
|
||||||
stop here. CNAME may also have A; MX/SRV may have
|
|
||||||
multiple results. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here type is still the question type */
|
|
||||||
if (type == T_NULL) {
|
|
||||||
/* Assume that first answer is what we wanted */
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
|
||||||
CHECKLEN(10);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
readlong(packet, &data, &ttl);
|
|
||||||
readshort(packet, &data, &rlen);
|
|
||||||
|
|
||||||
rv = MIN(rlen, sizeof(rdata));
|
|
||||||
rv = readdata(packet, &data, rdata, rv);
|
|
||||||
if (rv >= 2 && buf) {
|
|
||||||
rv = MIN(rv, buflen);
|
|
||||||
memcpy(buf, rdata, rv);
|
|
||||||
} else {
|
|
||||||
rv = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((type == T_A || type == T_CNAME) && buf) {
|
|
||||||
/* Assume that first answer is what we wanted */
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
|
||||||
CHECKLEN(10);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
readlong(packet, &data, &ttl);
|
|
||||||
readshort(packet, &data, &rlen);
|
|
||||||
|
|
||||||
memset(name, 0, sizeof(name));
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
|
||||||
name[sizeof(name)-1] = '\0';
|
|
||||||
strncpy(buf, name, buflen);
|
|
||||||
buf[buflen - 1] = '\0';
|
|
||||||
rv = strlen(buf);
|
|
||||||
}
|
|
||||||
else if ((type == T_MX || type == T_SRV) && buf) {
|
|
||||||
/* We support 250 records, 250*(255+header) ~= 64kB.
|
|
||||||
Only exact 10-multiples are accepted, and gaps in
|
|
||||||
numbering are not jumped over (->truncated).
|
|
||||||
Hopefully DNS servers won't mess around too much.
|
|
||||||
*/
|
|
||||||
char names[250][QUERY_NAME_SIZE];
|
|
||||||
char *rdatastart;
|
|
||||||
short pref;
|
|
||||||
int i;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
memset(names, 0, sizeof(names));
|
|
||||||
|
|
||||||
for (i=0; i < ancount; i++) {
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
|
||||||
CHECKLEN(12);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
readlong(packet, &data, &ttl);
|
|
||||||
readshort(packet, &data, &rlen);
|
|
||||||
rdatastart = data;
|
|
||||||
readshort(packet, &data, &pref);
|
|
||||||
|
|
||||||
if (type == T_SRV) {
|
|
||||||
/* skip weight, port */
|
|
||||||
data += 4;
|
|
||||||
CHECKLEN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pref % 10 == 0 && pref >= 10 &&
|
|
||||||
pref < 2500) {
|
|
||||||
readname(packet, packetlen, &data,
|
|
||||||
names[pref / 10 - 1],
|
|
||||||
QUERY_NAME_SIZE - 1);
|
|
||||||
names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* always trust rlen, not name encoding */
|
|
||||||
data = rdatastart + rlen;
|
|
||||||
CHECKLEN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* output is like Hname10.com\0Hname20.com\0\0 */
|
|
||||||
offset = 0;
|
|
||||||
i = 0;
|
|
||||||
while (names[i][0] != '\0') {
|
|
||||||
int l = MIN(strlen(names[i]), buflen-offset-2);
|
|
||||||
if (l <= 0)
|
|
||||||
break;
|
|
||||||
memcpy(buf + offset, names[i], l);
|
|
||||||
offset += l;
|
|
||||||
*(buf + offset) = '\0';
|
|
||||||
offset++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
*(buf + offset) = '\0';
|
|
||||||
rv = offset;
|
|
||||||
}
|
|
||||||
else if (type == T_TXT && buf) {
|
|
||||||
/* Assume that first answer is what we wanted */
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
|
||||||
CHECKLEN(10);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
readlong(packet, &data, &ttl);
|
|
||||||
readshort(packet, &data, &rlen);
|
|
||||||
|
|
||||||
rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata));
|
|
||||||
if (rv >= 1) {
|
|
||||||
rv = MIN(rv, buflen);
|
|
||||||
memcpy(buf, rdata, rv);
|
|
||||||
} else {
|
|
||||||
rv = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here type is the answer type (note A->CNAME) */
|
|
||||||
if (q != NULL)
|
|
||||||
q->type = type;
|
|
||||||
break;
|
|
||||||
case QR_QUERY:
|
|
||||||
if (qdcount < 1) {
|
|
||||||
warnx("no question section in name query");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(name, 0, sizeof(name));
|
|
||||||
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
|
||||||
name[sizeof(name)-1] = '\0';
|
|
||||||
CHECKLEN(4);
|
|
||||||
readshort(packet, &data, &type);
|
|
||||||
readshort(packet, &data, &class);
|
|
||||||
|
|
||||||
if (q == NULL) {
|
|
||||||
rv = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(q->name, name, sizeof(q->name));
|
|
||||||
q->name[sizeof(q->name) - 1] = '\0';
|
|
||||||
q->type = type;
|
|
||||||
q->id = id;
|
|
||||||
|
|
||||||
rv = strlen(q->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __DNS_H__
|
|
||||||
#define __DNS_H__
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
QR_QUERY = 0,
|
|
||||||
QR_ANSWER = 1
|
|
||||||
} qr_t;
|
|
||||||
|
|
||||||
extern int dnsc_use_edns0;
|
|
||||||
|
|
||||||
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);
|
|
||||||
int dns_encode_a_response(char *buf, size_t buflen, struct query *q);
|
|
||||||
unsigned short dns_get_id(char *packet, size_t packetlen);
|
|
||||||
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
|
|
||||||
|
|
||||||
#endif /* _DNS_H_ */
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 "common.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
build_hostname(char *buf, size_t buflen,
|
|
||||||
const char *data, const size_t datalen,
|
|
||||||
const char *topdomain, struct encoder *encoder, int maxlen)
|
|
||||||
{
|
|
||||||
int encsize;
|
|
||||||
size_t space;
|
|
||||||
char *b;
|
|
||||||
|
|
||||||
space = MIN(maxlen, buflen) - strlen(topdomain) - 8;
|
|
||||||
/* 8 = 5 max header length + 1 dot before topdomain + 2 safety */
|
|
||||||
|
|
||||||
if (!encoder->places_dots())
|
|
||||||
space -= (space / 57); /* space for dots */
|
|
||||||
|
|
||||||
memset(buf, 0, buflen);
|
|
||||||
|
|
||||||
encsize = encoder->encode(buf, &space, data, datalen);
|
|
||||||
|
|
||||||
if (!encoder->places_dots())
|
|
||||||
inline_dotify(buf, buflen);
|
|
||||||
|
|
||||||
b = buf;
|
|
||||||
b += strlen(buf);
|
|
||||||
|
|
||||||
/* move b back one step to see if the dot is there */
|
|
||||||
b--;
|
|
||||||
if (*b != '.')
|
|
||||||
*++b = '.';
|
|
||||||
b++;
|
|
||||||
/* move b ahead of the string so we can copy to it */
|
|
||||||
|
|
||||||
strncpy(b, topdomain, strlen(topdomain)+1);
|
|
||||||
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
|
|
||||||
{
|
|
||||||
if (!enc->eats_dots())
|
|
||||||
datalen = inline_undotify(data, datalen);
|
|
||||||
return enc->decode(buf, &buflen, data, datalen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
inline_dotify(char *buf, size_t buflen)
|
|
||||||
{
|
|
||||||
unsigned dots;
|
|
||||||
unsigned pos;
|
|
||||||
unsigned total;
|
|
||||||
char *reader, *writer;
|
|
||||||
|
|
||||||
total = strlen(buf);
|
|
||||||
dots = total / 57;
|
|
||||||
|
|
||||||
writer = buf;
|
|
||||||
writer += total;
|
|
||||||
writer += dots;
|
|
||||||
|
|
||||||
total += dots;
|
|
||||||
if (strlen(buf) + dots > buflen) {
|
|
||||||
writer = buf;
|
|
||||||
writer += buflen;
|
|
||||||
total = buflen;
|
|
||||||
}
|
|
||||||
|
|
||||||
reader = writer - dots;
|
|
||||||
pos = (unsigned) (reader - buf) + 1;
|
|
||||||
|
|
||||||
while (dots) {
|
|
||||||
*writer-- = *reader--;
|
|
||||||
pos--;
|
|
||||||
if (pos % 57 == 0) {
|
|
||||||
*writer-- = '.';
|
|
||||||
dots--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return new length of string */
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
inline_undotify(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
unsigned pos;
|
|
||||||
unsigned dots;
|
|
||||||
char *reader, *writer;
|
|
||||||
|
|
||||||
writer = buf;
|
|
||||||
reader = writer;
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
dots = 0;
|
|
||||||
|
|
||||||
while (pos < len) {
|
|
||||||
if (*reader == '.') {
|
|
||||||
reader++;
|
|
||||||
pos++;
|
|
||||||
dots++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*writer++ = *reader++;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return new length of string */
|
|
||||||
return len - dots;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 _ENCODING_H_
|
|
||||||
#define _ENCODING_H_
|
|
||||||
|
|
||||||
/* All-0, all-1, 01010101, 10101010: each 4 times to make sure the pattern
|
|
||||||
spreads across multiple encoded chars -> 16 bytes total.
|
|
||||||
Followed by 32 bytes from my /dev/random; should be enough.
|
|
||||||
*/
|
|
||||||
#define DOWNCODECCHECK1 "\000\000\000\000\377\377\377\377\125\125\125\125\252\252\252\252\201\143\310\322\307\174\262\027\137\117\316\311\111\055\122\041\141\251\161\040\045\263\006\163\346\330\104\060\171\120\127\277"
|
|
||||||
#define DOWNCODECCHECK1_LEN 48
|
|
||||||
|
|
||||||
struct encoder {
|
|
||||||
char name[8];
|
|
||||||
int (*encode) (char *, size_t *, const void *, size_t);
|
|
||||||
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 build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *, int);
|
|
||||||
int unpack_data(char *, size_t, char *, size_t, struct encoder *);
|
|
||||||
int inline_dotify(char *, size_t);
|
|
||||||
int inline_undotify(char *, size_t);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _ENCODING_H_ */
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* 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(unsigned 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* 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>
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include "windows.h"
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FW_QUERY_CACHE_SIZE 16
|
|
||||||
|
|
||||||
struct fw_query {
|
|
||||||
struct sockaddr addr;
|
|
||||||
int addrlen;
|
|
||||||
unsigned short id;
|
|
||||||
};
|
|
||||||
|
|
||||||
void fw_query_init();
|
|
||||||
void fw_query_put(struct fw_query *fw_query);
|
|
||||||
void fw_query_get(unsigned short query_id, struct fw_query **fw_query);
|
|
||||||
|
|
||||||
#endif /*__FW_QUERY_H__*/
|
|
||||||
|
|
|
@ -1,379 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include "windows.h"
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "tun.h"
|
|
||||||
#include "client.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
WORD req_version = MAKEWORD(2, 2);
|
|
||||||
WSADATA wsa_data;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BSD) && !defined(__GLIBC__)
|
|
||||||
static char *__progname;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PASSWORD_ENV_VAR "IODINE_PASS"
|
|
||||||
|
|
||||||
static void
|
|
||||||
sighandler(int sig)
|
|
||||||
{
|
|
||||||
client_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
usage() {
|
|
||||||
extern char *__progname;
|
|
||||||
|
|
||||||
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
|
||||||
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
|
|
||||||
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
help() {
|
|
||||||
extern char *__progname;
|
|
||||||
|
|
||||||
fprintf(stderr, "iodine IP over DNS tunneling client\n");
|
|
||||||
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
|
||||||
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
|
|
||||||
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
|
|
||||||
fprintf(stderr, "Options to try if connection doesn't work:\n");
|
|
||||||
fprintf(stderr, " -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
|
|
||||||
fprintf(stderr, " -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n");
|
|
||||||
fprintf(stderr, " Base128, or (only for TXT:) Raw (default: autodetect)\n");
|
|
||||||
fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent DNS timeouts\n");
|
|
||||||
fprintf(stderr, " -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n");
|
|
||||||
fprintf(stderr, " -m max size of downstream fragments (default: autodetect)\n");
|
|
||||||
fprintf(stderr, " -M max size of upstream hostnames (~100-255, default: 255)\n");
|
|
||||||
fprintf(stderr, " -r to skip raw UDP mode attempt\n");
|
|
||||||
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
|
|
||||||
fprintf(stderr, "Other options:\n");
|
|
||||||
fprintf(stderr, " -v to print version info and exit\n");
|
|
||||||
fprintf(stderr, " -h to print this help and exit\n");
|
|
||||||
fprintf(stderr, " -f to keep running in foreground\n");
|
|
||||||
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
|
|
||||||
fprintf(stderr, " -t dir to chroot to directory dir\n");
|
|
||||||
fprintf(stderr, " -d device to set tunnel device name\n");
|
|
||||||
fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n");
|
|
||||||
fprintf(stderr, " -F pidfile to write pid to a file\n");
|
|
||||||
fprintf(stderr, "nameserver is the IP number/hostname of the relaying nameserver. if absent, /etc/resolv.conf is used\n");
|
|
||||||
fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
version() {
|
|
||||||
char *svnver;
|
|
||||||
|
|
||||||
svnver = "$Rev$ from $Date$";
|
|
||||||
|
|
||||||
fprintf(stderr, "iodine IP over DNS tunneling client\n");
|
|
||||||
fprintf(stderr, "SVN version: %s\n", svnver);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *nameserv_addr;
|
|
||||||
char *topdomain;
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
struct passwd *pw;
|
|
||||||
#endif
|
|
||||||
char *username;
|
|
||||||
char password[33];
|
|
||||||
int foreground;
|
|
||||||
char *newroot;
|
|
||||||
char *context;
|
|
||||||
char *device;
|
|
||||||
char *pidfile;
|
|
||||||
int choice;
|
|
||||||
int tun_fd;
|
|
||||||
int dns_fd;
|
|
||||||
int max_downstream_frag_size;
|
|
||||||
int autodetect_frag_size;
|
|
||||||
int retval;
|
|
||||||
int raw_mode;
|
|
||||||
int lazymode;
|
|
||||||
int selecttimeout;
|
|
||||||
int hostname_maxlen;
|
|
||||||
|
|
||||||
nameserv_addr = NULL;
|
|
||||||
topdomain = NULL;
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
pw = NULL;
|
|
||||||
#endif
|
|
||||||
username = NULL;
|
|
||||||
memset(password, 0, 33);
|
|
||||||
srand(time(NULL));
|
|
||||||
foreground = 0;
|
|
||||||
newroot = NULL;
|
|
||||||
context = NULL;
|
|
||||||
device = NULL;
|
|
||||||
pidfile = NULL;
|
|
||||||
|
|
||||||
autodetect_frag_size = 1;
|
|
||||||
max_downstream_frag_size = 3072;
|
|
||||||
retval = 0;
|
|
||||||
raw_mode = 1;
|
|
||||||
lazymode = 1;
|
|
||||||
selecttimeout = 4;
|
|
||||||
hostname_maxlen = 0xFF;
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
WSAStartup(req_version, &wsa_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
srand((unsigned) time(NULL));
|
|
||||||
client_init();
|
|
||||||
|
|
||||||
#if !defined(BSD) && !defined(__GLIBC__)
|
|
||||||
__progname = strrchr(argv[0], '/');
|
|
||||||
if (__progname == NULL)
|
|
||||||
__progname = argv[0];
|
|
||||||
else
|
|
||||||
__progname++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) {
|
|
||||||
switch(choice) {
|
|
||||||
case 'v':
|
|
||||||
version();
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
foreground = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
help();
|
|
||||||
/* NOTREACHED */
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
raw_mode = 0;
|
|
||||||
case 'u':
|
|
||||||
username = optarg;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
newroot = optarg;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
device = optarg;
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
strncpy(password, optarg, sizeof(password));
|
|
||||||
password[sizeof(password)-1] = 0;
|
|
||||||
|
|
||||||
/* XXX: find better way of cleaning up ps(1) */
|
|
||||||
memset(optarg, 0, strlen(optarg));
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
autodetect_frag_size = 0;
|
|
||||||
max_downstream_frag_size = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
hostname_maxlen = atoi(optarg);
|
|
||||||
if (hostname_maxlen > 255)
|
|
||||||
hostname_maxlen = 255;
|
|
||||||
if (hostname_maxlen < 10)
|
|
||||||
hostname_maxlen = 10;
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
context = optarg;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
pidfile = optarg;
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
set_qtype(optarg);
|
|
||||||
break;
|
|
||||||
case 'O': /* not -D, is Debug in server */
|
|
||||||
set_downenc(optarg);
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
lazymode = atoi(optarg);
|
|
||||||
if (lazymode > 1)
|
|
||||||
lazymode = 1;
|
|
||||||
if (lazymode < 0)
|
|
||||||
lazymode = 0;
|
|
||||||
if (!lazymode)
|
|
||||||
selecttimeout = 1;
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
selecttimeout = atoi(optarg);
|
|
||||||
if (selecttimeout < 1)
|
|
||||||
selecttimeout = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_superuser(usage);
|
|
||||||
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (nameserv_addr) {
|
|
||||||
client_set_nameserver(nameserv_addr, DNS_PORT);
|
|
||||||
} else {
|
|
||||||
warnx("No nameserver found - not connected to any network?\n");
|
|
||||||
usage();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(topdomain) <= 128) {
|
|
||||||
if(check_topdomain(topdomain)) {
|
|
||||||
warnx("Topdomain contains invalid characters.\n");
|
|
||||||
usage();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warnx("Use a topdomain max 128 chars long.\n");
|
|
||||||
usage();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
client_set_selecttimeout(selecttimeout);
|
|
||||||
client_set_lazymode(lazymode);
|
|
||||||
client_set_topdomain(topdomain);
|
|
||||||
client_set_hostname_maxlen(hostname_maxlen);
|
|
||||||
|
|
||||||
if (username != NULL) {
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
if ((pw = getpwnam(username)) == NULL) {
|
|
||||||
warnx("User %s does not exist!\n", username);
|
|
||||||
usage();
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(password) == 0) {
|
|
||||||
if (NULL != getenv(PASSWORD_ENV_VAR))
|
|
||||||
snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
|
|
||||||
else
|
|
||||||
read_password(password, sizeof(password));
|
|
||||||
}
|
|
||||||
|
|
||||||
client_set_password(password);
|
|
||||||
|
|
||||||
if ((tun_fd = open_tun(device)) == -1) {
|
|
||||||
retval = 1;
|
|
||||||
goto cleanup1;
|
|
||||||
}
|
|
||||||
if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) {
|
|
||||||
retval = 1;
|
|
||||||
goto cleanup2;
|
|
||||||
}
|
|
||||||
|
|
||||||
signal(SIGINT, sighandler);
|
|
||||||
signal(SIGTERM, sighandler);
|
|
||||||
|
|
||||||
fprintf(stderr, "Sending DNS queries for %s to %s\n",
|
|
||||||
topdomain, nameserv_addr);
|
|
||||||
|
|
||||||
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
|
|
||||||
retval = 1;
|
|
||||||
goto cleanup2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client_get_conn() == CONN_RAW_UDP) {
|
|
||||||
fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Connection setup complete, transmitting data.\n");
|
|
||||||
|
|
||||||
if (foreground == 0)
|
|
||||||
do_detach();
|
|
||||||
|
|
||||||
if (pidfile != NULL)
|
|
||||||
do_pidfile(pidfile);
|
|
||||||
|
|
||||||
if (newroot != NULL)
|
|
||||||
do_chroot(newroot);
|
|
||||||
|
|
||||||
if (username != NULL) {
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context != NULL)
|
|
||||||
do_setcon(context);
|
|
||||||
|
|
||||||
client_tunnel(tun_fd, dns_fd);
|
|
||||||
|
|
||||||
cleanup2:
|
|
||||||
close_dns(dns_fd);
|
|
||||||
close_tun(tun_fd);
|
|
||||||
cleanup1:
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
2488
iodine/src/iodined.c
2488
iodine/src/iodined.c
File diff suppressed because it is too large
Load Diff
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <sys/types.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include "windows.h"
|
|
||||||
#else
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "md5.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Needs a 16byte array for output, and 32 bytes password
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
login_calculate(char *buf, int buflen, const char *pass, int seed)
|
|
||||||
{
|
|
||||||
unsigned char temp[32];
|
|
||||||
md5_state_t ctx;
|
|
||||||
int *ix;
|
|
||||||
int i;
|
|
||||||
int k;
|
|
||||||
|
|
||||||
if (buflen < 16)
|
|
||||||
return;
|
|
||||||
|
|
||||||
memcpy(temp, pass, 32);
|
|
||||||
ix = (int*) temp;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
k = ntohl(*ix);
|
|
||||||
k ^= seed;
|
|
||||||
*ix++ = htonl(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
md5_init(&ctx);
|
|
||||||
md5_append(&ctx, temp, 32);
|
|
||||||
md5_finish(&ctx, (unsigned char *) buf);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __LOGIN_H__
|
|
||||||
#define __LOGIN_H__
|
|
||||||
|
|
||||||
void login_calculate(char *, int, const char *, int);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
384
iodine/src/md5.c
384
iodine/src/md5.c
|
@ -1,384 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
L. Peter Deutsch
|
|
||||||
ghost@aladdin.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
|
|
||||||
/*
|
|
||||||
Independent implementation of MD5 (RFC 1321).
|
|
||||||
|
|
||||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
|
||||||
text is available at
|
|
||||||
http://www.ietf.org/rfc/rfc1321.txt
|
|
||||||
The code is derived from the text of the RFC, including the test suite
|
|
||||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
|
||||||
any code or documentation that is identified in the RFC as being
|
|
||||||
copyrighted.
|
|
||||||
|
|
||||||
The original and principal author of md5.c is L. Peter Deutsch
|
|
||||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
|
||||||
that follows (in reverse chronological order):
|
|
||||||
|
|
||||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
|
||||||
either statically or dynamically; added missing #include <string.h>
|
|
||||||
in library.
|
|
||||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
|
||||||
type, in test program and T value program.
|
|
||||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
|
||||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
|
||||||
unsigned in ANSI C, signed in traditional"; made test program
|
|
||||||
self-checking.
|
|
||||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
|
||||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
|
||||||
1999-05-03 lpd Original version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "md5.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
|
||||||
#ifdef ARCH_IS_BIG_ENDIAN
|
|
||||||
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
|
||||||
#else
|
|
||||||
# define BYTE_ORDER 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define T_MASK ((md5_word_t)~0)
|
|
||||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
|
||||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
|
||||||
#define T3 0x242070db
|
|
||||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
|
||||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
|
||||||
#define T6 0x4787c62a
|
|
||||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
|
||||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
|
||||||
#define T9 0x698098d8
|
|
||||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
|
||||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
|
||||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
|
||||||
#define T13 0x6b901122
|
|
||||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
|
||||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
|
||||||
#define T16 0x49b40821
|
|
||||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
|
||||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
|
||||||
#define T19 0x265e5a51
|
|
||||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
|
||||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
|
||||||
#define T22 0x02441453
|
|
||||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
|
||||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
|
||||||
#define T25 0x21e1cde6
|
|
||||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
|
||||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
|
||||||
#define T28 0x455a14ed
|
|
||||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
|
||||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
|
||||||
#define T31 0x676f02d9
|
|
||||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
|
||||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
|
||||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
|
||||||
#define T35 0x6d9d6122
|
|
||||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
|
||||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
|
||||||
#define T38 0x4bdecfa9
|
|
||||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
|
||||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
|
||||||
#define T41 0x289b7ec6
|
|
||||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
|
||||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
|
||||||
#define T44 0x04881d05
|
|
||||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
|
||||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
|
||||||
#define T47 0x1fa27cf8
|
|
||||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
|
||||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
|
||||||
#define T50 0x432aff97
|
|
||||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
|
||||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
|
||||||
#define T53 0x655b59c3
|
|
||||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
|
||||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
|
||||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
|
||||||
#define T57 0x6fa87e4f
|
|
||||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
|
||||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
|
||||||
#define T60 0x4e0811a1
|
|
||||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
|
||||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
|
||||||
#define T63 0x2ad7d2bb
|
|
||||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
|
||||||
{
|
|
||||||
md5_word_t
|
|
||||||
a = pms->abcd[0], b = pms->abcd[1],
|
|
||||||
c = pms->abcd[2], d = pms->abcd[3];
|
|
||||||
md5_word_t t;
|
|
||||||
#if BYTE_ORDER > 0
|
|
||||||
/* Define storage only for big-endian CPUs. */
|
|
||||||
md5_word_t X[16];
|
|
||||||
#else
|
|
||||||
/* Define storage for little-endian or both types of CPUs. */
|
|
||||||
md5_word_t xbuf[16];
|
|
||||||
const md5_word_t *X;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
|
||||||
#if BYTE_ORDER == 0
|
|
||||||
/*
|
|
||||||
* Determine dynamically whether this is a big-endian or
|
|
||||||
* little-endian machine, since we can use a more efficient
|
|
||||||
* algorithm on the latter.
|
|
||||||
*/
|
|
||||||
static const int w = 1;
|
|
||||||
|
|
||||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
|
||||||
#endif
|
|
||||||
#if BYTE_ORDER <= 0 /* little-endian */
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* On little-endian machines, we can process properly aligned
|
|
||||||
* data without copying it.
|
|
||||||
*/
|
|
||||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
|
||||||
/* data are properly aligned */
|
|
||||||
X = (const md5_word_t *)data;
|
|
||||||
} else {
|
|
||||||
/* not aligned */
|
|
||||||
memcpy(xbuf, data, 64);
|
|
||||||
X = xbuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if BYTE_ORDER == 0
|
|
||||||
else /* dynamic big-endian */
|
|
||||||
#endif
|
|
||||||
#if BYTE_ORDER >= 0 /* big-endian */
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* On big-endian machines, we must arrange the bytes in the
|
|
||||||
* right order.
|
|
||||||
*/
|
|
||||||
const md5_byte_t *xp = data;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
# if BYTE_ORDER == 0
|
|
||||||
X = xbuf; /* (dynamic only) */
|
|
||||||
# else
|
|
||||||
# define xbuf X /* (static only) */
|
|
||||||
# endif
|
|
||||||
for (i = 0; i < 16; ++i, xp += 4)
|
|
||||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
|
||||||
|
|
||||||
/* Round 1. */
|
|
||||||
/* Let [abcd k s i] denote the operation
|
|
||||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
|
||||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
|
||||||
#define SET(a, b, c, d, k, s, Ti)\
|
|
||||||
t = a + F(b,c,d) + X[k] + Ti;\
|
|
||||||
a = ROTATE_LEFT(t, s) + b
|
|
||||||
/* Do the following 16 operations. */
|
|
||||||
SET(a, b, c, d, 0, 7, T1);
|
|
||||||
SET(d, a, b, c, 1, 12, T2);
|
|
||||||
SET(c, d, a, b, 2, 17, T3);
|
|
||||||
SET(b, c, d, a, 3, 22, T4);
|
|
||||||
SET(a, b, c, d, 4, 7, T5);
|
|
||||||
SET(d, a, b, c, 5, 12, T6);
|
|
||||||
SET(c, d, a, b, 6, 17, T7);
|
|
||||||
SET(b, c, d, a, 7, 22, T8);
|
|
||||||
SET(a, b, c, d, 8, 7, T9);
|
|
||||||
SET(d, a, b, c, 9, 12, T10);
|
|
||||||
SET(c, d, a, b, 10, 17, T11);
|
|
||||||
SET(b, c, d, a, 11, 22, T12);
|
|
||||||
SET(a, b, c, d, 12, 7, T13);
|
|
||||||
SET(d, a, b, c, 13, 12, T14);
|
|
||||||
SET(c, d, a, b, 14, 17, T15);
|
|
||||||
SET(b, c, d, a, 15, 22, T16);
|
|
||||||
#undef SET
|
|
||||||
|
|
||||||
/* Round 2. */
|
|
||||||
/* Let [abcd k s i] denote the operation
|
|
||||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
|
||||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
|
||||||
#define SET(a, b, c, d, k, s, Ti)\
|
|
||||||
t = a + G(b,c,d) + X[k] + Ti;\
|
|
||||||
a = ROTATE_LEFT(t, s) + b
|
|
||||||
/* Do the following 16 operations. */
|
|
||||||
SET(a, b, c, d, 1, 5, T17);
|
|
||||||
SET(d, a, b, c, 6, 9, T18);
|
|
||||||
SET(c, d, a, b, 11, 14, T19);
|
|
||||||
SET(b, c, d, a, 0, 20, T20);
|
|
||||||
SET(a, b, c, d, 5, 5, T21);
|
|
||||||
SET(d, a, b, c, 10, 9, T22);
|
|
||||||
SET(c, d, a, b, 15, 14, T23);
|
|
||||||
SET(b, c, d, a, 4, 20, T24);
|
|
||||||
SET(a, b, c, d, 9, 5, T25);
|
|
||||||
SET(d, a, b, c, 14, 9, T26);
|
|
||||||
SET(c, d, a, b, 3, 14, T27);
|
|
||||||
SET(b, c, d, a, 8, 20, T28);
|
|
||||||
SET(a, b, c, d, 13, 5, T29);
|
|
||||||
SET(d, a, b, c, 2, 9, T30);
|
|
||||||
SET(c, d, a, b, 7, 14, T31);
|
|
||||||
SET(b, c, d, a, 12, 20, T32);
|
|
||||||
#undef SET
|
|
||||||
|
|
||||||
/* Round 3. */
|
|
||||||
/* Let [abcd k s t] denote the operation
|
|
||||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
|
||||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
|
||||||
#define SET(a, b, c, d, k, s, Ti)\
|
|
||||||
t = a + H(b,c,d) + X[k] + Ti;\
|
|
||||||
a = ROTATE_LEFT(t, s) + b
|
|
||||||
/* Do the following 16 operations. */
|
|
||||||
SET(a, b, c, d, 5, 4, T33);
|
|
||||||
SET(d, a, b, c, 8, 11, T34);
|
|
||||||
SET(c, d, a, b, 11, 16, T35);
|
|
||||||
SET(b, c, d, a, 14, 23, T36);
|
|
||||||
SET(a, b, c, d, 1, 4, T37);
|
|
||||||
SET(d, a, b, c, 4, 11, T38);
|
|
||||||
SET(c, d, a, b, 7, 16, T39);
|
|
||||||
SET(b, c, d, a, 10, 23, T40);
|
|
||||||
SET(a, b, c, d, 13, 4, T41);
|
|
||||||
SET(d, a, b, c, 0, 11, T42);
|
|
||||||
SET(c, d, a, b, 3, 16, T43);
|
|
||||||
SET(b, c, d, a, 6, 23, T44);
|
|
||||||
SET(a, b, c, d, 9, 4, T45);
|
|
||||||
SET(d, a, b, c, 12, 11, T46);
|
|
||||||
SET(c, d, a, b, 15, 16, T47);
|
|
||||||
SET(b, c, d, a, 2, 23, T48);
|
|
||||||
#undef SET
|
|
||||||
|
|
||||||
/* Round 4. */
|
|
||||||
/* Let [abcd k s t] denote the operation
|
|
||||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
|
||||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
|
||||||
#define SET(a, b, c, d, k, s, Ti)\
|
|
||||||
t = a + I(b,c,d) + X[k] + Ti;\
|
|
||||||
a = ROTATE_LEFT(t, s) + b
|
|
||||||
/* Do the following 16 operations. */
|
|
||||||
SET(a, b, c, d, 0, 6, T49);
|
|
||||||
SET(d, a, b, c, 7, 10, T50);
|
|
||||||
SET(c, d, a, b, 14, 15, T51);
|
|
||||||
SET(b, c, d, a, 5, 21, T52);
|
|
||||||
SET(a, b, c, d, 12, 6, T53);
|
|
||||||
SET(d, a, b, c, 3, 10, T54);
|
|
||||||
SET(c, d, a, b, 10, 15, T55);
|
|
||||||
SET(b, c, d, a, 1, 21, T56);
|
|
||||||
SET(a, b, c, d, 8, 6, T57);
|
|
||||||
SET(d, a, b, c, 15, 10, T58);
|
|
||||||
SET(c, d, a, b, 6, 15, T59);
|
|
||||||
SET(b, c, d, a, 13, 21, T60);
|
|
||||||
SET(a, b, c, d, 4, 6, T61);
|
|
||||||
SET(d, a, b, c, 11, 10, T62);
|
|
||||||
SET(c, d, a, b, 2, 15, T63);
|
|
||||||
SET(b, c, d, a, 9, 21, T64);
|
|
||||||
#undef SET
|
|
||||||
|
|
||||||
/* Then perform the following additions. (That is increment each
|
|
||||||
of the four registers by the value it had before this block
|
|
||||||
was started.) */
|
|
||||||
pms->abcd[0] += a;
|
|
||||||
pms->abcd[1] += b;
|
|
||||||
pms->abcd[2] += c;
|
|
||||||
pms->abcd[3] += d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
md5_init(md5_state_t *pms)
|
|
||||||
{
|
|
||||||
pms->count[0] = pms->count[1] = 0;
|
|
||||||
pms->abcd[0] = 0x67452301;
|
|
||||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
|
||||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
|
||||||
pms->abcd[3] = 0x10325476;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
|
||||||
{
|
|
||||||
const md5_byte_t *p = data;
|
|
||||||
int left = nbytes;
|
|
||||||
int offset = (pms->count[0] >> 3) & 63;
|
|
||||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
|
||||||
|
|
||||||
if (nbytes <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Update the message length. */
|
|
||||||
pms->count[1] += nbytes >> 29;
|
|
||||||
pms->count[0] += nbits;
|
|
||||||
if (pms->count[0] < nbits)
|
|
||||||
pms->count[1]++;
|
|
||||||
|
|
||||||
/* Process an initial partial block. */
|
|
||||||
if (offset) {
|
|
||||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
|
||||||
|
|
||||||
memcpy(pms->buf + offset, p, copy);
|
|
||||||
if (offset + copy < 64)
|
|
||||||
return;
|
|
||||||
p += copy;
|
|
||||||
left -= copy;
|
|
||||||
md5_process(pms, pms->buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process full blocks. */
|
|
||||||
for (; left >= 64; p += 64, left -= 64)
|
|
||||||
md5_process(pms, p);
|
|
||||||
|
|
||||||
/* Process a final partial block. */
|
|
||||||
if (left)
|
|
||||||
memcpy(pms->buf, p, left);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
|
||||||
{
|
|
||||||
static const md5_byte_t pad[64] = {
|
|
||||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
||||||
};
|
|
||||||
md5_byte_t data[8];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Save the length before padding. */
|
|
||||||
for (i = 0; i < 8; ++i)
|
|
||||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
|
||||||
/* Pad to 56 bytes mod 64. */
|
|
||||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
|
||||||
/* Append the length. */
|
|
||||||
md5_append(pms, data, 8);
|
|
||||||
for (i = 0; i < 16; ++i)
|
|
||||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
L. Peter Deutsch
|
|
||||||
ghost@aladdin.com
|
|
||||||
|
|
||||||
*/
|
|
||||||
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
|
|
||||||
/*
|
|
||||||
Independent implementation of MD5 (RFC 1321).
|
|
||||||
|
|
||||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
|
||||||
text is available at
|
|
||||||
http://www.ietf.org/rfc/rfc1321.txt
|
|
||||||
The code is derived from the text of the RFC, including the test suite
|
|
||||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
|
||||||
any code or documentation that is identified in the RFC as being
|
|
||||||
copyrighted.
|
|
||||||
|
|
||||||
The original and principal author of md5.h is L. Peter Deutsch
|
|
||||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
|
||||||
that follows (in reverse chronological order):
|
|
||||||
|
|
||||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
|
||||||
references to Ghostscript; clarified derivation from RFC 1321;
|
|
||||||
now handles byte order either statically or dynamically.
|
|
||||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
|
||||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
|
||||||
added conditionalization for C++ compilation from Martin
|
|
||||||
Purschke <purschke@bnl.gov>.
|
|
||||||
1999-05-03 lpd Original version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef md5_INCLUDED
|
|
||||||
# define md5_INCLUDED
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This package supports both compile-time and run-time determination of CPU
|
|
||||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
|
||||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
|
||||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
|
||||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
|
||||||
* run on either big- or little-endian CPUs, but will run slightly less
|
|
||||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
|
||||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
|
||||||
|
|
||||||
/* Define the state of the MD5 Algorithm. */
|
|
||||||
typedef struct md5_state_s {
|
|
||||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
|
||||||
md5_word_t abcd[4]; /* digest buffer */
|
|
||||||
md5_byte_t buf[64]; /* accumulate block */
|
|
||||||
} md5_state_t;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initialize the algorithm. */
|
|
||||||
void md5_init(md5_state_t *pms);
|
|
||||||
|
|
||||||
/* Append a string to the message. */
|
|
||||||
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
|
||||||
|
|
||||||
/* Finish the message and return the digest. */
|
|
||||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* end extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* md5_INCLUDED */
|
|
|
@ -1,36 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
case $2 in
|
|
||||||
link)
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
SunOS | solaris)
|
|
||||||
echo '-lsocket -lnsl';
|
|
||||||
;;
|
|
||||||
BeOS)
|
|
||||||
echo '-lsocket -lbind -lbsd';
|
|
||||||
;;
|
|
||||||
Haiku)
|
|
||||||
echo '-lnetwork';
|
|
||||||
;;
|
|
||||||
windows32)
|
|
||||||
echo '-lws2_32 -liphlpapi';
|
|
||||||
;;
|
|
||||||
Linux)
|
|
||||||
[ -e /usr/include/selinux/selinux.h ] && echo '-lselinux';
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
cflags)
|
|
||||||
case $1 in
|
|
||||||
BeOS)
|
|
||||||
echo '-Dsocklen_t=int';
|
|
||||||
;;
|
|
||||||
Linux)
|
|
||||||
[ -e /usr/include/selinux/selinux.h ] && echo '-DHAVE_SETCON';
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
|
@ -1,275 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static int
|
|
||||||
readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
|
|
||||||
{
|
|
||||||
char *dummy;
|
|
||||||
char *s;
|
|
||||||
char *d;
|
|
||||||
int len;
|
|
||||||
int offset;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if (loop <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
s = *src;
|
|
||||||
d = dst;
|
|
||||||
while(*s && len < length - 2) {
|
|
||||||
c = *s++;
|
|
||||||
|
|
||||||
/* is this a compressed label? */
|
|
||||||
if((c & 0xc0) == 0xc0) {
|
|
||||||
offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
|
|
||||||
if (offset > packetlen) {
|
|
||||||
if (len == 0) {
|
|
||||||
/* Bad jump first in packet */
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
/* Bad jump after some data */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dummy = packet + offset;
|
|
||||||
len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(c && len < length - 1) {
|
|
||||||
*d++ = *s++;
|
|
||||||
len++;
|
|
||||||
|
|
||||||
c--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len >= length - 1) {
|
|
||||||
break; /* We used up all space */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*s != 0) {
|
|
||||||
*d++ = '.';
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dst[len++] = '\0';
|
|
||||||
|
|
||||||
end:
|
|
||||||
(*src) = s+1;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
readname(char *packet, int packetlen, char **src, char *dst, size_t length)
|
|
||||||
{
|
|
||||||
return readname_loop(packet, packetlen, src, dst, length, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
readshort(char *packet, char **src, short *dst)
|
|
||||||
{
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
p = (unsigned char *) *src;
|
|
||||||
*dst = (p[0] << 8) | p[1];
|
|
||||||
|
|
||||||
(*src) += sizeof(short);
|
|
||||||
return sizeof(short);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
readlong(char *packet, char **src, uint32_t *dst)
|
|
||||||
{
|
|
||||||
/* A long as described in dns protocol is always 32 bits */
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
p = (unsigned char *) *src;
|
|
||||||
|
|
||||||
*dst = ((uint32_t)p[0] << 24)
|
|
||||||
| ((uint32_t)p[1] << 16)
|
|
||||||
| ((uint32_t)p[2] << 8)
|
|
||||||
| ((uint32_t)p[3]);
|
|
||||||
|
|
||||||
(*src) += sizeof(uint32_t);
|
|
||||||
return sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
readdata(char *packet, char **src, char *dst, size_t len)
|
|
||||||
{
|
|
||||||
if (len < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memcpy(dst, *src, len);
|
|
||||||
|
|
||||||
(*src) += len;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
readtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain)
|
|
||||||
{
|
|
||||||
unsigned char *uc;
|
|
||||||
int tocopy;
|
|
||||||
int dstused = 0;
|
|
||||||
|
|
||||||
while (srcremain > 0)
|
|
||||||
{
|
|
||||||
uc = (unsigned char*) (*src);
|
|
||||||
tocopy = *uc;
|
|
||||||
(*src)++;
|
|
||||||
srcremain--;
|
|
||||||
|
|
||||||
if (tocopy > srcremain)
|
|
||||||
return 0; /* illegal, better have nothing */
|
|
||||||
if (tocopy > dstremain)
|
|
||||||
return 0; /* doesn't fit, better have nothing */
|
|
||||||
|
|
||||||
memcpy(dst, *src, tocopy);
|
|
||||||
dst += tocopy;
|
|
||||||
(*src) += tocopy;
|
|
||||||
srcremain -= tocopy;
|
|
||||||
dstremain -= tocopy;
|
|
||||||
dstused += tocopy;
|
|
||||||
}
|
|
||||||
return dstused;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putname(char **buf, size_t buflen, const char *host)
|
|
||||||
{
|
|
||||||
char *word;
|
|
||||||
int left;
|
|
||||||
char *h;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
h = strdup(host);
|
|
||||||
left = buflen;
|
|
||||||
p = *buf;
|
|
||||||
|
|
||||||
word = strtok(h, ".");
|
|
||||||
while(word) {
|
|
||||||
if (strlen(word) > 63 || strlen(word) > left) {
|
|
||||||
free(h);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
left -= (strlen(word) + 1);
|
|
||||||
*p++ = (char)strlen(word);
|
|
||||||
memcpy(p, word, strlen(word));
|
|
||||||
p += strlen(word);
|
|
||||||
|
|
||||||
word = strtok(NULL, ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = 0;
|
|
||||||
|
|
||||||
free(h);
|
|
||||||
|
|
||||||
*buf = p;
|
|
||||||
return buflen - left;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putbyte(char **dst, unsigned char value)
|
|
||||||
{
|
|
||||||
**dst = value;
|
|
||||||
(*dst)++;
|
|
||||||
|
|
||||||
return sizeof(char);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putshort(char **dst, unsigned short value)
|
|
||||||
{
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
p = (unsigned char *) *dst;
|
|
||||||
|
|
||||||
*p++ = (value >> 8);
|
|
||||||
*p++ = value;
|
|
||||||
|
|
||||||
(*dst) = (char *) p;
|
|
||||||
return sizeof(short);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putlong(char **dst, uint32_t value)
|
|
||||||
{
|
|
||||||
/* A long as described in dns protocol is always 32 bits */
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
p = (unsigned char *) *dst;
|
|
||||||
|
|
||||||
*p++ = (value >> 24);
|
|
||||||
*p++ = (value >> 16);
|
|
||||||
*p++ = (value >> 8);
|
|
||||||
*p++ = (value);
|
|
||||||
|
|
||||||
(*dst) = (char *) p;
|
|
||||||
return sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putdata(char **dst, char *data, size_t len)
|
|
||||||
{
|
|
||||||
if (len < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memcpy(*dst, data, len);
|
|
||||||
|
|
||||||
(*dst) += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
puttxtbin(char **buf, size_t bufremain, char *from, size_t fromremain)
|
|
||||||
{
|
|
||||||
unsigned char uc;
|
|
||||||
unsigned char *ucp = &uc;
|
|
||||||
char *cp = (char *) ucp;
|
|
||||||
int tocopy;
|
|
||||||
int bufused = 0;
|
|
||||||
|
|
||||||
while (fromremain > 0)
|
|
||||||
{
|
|
||||||
tocopy = fromremain;
|
|
||||||
if (tocopy > 252)
|
|
||||||
tocopy = 252; /* allow off-by-1s in caches etc */
|
|
||||||
if (tocopy + 1 > bufremain)
|
|
||||||
return -1; /* doesn't fit, better have nothing */
|
|
||||||
|
|
||||||
uc = tocopy;
|
|
||||||
**buf = *cp;
|
|
||||||
(*buf)++;
|
|
||||||
bufremain--;
|
|
||||||
bufused++;
|
|
||||||
|
|
||||||
memcpy(*buf, from, tocopy);
|
|
||||||
(*buf) += tocopy;
|
|
||||||
from += tocopy;
|
|
||||||
bufremain -= tocopy;
|
|
||||||
fromremain -= tocopy;
|
|
||||||
bufused += tocopy;
|
|
||||||
}
|
|
||||||
return bufused;
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 _READ_H_
|
|
||||||
#define _READ_H_
|
|
||||||
|
|
||||||
int readname(char *, int, char **, char *, size_t);
|
|
||||||
int readshort(char *, char **, short *);
|
|
||||||
int readlong(char *, char **, uint32_t *);
|
|
||||||
int readdata(char *, char **, char *, size_t);
|
|
||||||
int readtxtbin(char *, char **, size_t, char *, size_t);
|
|
||||||
|
|
||||||
int putname(char **, size_t, const char *);
|
|
||||||
int putbyte(char **, unsigned char);
|
|
||||||
int putshort(char **, unsigned short);
|
|
||||||
int putlong(char **, uint32_t);
|
|
||||||
int putdata(char **, char *, size_t);
|
|
||||||
int puttxtbin(char **, size_t, char *, size_t);
|
|
||||||
|
|
||||||
#endif
|
|
541
iodine/src/tun.c
541
iodine/src/tun.c
|
@ -1,541 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <winioctl.h>
|
|
||||||
#include "windows.h"
|
|
||||||
|
|
||||||
HANDLE dev_handle;
|
|
||||||
struct tun_data data;
|
|
||||||
|
|
||||||
static void get_name(char *ifname, int namelen, char *dev_name);
|
|
||||||
|
|
||||||
#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
|
||||||
#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, METHOD_BUFFERED)
|
|
||||||
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
|
|
||||||
|
|
||||||
#define TAP_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
|
||||||
#define NETWORK_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
|
||||||
#define TAP_DEVICE_SPACE "\\\\.\\Global\\"
|
|
||||||
#define TAP_VERSION_ID_0801 "tap0801"
|
|
||||||
#define TAP_VERSION_ID_0901 "tap0901"
|
|
||||||
#define KEY_COMPONENT_ID "ComponentId"
|
|
||||||
#define NET_CFG_INST_ID "NetCfgInstanceId"
|
|
||||||
#else
|
|
||||||
#include <err.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#define TUN_MAX_TRY 50
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "tun.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
char if_name[250];
|
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
#ifdef LINUX
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <linux/if_tun.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
open_tun(const char *tun_device)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int tun_fd;
|
|
||||||
struct ifreq ifreq;
|
|
||||||
char *tunnel = "/dev/net/tun";
|
|
||||||
|
|
||||||
if ((tun_fd = open(tunnel, O_RDWR)) < 0) {
|
|
||||||
warn("open_tun: %s: %s", tunnel, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ifreq, 0, sizeof(ifreq));
|
|
||||||
|
|
||||||
ifreq.ifr_flags = IFF_TUN;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
|
|
||||||
return tun_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno != EBUSY) {
|
|
||||||
warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < TUN_MAX_TRY; i++) {
|
|
||||||
snprintf(ifreq.ifr_name, IFNAMSIZ, "dns%d", i);
|
|
||||||
|
|
||||||
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) {
|
|
||||||
fprintf(stderr, "Opened %s\n", ifreq.ifr_name);
|
|
||||||
snprintf(if_name, sizeof(if_name), "dns%d", i);
|
|
||||||
return tun_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno != EBUSY) {
|
|
||||||
warn("open_tun: ioctl[TUNSETIFF]: %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
warn("open_tun: Couldn't set interface name");
|
|
||||||
}
|
|
||||||
warn("error when opening tun");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* BSD */
|
|
||||||
|
|
||||||
int
|
|
||||||
open_tun(const char *tun_device)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int tun_fd;
|
|
||||||
char tun_name[50];
|
|
||||||
|
|
||||||
if (tun_device != NULL) {
|
|
||||||
snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device);
|
|
||||||
strncpy(if_name, tun_device, sizeof(if_name));
|
|
||||||
if_name[sizeof(if_name)-1] = '\0';
|
|
||||||
|
|
||||||
if ((tun_fd = open(tun_name, O_RDWR)) < 0) {
|
|
||||||
warn("open_tun: %s: %s", tun_name, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Opened %s\n", tun_name);
|
|
||||||
return tun_fd;
|
|
||||||
} else {
|
|
||||||
for (i = 0; i < TUN_MAX_TRY; i++) {
|
|
||||||
snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i);
|
|
||||||
|
|
||||||
if ((tun_fd = open(tun_name, O_RDWR)) >= 0) {
|
|
||||||
fprintf(stderr, "Opened %s\n", tun_name);
|
|
||||||
snprintf(if_name, sizeof(if_name), "tun%d", i);
|
|
||||||
return tun_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno == ENOENT)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
warn("open_tun: Failed to open tunneling device");
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !LINUX */
|
|
||||||
#else /* WINDOWS32 */
|
|
||||||
static void
|
|
||||||
get_device(char *device, int device_len, const char *wanted_dev)
|
|
||||||
{
|
|
||||||
LONG status;
|
|
||||||
HKEY adapter_key;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TAP_ADAPTER_KEY, 0, KEY_READ, &adapter_key);
|
|
||||||
|
|
||||||
if (status != ERROR_SUCCESS) {
|
|
||||||
warnx("Error opening registry key " TAP_ADAPTER_KEY );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (TRUE) {
|
|
||||||
char name[256];
|
|
||||||
char unit[256];
|
|
||||||
char component[256];
|
|
||||||
|
|
||||||
char cid_string[256] = KEY_COMPONENT_ID;
|
|
||||||
HKEY device_key;
|
|
||||||
DWORD datatype;
|
|
||||||
DWORD len;
|
|
||||||
|
|
||||||
/* Iterate through all adapter of this kind */
|
|
||||||
len = sizeof(name);
|
|
||||||
status = RegEnumKeyEx(adapter_key, index, name, &len, NULL, NULL, NULL, NULL);
|
|
||||||
if (status == ERROR_NO_MORE_ITEMS) {
|
|
||||||
break;
|
|
||||||
} else if (status != ERROR_SUCCESS) {
|
|
||||||
warnx("Error enumerating subkeys of registry key " TAP_ADAPTER_KEY );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(unit, sizeof(unit), TAP_ADAPTER_KEY "\\%s", name);
|
|
||||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit, 0, KEY_READ, &device_key);
|
|
||||||
if (status != ERROR_SUCCESS) {
|
|
||||||
warnx("Error opening registry key %s", unit);
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check component id */
|
|
||||||
len = sizeof(component);
|
|
||||||
status = RegQueryValueEx(device_key, cid_string, NULL, &datatype, (LPBYTE)component, &len);
|
|
||||||
if (status != ERROR_SUCCESS || datatype != REG_SZ) {
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
if (strncmp(TAP_VERSION_ID_0801, component, strlen(TAP_VERSION_ID_0801)) == 0 ||
|
|
||||||
strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) {
|
|
||||||
/* We found a TAP32 device, get its NetCfgInstanceId */
|
|
||||||
char iid_string[256] = NET_CFG_INST_ID;
|
|
||||||
|
|
||||||
status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len);
|
|
||||||
if (status != ERROR_SUCCESS || datatype != REG_SZ) {
|
|
||||||
warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string);
|
|
||||||
} else {
|
|
||||||
/* Done getting GUID of TAP device,
|
|
||||||
* now check if the name is the requested one */
|
|
||||||
if (wanted_dev) {
|
|
||||||
char name[250];
|
|
||||||
get_name(name, sizeof(name), device);
|
|
||||||
if (strncmp(name, wanted_dev, strlen(wanted_dev))) {
|
|
||||||
/* Skip if name mismatch */
|
|
||||||
goto next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Get the if name */
|
|
||||||
get_name(if_name, sizeof(if_name), device);
|
|
||||||
RegCloseKey(device_key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next:
|
|
||||||
RegCloseKey(device_key);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
RegCloseKey(adapter_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_name(char *ifname, int namelen, char *dev_name)
|
|
||||||
{
|
|
||||||
char path[256];
|
|
||||||
char name_str[256] = "Name";
|
|
||||||
LONG status;
|
|
||||||
HKEY conn_key;
|
|
||||||
DWORD len;
|
|
||||||
DWORD datatype;
|
|
||||||
|
|
||||||
memset(ifname, 0, namelen);
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), NETWORK_KEY "\\%s\\Connection", dev_name);
|
|
||||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &conn_key);
|
|
||||||
if (status != ERROR_SUCCESS) {
|
|
||||||
fprintf(stderr, "Could not look up name of interface %s: error opening key\n", dev_name);
|
|
||||||
RegCloseKey(conn_key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
len = namelen;
|
|
||||||
status = RegQueryValueEx(conn_key, name_str, NULL, &datatype, (LPBYTE)ifname, &len);
|
|
||||||
if (status != ERROR_SUCCESS || datatype != REG_SZ) {
|
|
||||||
fprintf(stderr, "Could not look up name of interface %s: error reading value\n", dev_name);
|
|
||||||
RegCloseKey(conn_key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RegCloseKey(conn_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD WINAPI tun_reader(LPVOID arg)
|
|
||||||
{
|
|
||||||
struct tun_data *tun = arg;
|
|
||||||
char buf[64*1024];
|
|
||||||
int len;
|
|
||||||
int res;
|
|
||||||
OVERLAPPED olpd;
|
|
||||||
int sock;
|
|
||||||
|
|
||||||
sock = open_dns(0, INADDR_ANY);
|
|
||||||
|
|
||||||
olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
while(TRUE) {
|
|
||||||
olpd.Offset = 0;
|
|
||||||
olpd.OffsetHigh = 0;
|
|
||||||
res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
|
|
||||||
if (!res) {
|
|
||||||
WaitForSingleObject(olpd.hEvent, INFINITE);
|
|
||||||
res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
|
|
||||||
res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr),
|
|
||||||
sizeof(struct sockaddr_in));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
open_tun(const char *tun_device)
|
|
||||||
{
|
|
||||||
char adapter[256];
|
|
||||||
char tapfile[512];
|
|
||||||
int tunfd;
|
|
||||||
in_addr_t local;
|
|
||||||
|
|
||||||
memset(adapter, 0, sizeof(adapter));
|
|
||||||
memset(if_name, 0, sizeof(if_name));
|
|
||||||
get_device(adapter, sizeof(adapter), tun_device);
|
|
||||||
|
|
||||||
if (strlen(adapter) == 0 || strlen(if_name) == 0) {
|
|
||||||
if (tun_device) {
|
|
||||||
warnx("No TAP adapters found. Try without -d.");
|
|
||||||
} else {
|
|
||||||
warnx("No TAP adapters found. Version 0801 and 0901 are supported.");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "Opening device %s\n", if_name);
|
|
||||||
snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
|
|
||||||
dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
|
|
||||||
if (dev_handle == INVALID_HANDLE_VALUE) {
|
|
||||||
warnx("Could not open device!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use a UDP connection to forward packets from tun,
|
|
||||||
* so we can still use select() in main code.
|
|
||||||
* A thread does blocking reads on tun device and
|
|
||||||
* sends data as udp to this socket */
|
|
||||||
|
|
||||||
local = htonl(0x7f000001); /* 127.0.0.1 */
|
|
||||||
tunfd = open_dns(55353, local);
|
|
||||||
|
|
||||||
data.tun = dev_handle;
|
|
||||||
memset(&(data.addr), 0, sizeof(data.addr));
|
|
||||||
data.addr.sin_family = AF_INET;
|
|
||||||
data.addr.sin_port = htons(55353);
|
|
||||||
data.addr.sin_addr.s_addr = local;
|
|
||||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
|
|
||||||
|
|
||||||
return tunfd;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
close_tun(int tun_fd)
|
|
||||||
{
|
|
||||||
if (tun_fd >= 0)
|
|
||||||
close(tun_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
write_tun(int tun_fd, char *data, size_t len)
|
|
||||||
{
|
|
||||||
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
|
|
||||||
data += 4;
|
|
||||||
len -= 4;
|
|
||||||
#else /* !FREEBSD/DARWIN */
|
|
||||||
#ifdef LINUX
|
|
||||||
data[0] = 0x00;
|
|
||||||
data[1] = 0x00;
|
|
||||||
data[2] = 0x08;
|
|
||||||
data[3] = 0x00;
|
|
||||||
#else /* OPENBSD */
|
|
||||||
data[0] = 0x00;
|
|
||||||
data[1] = 0x00;
|
|
||||||
data[2] = 0x00;
|
|
||||||
data[3] = 0x02;
|
|
||||||
#endif /* !LINUX */
|
|
||||||
#endif /* FREEBSD */
|
|
||||||
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
if (write(tun_fd, data, len) != len) {
|
|
||||||
warn("write_tun");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#else /* WINDOWS32 */
|
|
||||||
{
|
|
||||||
DWORD written;
|
|
||||||
DWORD res;
|
|
||||||
OVERLAPPED olpd;
|
|
||||||
|
|
||||||
olpd.Offset = 0;
|
|
||||||
olpd.OffsetHigh = 0;
|
|
||||||
olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
res = WriteFile(dev_handle, data, len, &written, &olpd);
|
|
||||||
if (!res && GetLastError() == ERROR_IO_PENDING) {
|
|
||||||
WaitForSingleObject(olpd.hEvent, INFINITE);
|
|
||||||
res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE);
|
|
||||||
if (written != len) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
read_tun(int tun_fd, char *buf, size_t len)
|
|
||||||
{
|
|
||||||
#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32)
|
|
||||||
/* FreeBSD/Darwin/NetBSD has no header */
|
|
||||||
int bytes;
|
|
||||||
memset(buf, 0, 4);
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
/* Windows needs recv() since it is local UDP socket */
|
|
||||||
bytes = recv(tun_fd, buf + 4, len - 4, 0);
|
|
||||||
#else
|
|
||||||
/* The other need read() because fd is not a socket */
|
|
||||||
bytes = read(tun_fd, buf + 4, len - 4);
|
|
||||||
#endif /*WINDOWS32*/
|
|
||||||
if (bytes < 0) {
|
|
||||||
return bytes;
|
|
||||||
} else {
|
|
||||||
return bytes + 4;
|
|
||||||
}
|
|
||||||
#else /* !FREEBSD */
|
|
||||||
return read(tun_fd, buf, len);
|
|
||||||
#endif /* !FREEBSD */
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
tun_setip(const char *ip, const char *remoteip, int netbits)
|
|
||||||
{
|
|
||||||
char cmdline[512];
|
|
||||||
int netmask;
|
|
||||||
struct in_addr net;
|
|
||||||
int i;
|
|
||||||
#ifndef LINUX
|
|
||||||
int r;
|
|
||||||
#endif
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
DWORD status;
|
|
||||||
DWORD ipdata[3];
|
|
||||||
struct in_addr addr;
|
|
||||||
DWORD len;
|
|
||||||
#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) {
|
|
||||||
fprintf(stderr, "Invalid IP: %s!\n", ip);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
snprintf(cmdline, sizeof(cmdline),
|
|
||||||
"/sbin/ifconfig %s %s %s netmask %s",
|
|
||||||
if_name,
|
|
||||||
ip,
|
|
||||||
#ifdef FREEBSD
|
|
||||||
remoteip, /* FreeBSD wants other IP as second IP */
|
|
||||||
#else
|
|
||||||
ip,
|
|
||||||
#endif
|
|
||||||
inet_ntoa(net));
|
|
||||||
|
|
||||||
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
|
|
||||||
#ifndef LINUX
|
|
||||||
r = system(cmdline);
|
|
||||||
if(r != 0) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
snprintf(cmdline, sizeof(cmdline),
|
|
||||||
"/sbin/route add %s/%d %s",
|
|
||||||
ip, netbits, ip);
|
|
||||||
}
|
|
||||||
fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip);
|
|
||||||
#endif
|
|
||||||
return system(cmdline);
|
|
||||||
#else /* WINDOWS32 */
|
|
||||||
|
|
||||||
/* Set device as connected */
|
|
||||||
fprintf(stderr, "Enabling interface '%s'\n", if_name);
|
|
||||||
status = 1;
|
|
||||||
r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status,
|
|
||||||
sizeof(status), &status, sizeof(status), &len, NULL);
|
|
||||||
if (!r) {
|
|
||||||
fprintf(stderr, "Failed to enable interface\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inet_aton(ip, &addr)) {
|
|
||||||
ipdata[0] = (DWORD) addr.s_addr; /* local ip addr */
|
|
||||||
ipdata[1] = net.s_addr & ipdata[0]; /* network addr */
|
|
||||||
ipdata[2] = (DWORD) net.s_addr; /* netmask */
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell ip/networkaddr/netmask to device for arp use */
|
|
||||||
r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata,
|
|
||||||
sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL);
|
|
||||||
if (!r) {
|
|
||||||
fprintf(stderr, "Failed to set interface in TUN mode\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* use netsh to set ip address */
|
|
||||||
fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip);
|
|
||||||
snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s",
|
|
||||||
if_name, ip, inet_ntoa(net));
|
|
||||||
return system(cmdline);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
tun_setmtu(const unsigned mtu)
|
|
||||||
{
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
char cmdline[512];
|
|
||||||
|
|
||||||
if (mtu > 200 && mtu <= 1500) {
|
|
||||||
snprintf(cmdline, sizeof(cmdline),
|
|
||||||
"/sbin/ifconfig %s mtu %u",
|
|
||||||
if_name,
|
|
||||||
mtu);
|
|
||||||
|
|
||||||
fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu);
|
|
||||||
return system(cmdline);
|
|
||||||
} else {
|
|
||||||
warn("MTU out of range: %u\n", mtu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
#else /* WINDOWS32 */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 _TUN_H_
|
|
||||||
#define _TUN_H_
|
|
||||||
|
|
||||||
int open_tun(const char *);
|
|
||||||
void close_tun(int);
|
|
||||||
int write_tun(int, char *, size_t);
|
|
||||||
ssize_t read_tun(int, char *, size_t);
|
|
||||||
int tun_setip(const char *, const char *, int);
|
|
||||||
int tun_setmtu(const unsigned);
|
|
||||||
|
|
||||||
#endif /* _TUN_H_ */
|
|
|
@ -1,204 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
|
||||||
#include <winsock2.h>
|
|
||||||
#else
|
|
||||||
#include <netdb.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
struct user users[USERS];
|
|
||||||
|
|
||||||
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 + 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].active = 0;
|
|
||||||
/* Rest is reset on login ('V' packet) */
|
|
||||||
}
|
|
||||||
|
|
||||||
return created_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
users_get_first_ip()
|
|
||||||
{
|
|
||||||
struct in_addr ip;
|
|
||||||
ip.s_addr = users[0].tun_ip;
|
|
||||||
return inet_ntoa(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
users_waiting_on_reply()
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
for (i = 0; i < USERS; i++) {
|
|
||||||
if (users[i].active && !users[i].disabled &&
|
|
||||||
users[i].last_pkt + 60 > time(NULL) &&
|
|
||||||
users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) {
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
find_user_by_ip(uint32_t ip)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = -1;
|
|
||||||
for (i = 0; i < USERS; i++) {
|
|
||||||
if (users[i].active && !users[i].disabled &&
|
|
||||||
users[i].last_pkt + 60 > time(NULL) &&
|
|
||||||
ip == users[i].tun_ip) {
|
|
||||||
ret = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
all_users_waiting_to_send()
|
|
||||||
/* If this returns true, then reading from tun device is blocked.
|
|
||||||
So only return true when all clients have at least one packet in
|
|
||||||
the outpacket-queue, so that sending back-to-back is possible
|
|
||||||
without going through another select loop.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
time_t now;
|
|
||||||
int ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
now = time(NULL);
|
|
||||||
for (i = 0; i < USERS; i++) {
|
|
||||||
if (users[i].active && !users[i].disabled &&
|
|
||||||
users[i].last_pkt + 60 > now &&
|
|
||||||
((users[i].conn == CONN_RAW_UDP) ||
|
|
||||||
((users[i].conn == CONN_DNS_NULL)
|
|
||||||
#ifdef OUTPACKETQ_LEN
|
|
||||||
&& users[i].outpacketq_filled < 1
|
|
||||||
#else
|
|
||||||
&& users[i].outpacket.len == 0
|
|
||||||
#endif
|
|
||||||
))) {
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
find_available_user()
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
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)) && !users[i].disabled) {
|
|
||||||
users[i].active = 1;
|
|
||||||
users[i].last_pkt = time(NULL);
|
|
||||||
users[i].fragsize = 4096;
|
|
||||||
users[i].conn = CONN_DNS_NULL;
|
|
||||||
ret = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
user_switch_codec(int userid, struct encoder *enc)
|
|
||||||
{
|
|
||||||
if (userid < 0 || userid >= USERS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
users[userid].encoder = enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
user_set_conn_type(int userid, enum connection c)
|
|
||||||
{
|
|
||||||
if (userid < 0 || userid >= USERS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (c < 0 || c >= CONN_MAX)
|
|
||||||
return;
|
|
||||||
|
|
||||||
users[userid].conn = c;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __USER_H__
|
|
||||||
#define __USER_H__
|
|
||||||
|
|
||||||
#define USERS 16
|
|
||||||
|
|
||||||
#define OUTPACKETQ_LEN 4 /* Note: 16 users * 1 packet = 1MB */
|
|
||||||
/* Undefine to have no queue for packets coming in from tun device, which may
|
|
||||||
lead to massive dropping in multi-user situations with high traffic. */
|
|
||||||
|
|
||||||
#define DNSCACHE_LEN 4
|
|
||||||
/* Undefine to disable. Should be less than 18; also see comments in iodined.c */
|
|
||||||
|
|
||||||
|
|
||||||
#define QMEMPING_LEN 30
|
|
||||||
/* Max advisable: 64k/2 = 32000. Total mem usage: QMEMPING_LEN * USERS * 6 bytes */
|
|
||||||
|
|
||||||
#define QMEMDATA_LEN 15
|
|
||||||
/* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */
|
|
||||||
|
|
||||||
struct user {
|
|
||||||
char id;
|
|
||||||
int active;
|
|
||||||
int disabled;
|
|
||||||
time_t last_pkt;
|
|
||||||
int seed;
|
|
||||||
in_addr_t tun_ip;
|
|
||||||
struct in_addr host;
|
|
||||||
struct query q;
|
|
||||||
struct query q_sendrealsoon;
|
|
||||||
int q_sendrealsoon_new;
|
|
||||||
struct packet inpacket;
|
|
||||||
struct packet outpacket;
|
|
||||||
int outfragresent;
|
|
||||||
struct encoder *encoder;
|
|
||||||
char downenc;
|
|
||||||
int out_acked_seqno;
|
|
||||||
int out_acked_fragment;
|
|
||||||
int fragsize;
|
|
||||||
enum connection conn;
|
|
||||||
int lazy;
|
|
||||||
unsigned char qmemping_cmc[QMEMPING_LEN * 4];
|
|
||||||
unsigned short qmemping_type[QMEMPING_LEN];
|
|
||||||
int qmemping_lastfilled;
|
|
||||||
unsigned char qmemdata_cmc[QMEMDATA_LEN * 4];
|
|
||||||
unsigned short qmemdata_type[QMEMDATA_LEN];
|
|
||||||
int qmemdata_lastfilled;
|
|
||||||
#ifdef OUTPACKETQ_LEN
|
|
||||||
struct packet outpacketq[OUTPACKETQ_LEN];
|
|
||||||
int outpacketq_nexttouse;
|
|
||||||
int outpacketq_filled;
|
|
||||||
#endif
|
|
||||||
#ifdef DNSCACHE_LEN
|
|
||||||
struct query dnscache_q[DNSCACHE_LEN];
|
|
||||||
char dnscache_answer[DNSCACHE_LEN][4096];
|
|
||||||
int dnscache_answerlen[DNSCACHE_LEN];
|
|
||||||
int dnscache_lastfilled;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct user users[USERS];
|
|
||||||
|
|
||||||
int init_users(in_addr_t, int);
|
|
||||||
const char* users_get_first_ip();
|
|
||||||
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);
|
|
||||||
void user_set_conn_type(int userid, enum connection c);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <stdio.h>
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
char *
|
|
||||||
get_resolvconf_addr()
|
|
||||||
{
|
|
||||||
static char addr[16];
|
|
||||||
char *rv;
|
|
||||||
#ifndef WINDOWS32
|
|
||||||
char buf[80];
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
rv = NULL;
|
|
||||||
|
|
||||||
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
|
|
||||||
err(1, "/etc/resolv.conf");
|
|
||||||
|
|
||||||
while (feof(fp) == 0) {
|
|
||||||
fgets(buf, sizeof(buf), fp);
|
|
||||||
|
|
||||||
if (sscanf(buf, "nameserver %15s", addr) == 1) {
|
|
||||||
rv = addr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
#else /* !WINDOWS32 */
|
|
||||||
FIXED_INFO *fixed_info;
|
|
||||||
ULONG buflen;
|
|
||||||
DWORD ret;
|
|
||||||
|
|
||||||
rv = NULL;
|
|
||||||
fixed_info = malloc(sizeof(FIXED_INFO));
|
|
||||||
buflen = sizeof(FIXED_INFO);
|
|
||||||
|
|
||||||
if (GetNetworkParams(fixed_info, &buflen) == ERROR_BUFFER_OVERFLOW) {
|
|
||||||
/* official ugly api workaround */
|
|
||||||
free(fixed_info);
|
|
||||||
fixed_info = malloc(buflen);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GetNetworkParams(fixed_info, &buflen);
|
|
||||||
if (ret == NO_ERROR) {
|
|
||||||
strncpy(addr, fixed_info->DnsServerList.IpAddress.String, sizeof(addr));
|
|
||||||
addr[15] = 0;
|
|
||||||
rv = addr;
|
|
||||||
}
|
|
||||||
free(fixed_info);
|
|
||||||
#endif
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
#ifndef __UTIL_H__
|
|
||||||
#define __UTIL_H__
|
|
||||||
|
|
||||||
char *get_resolvconf_addr();
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 _VERSION_H_
|
|
||||||
#define _VERSION_H_
|
|
||||||
|
|
||||||
/* This is the version of the network protocol
|
|
||||||
It is usually equal to the latest iodine version number */
|
|
||||||
#define VERSION 0x00000502
|
|
||||||
|
|
||||||
#endif /* _VERSION_H_ */
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __FIX_WINDOWS_H__
|
|
||||||
#define __FIX_WINDOWS_H__
|
|
||||||
|
|
||||||
typedef unsigned int in_addr_t;
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <windns.h>
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <iphlpapi.h>
|
|
||||||
|
|
||||||
/* Missing from the mingw headers */
|
|
||||||
#ifndef DNS_TYPE_SRV
|
|
||||||
# define DNS_TYPE_SRV 33
|
|
||||||
#endif
|
|
||||||
#ifndef DNS_TYPE_TXT
|
|
||||||
# define DNS_TYPE_TXT 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define T_A DNS_TYPE_A
|
|
||||||
#define T_NS DNS_TYPE_NS
|
|
||||||
#define T_NULL DNS_TYPE_NULL
|
|
||||||
#define T_CNAME DNS_TYPE_CNAME
|
|
||||||
#define T_MX DNS_TYPE_MX
|
|
||||||
#define T_TXT DNS_TYPE_TXT
|
|
||||||
#define T_SRV DNS_TYPE_SRV
|
|
||||||
|
|
||||||
#define C_IN 1
|
|
||||||
|
|
||||||
#define FORMERR 1
|
|
||||||
#define SERVFAIL 2
|
|
||||||
#define NXDOMAIN 3
|
|
||||||
#define NOTIMP 4
|
|
||||||
#define REFUSED 5
|
|
||||||
|
|
||||||
#define sleep(seconds) Sleep((seconds)*1000)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned id :16; /* query identification number */
|
|
||||||
/* fields in third byte */
|
|
||||||
unsigned rd :1; /* recursion desired */
|
|
||||||
unsigned tc :1; /* truncated message */
|
|
||||||
unsigned aa :1; /* authoritive answer */
|
|
||||||
unsigned opcode :4; /* purpose of message */
|
|
||||||
unsigned qr :1; /* response flag */
|
|
||||||
/* fields in fourth byte */
|
|
||||||
unsigned rcode :4; /* response code */
|
|
||||||
unsigned cd: 1; /* checking disabled by resolver */
|
|
||||||
unsigned ad: 1; /* authentic data from named */
|
|
||||||
unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
|
|
||||||
unsigned ra :1; /* recursion available */
|
|
||||||
/* remaining bytes */
|
|
||||||
unsigned qdcount :16; /* number of question entries */
|
|
||||||
unsigned ancount :16; /* number of answer entries */
|
|
||||||
unsigned nscount :16; /* number of authority entries */
|
|
||||||
unsigned arcount :16; /* number of resource entries */
|
|
||||||
} HEADER;
|
|
||||||
|
|
||||||
struct ip
|
|
||||||
{
|
|
||||||
unsigned int ip_hl:4; /* header length */
|
|
||||||
unsigned int ip_v:4; /* version */
|
|
||||||
u_char ip_tos; /* type of service */
|
|
||||||
u_short ip_len; /* total length */
|
|
||||||
u_short ip_id; /* identification */
|
|
||||||
u_short ip_off; /* fragment offset field */
|
|
||||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
|
||||||
#define IP_DF 0x4000 /* dont fragment flag */
|
|
||||||
#define IP_MF 0x2000 /* more fragments flag */
|
|
||||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
|
||||||
u_char ip_ttl; /* time to live */
|
|
||||||
u_char ip_p; /* protocol */
|
|
||||||
u_short ip_sum; /* checksum */
|
|
||||||
struct in_addr ip_src, ip_dst; /* source and dest address */
|
|
||||||
};
|
|
||||||
|
|
||||||
DWORD WINAPI tun_reader(LPVOID arg);
|
|
||||||
struct tun_data {
|
|
||||||
HANDLE tun;
|
|
||||||
int sock;
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,27 +0,0 @@
|
||||||
CC = gcc
|
|
||||||
TEST = test
|
|
||||||
OBJS = test.o base32.o base64.o read.o dns.o encoding.o login.o user.o fw_query.o
|
|
||||||
SRCOBJS = ../src/base32.o ../src/base64.o ../src/read.o ../src/dns.o ../src/encoding.o ../src/login.o ../src/md5.o ../src/user.o ../src/fw_query.o
|
|
||||||
|
|
||||||
OS = `uname | tr "a-z" "A-Z"`
|
|
||||||
|
|
||||||
CHECK_PATH = /usr/local
|
|
||||||
LDFLAGS = -L$(CHECK_PATH)/lib -lcheck `../src/osflags link`
|
|
||||||
CFLAGS = -g -Wall -D$(OS) -I../src -I$(CHECK_PATH)/include -pedantic `../src/osflags cflags`
|
|
||||||
|
|
||||||
all: $(TEST)
|
|
||||||
@LD_LIBRARY_PATH=${CHECK_PATH}/lib ./$(TEST)
|
|
||||||
|
|
||||||
$(TEST): $(OBJS) $(SRCOBJS)
|
|
||||||
@echo LD $(TEST)
|
|
||||||
@$(CC) -o $@ $(SRCOBJS) $(OBJS) $(LDFLAGS)
|
|
||||||
|
|
||||||
.c.o:
|
|
||||||
@echo CC $<
|
|
||||||
@$(CC) $(CFLAGS) -c $<
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@echo "Cleaning tests/"
|
|
||||||
@rm -f *~ *.core $(TEST) $(OBJS)
|
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "base32.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
#define TUPLES 5
|
|
||||||
|
|
||||||
static struct tuple
|
|
||||||
{
|
|
||||||
char *a;
|
|
||||||
char *b;
|
|
||||||
} testpairs[TUPLES] = {
|
|
||||||
{ "iodinetestingtesting", "nfxwi0lomv0gk21unfxgo3dfon0gs1th" },
|
|
||||||
{ "abc123", "mfrggmjsgm" },
|
|
||||||
{ "test", "orsxg3a" },
|
|
||||||
{ "tst", "orzxi" },
|
|
||||||
{ "", "" },
|
|
||||||
};
|
|
||||||
|
|
||||||
START_TEST(test_base32_encode)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char buf[4096];
|
|
||||||
struct encoder *b32;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b32 = get_base32_encoder();
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
val = b32->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
|
|
||||||
|
|
||||||
fail_unless(strcmp(buf, testpairs[_i].b) == 0,
|
|
||||||
"'%s' != '%s'", buf, testpairs[_i].b);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_base32_decode)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char buf[4096];
|
|
||||||
struct encoder *b32;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b32 = get_base32_encoder();
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
val = b32->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
|
|
||||||
|
|
||||||
fail_unless(buf != NULL, "buf == NULL");
|
|
||||||
fail_unless(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
|
|
||||||
|
|
||||||
START_TEST(test_base32_blksize)
|
|
||||||
{
|
|
||||||
size_t rawlen;
|
|
||||||
size_t enclen;
|
|
||||||
char *rawbuf;
|
|
||||||
char *encbuf;
|
|
||||||
struct encoder *b32;
|
|
||||||
int i;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b32 = get_base32_encoder();
|
|
||||||
|
|
||||||
rawlen = b32->blocksize_raw();
|
|
||||||
enclen = b32->blocksize_encoded();
|
|
||||||
|
|
||||||
rawbuf = malloc(rawlen + 16);
|
|
||||||
encbuf = malloc(enclen + 16);
|
|
||||||
|
|
||||||
for (i = 0; i < rawlen; i++) {
|
|
||||||
rawbuf[i] = 'A';
|
|
||||||
}
|
|
||||||
rawbuf[i] = 0;
|
|
||||||
|
|
||||||
val = b32->encode(encbuf, &enclen, rawbuf, rawlen);
|
|
||||||
|
|
||||||
fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
|
|
||||||
fail_unless(enclen == 5, "encoded %d bytes, not 5", enclen);
|
|
||||||
fail_unless(val == 8, "encoded string %s was length %d", encbuf, val);
|
|
||||||
|
|
||||||
memset(rawbuf, 0, rawlen + 16);
|
|
||||||
|
|
||||||
enclen = val;
|
|
||||||
val = b32->decode(rawbuf, &rawlen, encbuf, enclen);
|
|
||||||
|
|
||||||
fail_unless(rawlen == 5, "raw length was %d not 5", rawlen);
|
|
||||||
fail_unless(val == 5, "val was not 5 but %d", val);
|
|
||||||
for (i = 0; i < rawlen; i++) {
|
|
||||||
fail_unless(rawbuf[i] == 'A');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_base32_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Base32");
|
|
||||||
tcase_add_loop_test(tc, test_base32_encode, 0, TUPLES);
|
|
||||||
tcase_add_loop_test(tc, test_base32_decode, 0, TUPLES);
|
|
||||||
tcase_add_test(tc, test_base32_5to8_8to5);
|
|
||||||
tcase_add_test(tc, test_base32_blksize);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "base64.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
#define TUPLES 5
|
|
||||||
|
|
||||||
static struct tuple
|
|
||||||
{
|
|
||||||
char *a;
|
|
||||||
char *b;
|
|
||||||
} testpairs[TUPLES] = {
|
|
||||||
{ "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" },
|
|
||||||
{ "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"
|
|
||||||
"\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\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",
|
|
||||||
|
|
||||||
"+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"
|
|
||||||
"\xDF\x6D\x74\xCF\x2C\x70\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\xFF\xEF\x7C\xEF\xAE\x78\xDF\x6D\x74\xCF\x2C\x70"
|
|
||||||
"\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",
|
|
||||||
|
|
||||||
"+9876543210-ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcbapZ"
|
|
||||||
"776543210-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba+987654321"
|
|
||||||
"0-ZYXWVUTSRQfHKwfHGsHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
|
|
||||||
},
|
|
||||||
{ "", "" }
|
|
||||||
};
|
|
||||||
|
|
||||||
START_TEST(test_base64_encode)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char buf[4096];
|
|
||||||
struct encoder *b64;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b64 = get_base64_encoder();
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
val = b64->encode(buf, &len, testpairs[_i].a, strlen(testpairs[_i].a));
|
|
||||||
|
|
||||||
fail_unless(strcmp(buf, testpairs[_i].b) == 0,
|
|
||||||
"'%s' != '%s'", buf, testpairs[_i].b);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_base64_decode)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char buf[4096];
|
|
||||||
struct encoder *b64;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b64 = get_base64_encoder();
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
val = b64->decode(buf, &len, testpairs[_i].b, strlen(testpairs[_i].b));
|
|
||||||
|
|
||||||
fail_unless(buf != NULL, "buf == NULL");
|
|
||||||
fail_unless(strcmp(buf, testpairs[_i].a) == 0,
|
|
||||||
"'%s' != '%s'", buf, testpairs[_i].a);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_base64_blksize)
|
|
||||||
{
|
|
||||||
size_t rawlen;
|
|
||||||
size_t enclen;
|
|
||||||
char *rawbuf;
|
|
||||||
char *encbuf;
|
|
||||||
struct encoder *b64;
|
|
||||||
int i;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
b64 = get_base64_encoder();
|
|
||||||
|
|
||||||
rawlen = b64->blocksize_raw();
|
|
||||||
enclen = b64->blocksize_encoded();
|
|
||||||
|
|
||||||
rawbuf = malloc(rawlen + 16);
|
|
||||||
encbuf = malloc(enclen + 16);
|
|
||||||
|
|
||||||
for (i = 0; i < rawlen; i++) {
|
|
||||||
rawbuf[i] = 'A';
|
|
||||||
}
|
|
||||||
rawbuf[i] = 0;
|
|
||||||
|
|
||||||
val = b64->encode(encbuf, &enclen, rawbuf, rawlen);
|
|
||||||
|
|
||||||
fail_unless(rawlen == 3, "raw length was %d not 3", rawlen);
|
|
||||||
fail_unless(enclen == 3, "encoded %d bytes, not 3", enclen);
|
|
||||||
fail_unless(val == 4, "encoded string %s was length %d", encbuf, val);
|
|
||||||
|
|
||||||
memset(rawbuf, 0, rawlen + 16);
|
|
||||||
|
|
||||||
enclen = val;
|
|
||||||
val = b64->decode(rawbuf, &rawlen, encbuf, enclen);
|
|
||||||
|
|
||||||
fail_unless(rawlen == 3, "raw length was %d not 3", rawlen);
|
|
||||||
fail_unless(val == 3);
|
|
||||||
for (i = 0; i < rawlen; i++) {
|
|
||||||
fail_unless(rawbuf[i] == 'A');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_base64_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Base64");
|
|
||||||
tcase_add_loop_test(tc, test_base64_encode, 0, TUPLES);
|
|
||||||
tcase_add_loop_test(tc, test_base64_decode, 0, TUPLES);
|
|
||||||
tcase_add_test(tc, test_base64_blksize);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <arpa/nameser.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "dns.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "base32.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
static void dump_packet(char *, size_t);
|
|
||||||
|
|
||||||
static char query_packet[] =
|
|
||||||
"\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 answer_packet[] =
|
|
||||||
"\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 answer_packet_high_trans_id[] =
|
|
||||||
"\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)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
char resolv[512];
|
|
||||||
struct query q;
|
|
||||||
struct encoder *enc;
|
|
||||||
char *d;
|
|
||||||
size_t len;
|
|
||||||
size_t enclen;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
enclen = sizeof(resolv);
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
memset(&resolv, 0, sizeof(resolv));
|
|
||||||
memset(&q, 0, sizeof(struct query));
|
|
||||||
q.type = T_NULL;
|
|
||||||
q.id = 1337;
|
|
||||||
d = resolv;
|
|
||||||
enc = get_base32_encoder();
|
|
||||||
|
|
||||||
*d++ = 'A';
|
|
||||||
enc->encode(d, &enclen, innerData, strlen(innerData));
|
|
||||||
d = resolv + strlen(resolv);
|
|
||||||
if (*d != '.') {
|
|
||||||
*d++ = '.';
|
|
||||||
}
|
|
||||||
strcpy(d, topdomain);
|
|
||||||
len = sizeof(buf);
|
|
||||||
ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
|
|
||||||
len = sizeof(query_packet) - 1; /* Skip extra null character */
|
|
||||||
|
|
||||||
if (strncmp(query_packet, buf, sizeof(query_packet)) || ret != len) {
|
|
||||||
printf("\n");
|
|
||||||
dump_packet(query_packet, len);
|
|
||||||
dump_packet(buf, ret);
|
|
||||||
}
|
|
||||||
fail_unless(strncmp(query_packet, buf, sizeof(query_packet)) == 0, "Did not compile expected packet");
|
|
||||||
fail_unless(ret == len, "Bad packet length: %d, expected %d", ret, len);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_decode_query)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
char *domain;
|
|
||||||
struct query q;
|
|
||||||
struct encoder *enc;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
memset(&q, 0, sizeof(struct query));
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
q.id = 0;
|
|
||||||
len = sizeof(query_packet) - 1;
|
|
||||||
enc = get_base32_encoder();
|
|
||||||
|
|
||||||
dns_decode(buf, sizeof(buf), &q, QR_QUERY, query_packet, len);
|
|
||||||
domain = strstr(q.name, topdomain);
|
|
||||||
len = sizeof(buf);
|
|
||||||
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), "Bad host length: %d, expected %d: '%s'", strlen(buf), strlen(innerData), buf);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_encode_response)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
char *host = "silly.host.of.iodine.code.kryo.se";
|
|
||||||
struct query q;
|
|
||||||
int len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
memset(&q, 0, sizeof(struct query));
|
|
||||||
strncpy(q.name, host, strlen(host));
|
|
||||||
q.type = T_NULL;
|
|
||||||
q.id = 1337;
|
|
||||||
|
|
||||||
ret = dns_encode(buf, len, &q, QR_ANSWER, msgData, strlen(msgData));
|
|
||||||
len = sizeof(answer_packet) - 1; /* Skip extra null character */
|
|
||||||
|
|
||||||
fail_unless(strncmp(answer_packet, buf, sizeof(answer_packet)) == 0, "Did not compile expected packet");
|
|
||||||
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, &q, QR_ANSWER, answer_packet, sizeof(answer_packet)-1);
|
|
||||||
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
|
|
||||||
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
|
|
||||||
fail_unless(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, answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id)-1);
|
|
||||||
fail_unless(strncmp(msgData, buf, sizeof(msgData)) == 0, "Did not extract expected data");
|
|
||||||
fail_unless(ret == strlen(msgData), "Bad data length: %d, expected %d", ret, strlen(msgData));
|
|
||||||
fail_unless(q.id == 0x8539, "q.id was %08X instead of %08X!", q.id, 0x8539);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_get_id_short_packet)
|
|
||||||
{
|
|
||||||
char buf[5];
|
|
||||||
int len;
|
|
||||||
unsigned short id;
|
|
||||||
|
|
||||||
len = sizeof(buf);
|
|
||||||
memset(&buf, 5, sizeof(buf));
|
|
||||||
|
|
||||||
id = dns_get_id(buf, len);
|
|
||||||
fail_unless(id == 0);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_get_id_low)
|
|
||||||
{
|
|
||||||
unsigned short id;
|
|
||||||
|
|
||||||
id = dns_get_id(answer_packet, sizeof(answer_packet));
|
|
||||||
fail_unless(id == 1337);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_get_id_high)
|
|
||||||
{
|
|
||||||
unsigned short id;
|
|
||||||
|
|
||||||
id = dns_get_id(answer_packet_high_trans_id, sizeof(answer_packet_high_trans_id));
|
|
||||||
fail_unless(id == 0x8539);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
static void
|
|
||||||
dump_packet(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
for (pos = 0; pos < len; pos++) {
|
|
||||||
printf("\\x%02X", (unsigned char) buf[pos]);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
for (pos = 0; pos < len; pos++) {
|
|
||||||
if (isalnum((unsigned char) buf[pos])) {
|
|
||||||
printf(" %c ", (unsigned char) buf[pos]);
|
|
||||||
} else {
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_dns_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Dns");
|
|
||||||
tcase_add_test(tc, test_encode_query);
|
|
||||||
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);
|
|
||||||
tcase_add_test(tc, test_get_id_short_packet);
|
|
||||||
tcase_add_test(tc, test_get_id_low);
|
|
||||||
tcase_add_test(tc, test_get_id_high);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "test.h"
|
|
||||||
#include "base32.h"
|
|
||||||
#include "base64.h"
|
|
||||||
|
|
||||||
#define TUPLES 4
|
|
||||||
|
|
||||||
static struct tuple
|
|
||||||
{
|
|
||||||
char *a;
|
|
||||||
char *b;
|
|
||||||
} dottests[] = {
|
|
||||||
{ "aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
||||||
"aaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaa"},
|
|
||||||
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."},
|
|
||||||
{ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
||||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
|
|
||||||
{ "abc123", "abc123" },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
START_TEST(test_inline_dotify)
|
|
||||||
{
|
|
||||||
char temp[1024];
|
|
||||||
char *b;
|
|
||||||
|
|
||||||
memset(temp, 0, sizeof(temp));
|
|
||||||
strcpy(temp, dottests[_i].a);
|
|
||||||
b = temp;
|
|
||||||
inline_dotify(b, sizeof(temp));
|
|
||||||
|
|
||||||
fail_unless(strcmp(dottests[_i].b, temp) == 0,
|
|
||||||
"'%s' != '%s'", temp, dottests[_i].b);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_inline_undotify)
|
|
||||||
{
|
|
||||||
char temp[1024];
|
|
||||||
char *b;
|
|
||||||
|
|
||||||
memset(temp, 0, sizeof(temp));
|
|
||||||
strcpy(temp, dottests[_i].b);
|
|
||||||
b = temp;
|
|
||||||
inline_undotify(b, sizeof(temp));
|
|
||||||
|
|
||||||
fail_unless(strcmp(dottests[_i].a, temp) == 0,
|
|
||||||
"'%s' != '%s'", temp, dottests[_i].a);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_build_hostname)
|
|
||||||
{
|
|
||||||
char data[256];
|
|
||||||
char buf[1024];
|
|
||||||
char *topdomain = "a.c";
|
|
||||||
int buflen;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(data); i++) {
|
|
||||||
data[i] = i & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
buflen = sizeof(buf);
|
|
||||||
|
|
||||||
for (i = 1; i < sizeof(data); i++) {
|
|
||||||
int len = build_hostname(buf, buflen, data, i, topdomain, get_base32_encoder(), sizeof(buf));
|
|
||||||
|
|
||||||
fail_if(len > i);
|
|
||||||
fail_if(strstr(buf, ".."), "Found double dots when encoding data len %d! buf: %s", i, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_encoding_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Encoding");
|
|
||||||
tcase_add_loop_test(tc, test_inline_dotify, 0, TUPLES);
|
|
||||||
tcase_add_loop_test(tc, test_inline_undotify, 0, TUPLES);
|
|
||||||
tcase_add_test(tc, test_build_hostname);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006-2009 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 <check.h>
|
|
||||||
|
|
||||||
#include "fw_query.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
START_TEST(test_fw_query_simple)
|
|
||||||
{
|
|
||||||
struct fw_query q;
|
|
||||||
struct fw_query *qp;
|
|
||||||
|
|
||||||
q.addrlen = 33;
|
|
||||||
q.id = 0x848A;
|
|
||||||
|
|
||||||
fw_query_init();
|
|
||||||
|
|
||||||
/* Test empty cache */
|
|
||||||
fw_query_get(0x848A, &qp);
|
|
||||||
fail_unless(qp == NULL);
|
|
||||||
|
|
||||||
fw_query_put(&q);
|
|
||||||
|
|
||||||
/* Test cache with one entry */
|
|
||||||
fw_query_get(0x848A, &qp);
|
|
||||||
fail_unless(qp->addrlen == q.addrlen);
|
|
||||||
fail_unless(qp->id == q.id);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_fw_query_edge)
|
|
||||||
{
|
|
||||||
struct fw_query q;
|
|
||||||
struct fw_query *qp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fw_query_init();
|
|
||||||
|
|
||||||
q.addrlen = 33;
|
|
||||||
q.id = 0x848A;
|
|
||||||
fw_query_put(&q);
|
|
||||||
|
|
||||||
for (i = 1; i < FW_QUERY_CACHE_SIZE; i++) {
|
|
||||||
q.addrlen++;
|
|
||||||
q.id++;
|
|
||||||
fw_query_put(&q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The query should still be cached */
|
|
||||||
fw_query_get(0x848A, &qp);
|
|
||||||
fail_unless(qp->addrlen == 33);
|
|
||||||
fail_unless(qp->id == 0x848A);
|
|
||||||
|
|
||||||
q.addrlen++;
|
|
||||||
q.id++;
|
|
||||||
fw_query_put(&q);
|
|
||||||
|
|
||||||
/* but now it is overwritten */
|
|
||||||
fw_query_get(0x848A, &qp);
|
|
||||||
fail_unless(qp == NULL);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_fw_query_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Forwarded query");
|
|
||||||
tcase_add_test(tc, test_fw_query_simple);
|
|
||||||
tcase_add_test(tc, test_fw_query_edge);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "test.h"
|
|
||||||
#include "login.h"
|
|
||||||
|
|
||||||
START_TEST(test_login_hash)
|
|
||||||
{
|
|
||||||
char ans[16];
|
|
||||||
char good[] = "\x2A\x8A\x12\xB4\xE0\x42\xEE\xAB\xD0\x19\x17\x1E\x44\xA0\x88\xCD";
|
|
||||||
char pass[32] = "iodine is the shit";
|
|
||||||
int len;
|
|
||||||
int seed;
|
|
||||||
|
|
||||||
len = sizeof(ans);
|
|
||||||
seed = 15;
|
|
||||||
|
|
||||||
memset(ans, 0, sizeof(ans));
|
|
||||||
login_calculate(ans, len, pass, seed);
|
|
||||||
fail_unless(strncmp(ans, good, len) == 0, NULL);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_login_hash_short)
|
|
||||||
{
|
|
||||||
char ans[8];
|
|
||||||
char check[sizeof(ans)];
|
|
||||||
char pass[32] = "iodine is the shit";
|
|
||||||
int len;
|
|
||||||
int seed;
|
|
||||||
|
|
||||||
len = sizeof(ans);
|
|
||||||
seed = 15;
|
|
||||||
|
|
||||||
memset(ans, 0, sizeof(ans));
|
|
||||||
memset(check, 0, sizeof(check));
|
|
||||||
|
|
||||||
/* If len < 16, it should do nothing */
|
|
||||||
login_calculate(ans, len, pass, seed);
|
|
||||||
fail_if(memcmp(ans, check, sizeof(ans)));
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_login_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Login");
|
|
||||||
tcase_add_test(tc, test_login_hash);
|
|
||||||
tcase_add_test(tc, test_login_hash_short);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,297 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <arpa/nameser.h>
|
|
||||||
#ifdef DARWIN
|
|
||||||
#include <arpa/nameser8_compat.h>
|
|
||||||
#endif
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <check.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "dns.h"
|
|
||||||
#include "read.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
START_TEST(test_read_putshort)
|
|
||||||
{
|
|
||||||
unsigned short k;
|
|
||||||
unsigned short l;
|
|
||||||
char* p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 65536; i++) {
|
|
||||||
p = (char*)&k;
|
|
||||||
putshort(&p, 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,
|
|
||||||
"Bad value on readshort for %d: %d != %d",
|
|
||||||
i, l, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_putlong)
|
|
||||||
{
|
|
||||||
uint32_t k;
|
|
||||||
uint32_t l;
|
|
||||||
char* p;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
p = (char*)&k;
|
|
||||||
j = 0xf << i;
|
|
||||||
|
|
||||||
putlong(&p, 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,
|
|
||||||
"Bad value on readlong for %d: %d != %d", i, l, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_empty_loop)
|
|
||||||
{
|
|
||||||
unsigned char emptyloop[] = {
|
|
||||||
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
data = (char*) emptyloop + sizeof(HEADER);
|
|
||||||
buf[1023] = 'A';
|
|
||||||
rv = readname((char *) emptyloop, sizeof(emptyloop), &data, buf, 1023);
|
|
||||||
fail_unless(buf[1023] == 'A');
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_inf_loop)
|
|
||||||
{
|
|
||||||
unsigned char infloop[] = {
|
|
||||||
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 'A', 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01 };
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_longname)
|
|
||||||
{
|
|
||||||
unsigned char longname[] =
|
|
||||||
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x3FzBCDEFGHIJKLMNOPQURSTUVXYZ0123456789abcdefghijklmnopqrstuvxyzAA"
|
|
||||||
"\x00\x00\x01\x00\x01";
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
data = (char*) longname + sizeof(HEADER);
|
|
||||||
buf[256] = '\a';
|
|
||||||
rv = readname((char*) longname, sizeof(longname), &data, buf, 256);
|
|
||||||
fail_unless(buf[256] == '\a');
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_onejump)
|
|
||||||
{
|
|
||||||
unsigned char onejump[] =
|
|
||||||
"AA\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
|
|
||||||
"\x02hh\xc0\x15\x00\x01\x00\x01\x05zBCDE\x00";
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
data = (char*) onejump + sizeof(HEADER);
|
|
||||||
rv = readname((char*) onejump, sizeof(onejump), &data, buf, 256);
|
|
||||||
fail_unless(rv == 9);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_badjump_start)
|
|
||||||
{
|
|
||||||
unsigned char badjump[] = {
|
|
||||||
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
|
|
||||||
unsigned char *jumper;
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* This test uses malloc to cause segfault if jump is executed */
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
jumper = malloc(sizeof(badjump));
|
|
||||||
if (jumper) {
|
|
||||||
memcpy(jumper, badjump, sizeof(badjump));
|
|
||||||
data = (char*) jumper + sizeof(HEADER);
|
|
||||||
rv = readname((char*) jumper, sizeof(badjump), &data, buf, 256);
|
|
||||||
|
|
||||||
fail_unless(rv == 0);
|
|
||||||
fail_unless(buf[0] == 0);
|
|
||||||
}
|
|
||||||
free(jumper);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_read_name_badjump_second)
|
|
||||||
{
|
|
||||||
unsigned char badjump2[] = {
|
|
||||||
'A', 'A', 0x81, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 'B', 'A', 0xfe, 0xcc, 0x00, 0x01, 0x00, 0x01 };
|
|
||||||
unsigned char *jumper;
|
|
||||||
char buf[1024];
|
|
||||||
char *data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* This test uses malloc to cause segfault if jump is executed */
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
jumper = malloc(sizeof(badjump2));
|
|
||||||
if (jumper) {
|
|
||||||
memcpy(jumper, badjump2, sizeof(badjump2));
|
|
||||||
data = (char*) jumper + sizeof(HEADER);
|
|
||||||
rv = readname((char*) jumper, sizeof(badjump2), &data, buf, 256);
|
|
||||||
|
|
||||||
fail_unless(rv == 4);
|
|
||||||
fail_unless(strcmp("BA.", buf) == 0,
|
|
||||||
"buf is not BA: %s", buf);
|
|
||||||
}
|
|
||||||
free(jumper);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_putname)
|
|
||||||
{
|
|
||||||
char out[] = "\x06" "BADGER\x06" "BADGER\x04" "KRYO\x02" "SE\x00";
|
|
||||||
char buf[256];
|
|
||||||
char *domain = "BADGER.BADGER.KRYO.SE";
|
|
||||||
char *b;
|
|
||||||
int len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
len = 256;
|
|
||||||
|
|
||||||
memset(buf, 0, 256);
|
|
||||||
b = buf;
|
|
||||||
ret = putname(&b, 256, domain);
|
|
||||||
|
|
||||||
fail_unless(ret == strlen(domain) + 1);
|
|
||||||
fail_unless(strncmp(buf, out, ret) == 0, "Happy flow failed");
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_putname_nodot)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
char *nodot =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
char *b;
|
|
||||||
int len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
len = 256;
|
|
||||||
|
|
||||||
memset(buf, 0, 256);
|
|
||||||
b = buf;
|
|
||||||
ret = putname(&b, 256, nodot);
|
|
||||||
|
|
||||||
fail_unless(ret == -1);
|
|
||||||
fail_unless(b == buf);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_putname_toolong)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
char *toolong =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ."
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.ABCDEFGHIJKLMNOPQRSTUVWXYZ.";
|
|
||||||
char *b;
|
|
||||||
int len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
len = 256;
|
|
||||||
|
|
||||||
memset(buf, 0, 256);
|
|
||||||
b = buf;
|
|
||||||
ret = putname(&b, 256, toolong);
|
|
||||||
|
|
||||||
fail_unless(ret == -1);
|
|
||||||
fail_unless(b == buf);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
|
|
||||||
TCase *
|
|
||||||
test_read_create_tests()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("Read");
|
|
||||||
tcase_set_timeout(tc, 60);
|
|
||||||
tcase_add_test(tc, test_read_putshort);
|
|
||||||
tcase_add_test(tc, test_read_putlong);
|
|
||||||
tcase_add_test(tc, test_read_name_empty_loop);
|
|
||||||
tcase_add_test(tc, test_read_name_inf_loop);
|
|
||||||
tcase_add_test(tc, test_read_name_longname);
|
|
||||||
tcase_add_test(tc, test_read_name_onejump);
|
|
||||||
tcase_add_test(tc, test_read_name_badjump_start);
|
|
||||||
tcase_add_test(tc, test_read_name_badjump_second);
|
|
||||||
tcase_add_test(tc, test_putname);
|
|
||||||
tcase_add_test(tc, test_putname_nodot);
|
|
||||||
tcase_add_test(tc, test_putname_toolong);
|
|
||||||
|
|
||||||
return tc;
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
SRunner *runner;
|
|
||||||
Suite *iodine;
|
|
||||||
TCase *test;
|
|
||||||
int failed;
|
|
||||||
|
|
||||||
iodine = suite_create("iodine");
|
|
||||||
|
|
||||||
test = test_base32_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_base64_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_dns_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_encoding_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_read_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_login_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_user_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
test = test_fw_query_create_tests();
|
|
||||||
suite_add_tcase(iodine, test);
|
|
||||||
|
|
||||||
runner = srunner_create(iodine);
|
|
||||||
srunner_run_all(runner, CK_NORMAL);
|
|
||||||
failed = srunner_ntests_failed(runner);
|
|
||||||
|
|
||||||
srunner_free(runner);
|
|
||||||
|
|
||||||
return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 __TEST_H__
|
|
||||||
#define __TEST_H__
|
|
||||||
|
|
||||||
TCase *test_base32_create_tests();
|
|
||||||
TCase *test_base64_create_tests();
|
|
||||||
TCase *test_dns_create_tests();
|
|
||||||
TCase *test_encoding_create_tests();
|
|
||||||
TCase *test_read_create_tests();
|
|
||||||
TCase *test_login_create_tests();
|
|
||||||
TCase *test_user_create_tests();
|
|
||||||
TCase *test_fw_query_create_tests();
|
|
||||||
|
|
||||||
char *va_str(const char *, ...);
|
|
||||||
|
|
||||||
#if (CHECK_MAJOR_VERSION == 0 && \
|
|
||||||
((CHECK_MINOR_VERSION == 9 && CHECK_MICRO_VERSION < 2) || \
|
|
||||||
(CHECK_MINOR_VERSION < 9)))
|
|
||||||
#define tcase_set_timeout(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,199 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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 <check.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "user.h"
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
START_TEST(test_init_users)
|
|
||||||
{
|
|
||||||
in_addr_t ip;
|
|
||||||
char givenip[16];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
|
||||||
init_users(ip, 27);
|
|
||||||
for (i = 0; i < USERS; i++) {
|
|
||||||
fail_unless(users[i].id == i);
|
|
||||||
fail_unless(users[i].q.id == 0);
|
|
||||||
fail_unless(users[i].inpacket.len == 0);
|
|
||||||
fail_unless(users[i].outpacket.len == 0);
|
|
||||||
snprintf(givenip, sizeof(givenip), "127.0.0.%d", i + 2);
|
|
||||||
fail_unless(users[i].tun_ip == inet_addr(givenip));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_users_waiting)
|
|
||||||
{
|
|
||||||
in_addr_t ip;
|
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
|
||||||
init_users(ip, 27);
|
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 0);
|
|
||||||
|
|
||||||
users[3].active = 1;
|
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 0);
|
|
||||||
|
|
||||||
users[3].last_pkt = time(NULL);
|
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 0);
|
|
||||||
|
|
||||||
users[3].conn = CONN_DNS_NULL;
|
|
||||||
users[3].q.id = 1;
|
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 1);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_find_user_by_ip)
|
|
||||||
{
|
|
||||||
in_addr_t ip;
|
|
||||||
unsigned int testip;
|
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
|
||||||
init_users(ip, 27);
|
|
||||||
users[0].conn = CONN_DNS_NULL;
|
|
||||||
|
|
||||||
testip = (unsigned int) inet_addr("10.0.0.1");
|
|
||||||
fail_unless(find_user_by_ip(testip) == -1);
|
|
||||||
|
|
||||||
testip = (unsigned int) inet_addr("127.0.0.2");
|
|
||||||
fail_unless(find_user_by_ip(testip) == -1);
|
|
||||||
|
|
||||||
users[0].active = 1;
|
|
||||||
|
|
||||||
testip = (unsigned int) inet_addr("127.0.0.2");
|
|
||||||
fail_unless(find_user_by_ip(testip) == -1);
|
|
||||||
|
|
||||||
users[0].last_pkt = time(NULL);
|
|
||||||
|
|
||||||
testip = (unsigned int) inet_addr("127.0.0.2");
|
|
||||||
fail_unless(find_user_by_ip(testip) == 0);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_all_users_waiting_to_send)
|
|
||||||
{
|
|
||||||
in_addr_t ip;
|
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
|
||||||
init_users(ip, 27);
|
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
|
||||||
|
|
||||||
users[0].conn = CONN_DNS_NULL;
|
|
||||||
users[0].active = 1;
|
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
|
||||||
|
|
||||||
users[0].last_pkt = time(NULL);
|
|
||||||
users[0].outpacket.len = 0;
|
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 0);
|
|
||||||
|
|
||||||
#ifdef OUTPACKETQ_LEN
|
|
||||||
users[0].outpacketq_filled = 1;
|
|
||||||
#else
|
|
||||||
users[0].outpacket.len = 44;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_find_available_user)
|
|
||||||
{
|
|
||||||
in_addr_t ip;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
|
||||||
init_users(ip, 27);
|
|
||||||
|
|
||||||
for (i = 0; i < USERS; 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
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
TCase *tc;
|
|
||||||
|
|
||||||
tc = tcase_create("User");
|
|
||||||
tcase_add_test(tc, test_init_users);
|
|
||||||
tcase_add_test(tc, test_users_waiting);
|
|
||||||
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;
|
|
||||||
}
|
|
274
man/iodine.8
274
man/iodine.8
|
@ -1,5 +1,5 @@
|
||||||
.\" groff -man -Tascii iodine.8
|
.\" groff -man -Tascii iodine.8
|
||||||
.TH IODINE 8 "JUL 2008" "User Manuals"
|
.TH IODINE 8 "DEC 2009" "User Manuals"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
iodine, iodined \- tunnel IPv4 over DNS
|
iodine, iodined \- tunnel IPv4 over DNS
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -19,10 +19,20 @@ iodine, iodined \- tunnel IPv4 over DNS
|
||||||
.I device
|
.I device
|
||||||
.B ] [-m
|
.B ] [-m
|
||||||
.I fragsize
|
.I fragsize
|
||||||
|
.B ] [-M
|
||||||
|
.I namelen
|
||||||
.B ] [-z
|
.B ] [-z
|
||||||
.I context
|
.I context
|
||||||
.B ] [-F
|
.B ] [-F
|
||||||
.I pidfile
|
.I pidfile
|
||||||
|
.B ] [-T
|
||||||
|
.I dnstype
|
||||||
|
.B ] [-O
|
||||||
|
.I downenc
|
||||||
|
.B ] [-L
|
||||||
|
.I 0|1
|
||||||
|
.B ] [-I
|
||||||
|
.I interval
|
||||||
.B ]
|
.B ]
|
||||||
.B [
|
.B [
|
||||||
.I nameserver
|
.I nameserver
|
||||||
|
@ -46,7 +56,7 @@ iodine, iodined \- tunnel IPv4 over DNS
|
||||||
.B ] [-p
|
.B ] [-p
|
||||||
.I port
|
.I port
|
||||||
.B ] [-n
|
.B ] [-n
|
||||||
.I external ip
|
.I external_ip
|
||||||
.B ] [-b
|
.B ] [-b
|
||||||
.I dnsport
|
.I dnsport
|
||||||
.B ] [-P
|
.B ] [-P
|
||||||
|
@ -66,11 +76,20 @@ iodine, iodined \- tunnel IPv4 over DNS
|
||||||
lets you tunnel IPv4 data through a DNS
|
lets you tunnel IPv4 data through a DNS
|
||||||
server. This can be useful in situations where Internet access is firewalled,
|
server. This can be useful in situations where Internet access is firewalled,
|
||||||
but DNS queries are allowed. It needs a TUN/TAP device to operate. The
|
but DNS queries are allowed. It needs a TUN/TAP device to operate. The
|
||||||
bandwidth is asymmetrical with limited upstream and up to 1 Mbit/s downstream.
|
bandwidth is asymmetrical,
|
||||||
|
with a measured maximum of 680 kbit/s upstream and 2.3 Mbit/s
|
||||||
|
downstream in a wired LAN test network.
|
||||||
|
Realistic sustained throughput on a Wifi network using a carrier-grade
|
||||||
|
DNS cache has been measured at some 50 kbit/s upstream and over 200 kbit/s
|
||||||
|
downstream.
|
||||||
.B iodine
|
.B iodine
|
||||||
is the client application,
|
is the client application,
|
||||||
.B iodined
|
.B iodined
|
||||||
is the server.
|
is the server.
|
||||||
|
|
||||||
|
Note: server and client are required to speak the exact same protocol. In most
|
||||||
|
cases, this means running the same iodine version. Unfortunately, implementing
|
||||||
|
backward and forward protocol compatibility is usually not feasible.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.SS Common Options:
|
.SS Common Options:
|
||||||
.TP
|
.TP
|
||||||
|
@ -111,52 +130,151 @@ of the iodined host and test if it is reachable directly. If it is, traffic
|
||||||
will be sent to the server instead of the DNS relay.
|
will be sent to the server instead of the DNS relay.
|
||||||
.TP
|
.TP
|
||||||
.B -m fragsize
|
.B -m fragsize
|
||||||
Maximum downstream fragsize. Not setting this will cause the client to probe
|
Force maximum downstream fragment size. Not setting this will cause the
|
||||||
the maximum accepted downstream packet size.
|
client to automatically probe the maximum accepted downstream fragment size.
|
||||||
|
.TP
|
||||||
|
.B -M namelen
|
||||||
|
Maximum length of upstream hostnames, default 255.
|
||||||
|
Usable range ca. 100 to 255.
|
||||||
|
Use this option to scale back upstream bandwidth in favor of downstream
|
||||||
|
bandwidth.
|
||||||
|
Also useful for DNS servers that perform unreliably when using full-length
|
||||||
|
hostnames, noticable when fragment size autoprobe returns very
|
||||||
|
different results each time.
|
||||||
|
.TP
|
||||||
|
.B -T dnstype
|
||||||
|
DNS request type override.
|
||||||
|
By default, autodetection will probe for working DNS request types, and
|
||||||
|
will select the request type that is expected to provide the most bandwidth.
|
||||||
|
However, it may turn out that a DNS relay imposes limits that skew the
|
||||||
|
picture, which may lead to an "unexpected" DNS request type providing
|
||||||
|
more bandwidth.
|
||||||
|
In that case, use this option to override the autodetection.
|
||||||
|
In (expected) decreasing bandwidth order, the supported DNS request types are:
|
||||||
|
.IR NULL ,
|
||||||
|
.IR TXT ,
|
||||||
|
.IR SRV ,
|
||||||
|
.IR MX ,
|
||||||
|
.I CNAME
|
||||||
|
and
|
||||||
|
.I A
|
||||||
|
(returning CNAME).
|
||||||
|
Note that
|
||||||
|
.IR SRV ,
|
||||||
|
.I MX
|
||||||
|
and
|
||||||
|
.I A
|
||||||
|
may/will cause additional lookups by "smart" caching
|
||||||
|
nameservers to get an actual IP address, which may either slow down or fail
|
||||||
|
completely.
|
||||||
|
.TP
|
||||||
|
.B -O downenc
|
||||||
|
Force downstream encoding type for all query type responses except NULL.
|
||||||
|
Default is autodetected, but may not spot all problems for the more advanced
|
||||||
|
codecs.
|
||||||
|
Use this option to override the autodetection.
|
||||||
|
.I Base32
|
||||||
|
is the lowest-grade codec and should always work; this is used when
|
||||||
|
autodetection fails.
|
||||||
|
.I Base64
|
||||||
|
provides more bandwidth, but may not work on all nameservers.
|
||||||
|
.I Base64u
|
||||||
|
is equal to Base64 except in using underscore ('_')
|
||||||
|
instead of plus sign ('+'), possibly working where
|
||||||
|
.I Base64
|
||||||
|
does not.
|
||||||
|
.I Base128
|
||||||
|
uses high byte values (mostly accented letters in iso8859-1),
|
||||||
|
which might work with some nameservers.
|
||||||
|
For TXT queries,
|
||||||
|
.I Raw
|
||||||
|
will provide maximum performance, but this will only work if the nameserver
|
||||||
|
path is fully 8-bit-clean for responses that are assumed to be "legible text".
|
||||||
|
.TP
|
||||||
|
.B -L 0|1
|
||||||
|
Lazy-mode switch.
|
||||||
|
\-L1 (default): Use lazy mode for improved performance and decreased latency.
|
||||||
|
A very small minority of DNS relays appears to be unable to handle the
|
||||||
|
lazy mode traffic pattern, resulting in no or very little data coming through.
|
||||||
|
The iodine client will detect this and try to switch back to legacy mode,
|
||||||
|
but this may not always work.
|
||||||
|
In these situations use \-L0 to force running in legacy mode
|
||||||
|
(implies \-I1).
|
||||||
|
.TP
|
||||||
|
.B -I interval
|
||||||
|
Maximum interval between requests (pings) so that intermediate DNS
|
||||||
|
servers will not time out. Default is 4 in lazy mode, which will work
|
||||||
|
fine in most cases. When too many SERVFAIL errors occur, iodine
|
||||||
|
will automatically reduce this to 1.
|
||||||
|
To get absolute minimum DNS traffic,
|
||||||
|
increase well above 4, but not so high that SERVFAIL errors start to occur.
|
||||||
|
There are some DNS relays with very small timeouts,
|
||||||
|
notably dnsadvantage.com (ultradns), that will give
|
||||||
|
SERVFAIL errors even with \-I1; data will still get trough,
|
||||||
|
and these errors can be ignored.
|
||||||
|
Maximum useful value is 59, since iodined will close a client's
|
||||||
|
connection after 60 seconds of inactivity.
|
||||||
.SS Server Options:
|
.SS Server Options:
|
||||||
.TP
|
.TP
|
||||||
.B -c
|
.B -c
|
||||||
Disable checks on client IP on all incoming requests.
|
Disable checking the client IP address on all incoming requests.
|
||||||
|
By default, requests originating from non-matching IP adresses will be
|
||||||
|
rejected, however this will cause problems when requests are routed
|
||||||
|
via a cluster of DNS servers.
|
||||||
.TP
|
.TP
|
||||||
.B -s
|
.B -s
|
||||||
Don't try to configure IP address or MTU. This should only be used if
|
Don't try to configure IP address or MTU.
|
||||||
you have already configured the device that will be used.
|
This should only be used if you have already configured the device that will be
|
||||||
|
used.
|
||||||
.TP
|
.TP
|
||||||
.B -D
|
.B -D
|
||||||
Increase debug level. Level 1 prints info about each RX/TX packet.
|
Increase debug level. Level 1 prints info about each RX/TX packet.
|
||||||
|
Implies the
|
||||||
|
.B -f
|
||||||
|
option.
|
||||||
|
On level 2 (-DD) or higher, DNS queries will be printed literally.
|
||||||
|
When using Base128 upstream encoding, this is best viewed as
|
||||||
|
ISO Latin-1 text instead of (illegal) UTF-8.
|
||||||
|
This is easily done with : "LC_ALL=C luit iodined -DD ..."
|
||||||
|
(see luit(1)).
|
||||||
.TP
|
.TP
|
||||||
.B -m mtu
|
.B -m mtu
|
||||||
Set 'mtu' as mtu size for the tunnel device. This will be sent to the client
|
Set 'mtu' as mtu size for the tun device.
|
||||||
on connect, and the client will use the same mtu.
|
This will be sent to the client on login, and the client will use the same mtu
|
||||||
|
for its tun device. Default 1130. Note that the DNS traffic will be
|
||||||
|
automatically fragmented when needed.
|
||||||
.TP
|
.TP
|
||||||
.B -l listen_ip
|
.B -l listen_ip
|
||||||
Make the server listen only on 'listen_ip' instead of on 0.0.0.0 for incoming
|
Make the server listen only on 'listen_ip' for incoming requests.
|
||||||
connections.
|
By default, incoming requests are accepted from all interfaces.
|
||||||
.TP
|
.TP
|
||||||
.B -p port
|
.B -p port
|
||||||
Make the server listen on 'port' instead of 53 for traffic.
|
Make the server listen on 'port' instead of 53 for traffic.
|
||||||
.B Note:
|
.B Note:
|
||||||
You must make sure the dns requests are forwarded to this port yourself.
|
You must make sure the dns requests are forwarded to this port yourself.
|
||||||
.TP
|
.TP
|
||||||
.B -n external ip
|
.B -n external_ip
|
||||||
The IP address to return in NS responses. Default is to return the address used
|
The IP address to return in NS responses. Default is to return the address used
|
||||||
as destination in the query.
|
as destination in the query.
|
||||||
.TP
|
.TP
|
||||||
.B -b dnsport
|
.B -b dnsport
|
||||||
If this port is specified, all incoming requests not inside the tunnel domain
|
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.
|
will be forwarded to this port on localhost, to be handled by a real dns.
|
||||||
|
.B Note:
|
||||||
|
The forwarding is not fully transparent, and not advised for use
|
||||||
|
in production environments.
|
||||||
.SS Client Arguments:
|
.SS Client Arguments:
|
||||||
.TP
|
.TP
|
||||||
.B nameserver
|
.B nameserver
|
||||||
The nameserver to use to relay the dns traffic. This can be any relaying
|
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.
|
nameserver or the server running iodined if reachable. This field can be
|
||||||
This argument is optional, and if not specified a nameserver will be read
|
given as an IP address, or as a hostname. This argument is optional, and
|
||||||
from the
|
if not specified a nameserver will be read from the
|
||||||
.I /etc/resolv.conf
|
.I /etc/resolv.conf
|
||||||
file.
|
file.
|
||||||
.TP
|
.TP
|
||||||
.B topdomain
|
.B topdomain
|
||||||
The dns traffic will be sent as querys of type NULL for subdomains under
|
The dns traffic will be sent as queries for subdomains under
|
||||||
\'topdomain'. This is normally a subdomain to a domain you own. Use a short
|
\'topdomain'. This is normally a subdomain to a domain you own. Use a short
|
||||||
domain name to get better throughput. If
|
domain name to get better throughput. If
|
||||||
.B nameserver
|
.B nameserver
|
||||||
|
@ -165,96 +283,56 @@ must be the same on both the client and the server.
|
||||||
.SS Server Arguments:
|
.SS Server Arguments:
|
||||||
.TP
|
.TP
|
||||||
.B tunnel_ip[/netmask]
|
.B tunnel_ip[/netmask]
|
||||||
This is the servers ip address on the tunnel interface. The client will be
|
This is the server's ip address on the tun interface. The client will be
|
||||||
given the next ip number in the range. It is recommended to use the
|
given the next ip number in the range. It is recommended to use the
|
||||||
10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden
|
10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden
|
||||||
by specifying it here. Using a smaller network will limit the number of
|
by specifying it here. Using a smaller network will limit the number of
|
||||||
concurrent users.
|
concurrent users.
|
||||||
.TP
|
.TP
|
||||||
.B topdomain
|
.B topdomain
|
||||||
The dns traffic will is expected to be sent as querys of type NULL for
|
The dns traffic is expected to arrive as queries for
|
||||||
subdomains under 'topdomain'. This is normally a subdomain to a domain you
|
subdomains under 'topdomain'. This is normally a subdomain to a domain you
|
||||||
own. Use a short domain name to get better throughput. This argument must be
|
own. Use a short domain name to get better throughput. This argument must be
|
||||||
the same on both the client and the server.
|
the same on both the client and the server. Queries for domains other
|
||||||
|
than 'topdomain' will be forwarded when the \-b option is given, otherwise
|
||||||
|
they will be dropped.
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.SS Quickstart:
|
See the README file for both a quick test scenario, and a detailed description
|
||||||
.TP
|
of real-world deployment.
|
||||||
Try it out within your own LAN! Follow these simple steps:
|
.SH SECURITY
|
||||||
.TP
|
Login is a relatively secure challenge-response MD5 hash, with the
|
||||||
- On your server, run: ./iodined \-f 10.0.0.1 test.asdf
|
password never passing the wire.
|
||||||
(If you already use the 10.0.0.0 network, use another internal net like
|
However, all other data is
|
||||||
172.16.0.0)
|
.B NOT
|
||||||
.TP
|
encrypted in any way. The DNS traffic is also vulnerable to replay,
|
||||||
- Enter a password
|
injection and man-in-the-middle attacks, especially when iodined is used
|
||||||
.TP
|
with the \-c option. Use of ssh or vpn tunneling is strongly recommended.
|
||||||
- On the client, run: ./iodine \-f 192.168.0.1 test.asdf
|
On both server and client, use
|
||||||
(Replace 192.168.0.1 with the server's ip address)
|
.IR iptables ,
|
||||||
.TP
|
.I pf
|
||||||
- Enter the same password
|
or other firewalls to block all traffic coming in from the tun interfaces,
|
||||||
.TP
|
except to the used ssh or vpn ports.
|
||||||
- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1
|
.SH ENVIRONMENT
|
||||||
.TP
|
.SS IODINE_PASS
|
||||||
- Try pinging each other through the tunnel
|
If the environment variable
|
||||||
.TP
|
.B IODINE_PASS
|
||||||
- Done! :)
|
is set, iodine will use the value it is set to as password instead of asking
|
||||||
.TP
|
for one. The
|
||||||
To actually use it through a relaying nameserver, see below.
|
.B -P
|
||||||
.SS Full setup:
|
option still has precedence.
|
||||||
|
.SS IODINED_PASS
|
||||||
.TP
|
If the environment variable
|
||||||
.B Server side:
|
.B IODINED_PASS
|
||||||
To use this tunnel, you need control over a real domain (like mytunnel.com),
|
is set, iodined will use the value it is set to as password instead of asking
|
||||||
and a server with a public IP number. If the server already runs a DNS
|
for one. The
|
||||||
server, change the listening port and then use the \-b option to let
|
.B -P
|
||||||
iodined forward the DNS requests. Then, delegate a subdomain
|
option still has precedence.
|
||||||
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
|
.El
|
||||||
add these lines to the zone file (replace 10.15.213.99 with your server ip):
|
.SH SEE ALSO
|
||||||
|
The README file in the source distribution contains some more elaborate
|
||||||
.nf
|
information.
|
||||||
tunnel1host IN A 10.15.213.99
|
|
||||||
tunnel1 IN NS tunnel1host.mytunnel.com.
|
|
||||||
.fi
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
everything is ready for the client.
|
|
||||||
.TP
|
|
||||||
.B 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.
|
|
||||||
.TP
|
|
||||||
.B Routing:
|
|
||||||
The normal case is to route all traffic through the DNS tunnel. To do this, first
|
|
||||||
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 Troubleshooting:
|
|
||||||
Use the \-D option on the server to show received and sent queries, or use a
|
|
||||||
tool like Wireshark/tcpdump. The iodined server replies to NS requests sent for
|
|
||||||
subdomains of the tunnel domain. If your domain is tunnel.com, send a NS
|
|
||||||
request for foo.tunnel.com to see if the delegation works. dig is a good tool
|
|
||||||
for this:
|
|
||||||
.nf
|
|
||||||
dig \-t NS foo123.tunnel.com
|
|
||||||
.fi
|
|
||||||
.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
|
.SH BUGS
|
||||||
File bugs at http://dev.kryo.se/iodine/
|
File bugs at http://dev.kryo.se/iodine/
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>
|
Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>. Major
|
||||||
|
contributions by Anne Bezemer.
|
||||||
|
|
14
src/Makefile
14
src/Makefile
|
@ -1,4 +1,4 @@
|
||||||
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o
|
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o base64u.o base128.o md5.o common.o
|
||||||
CLIENTOBJS = iodine.o client.o util.o
|
CLIENTOBJS = iodine.o client.o util.o
|
||||||
CLIENT = ../bin/iodine
|
CLIENT = ../bin/iodine
|
||||||
SERVEROBJS = iodined.o user.o fw_query.o
|
SERVEROBJS = iodined.o user.o fw_query.o
|
||||||
|
@ -30,7 +30,17 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
|
||||||
@echo CC $<
|
@echo CC $<
|
||||||
@$(CC) $(CFLAGS) $< -o $@
|
@$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
base64u.o client.o iodined.o: base64u.h
|
||||||
|
base64u.c: base64.c
|
||||||
|
@echo Making $@
|
||||||
|
@echo '/* No use in editing, produced by Makefile! */' > $@
|
||||||
|
@sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < base64.c >> $@
|
||||||
|
base64u.h: base64.h
|
||||||
|
@echo Making $@
|
||||||
|
@echo '/* No use in editing, produced by Makefile! */' > $@
|
||||||
|
@sed -e 's/\([Bb][Aa][Ss][Ee]64\)/\1u/g ; s/0123456789+/0123456789_/' < base64.h >> $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo "Cleaning src/"
|
@echo "Cleaning src/"
|
||||||
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core
|
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.*
|
||||||
|
|
||||||
|
|
250
src/base32.c
250
src/base32.c
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
||||||
|
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -26,10 +27,13 @@
|
||||||
|
|
||||||
static const char cb32[] =
|
static const char cb32[] =
|
||||||
"abcdefghijklmnopqrstuvwxyz012345";
|
"abcdefghijklmnopqrstuvwxyz012345";
|
||||||
static unsigned char rev32[128];
|
static const char cb32_ucase[] =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
|
||||||
|
static unsigned char rev32[256];
|
||||||
|
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_encode(char *, size_t *, const void *, size_t);
|
||||||
|
static int base32_decode(void *, size_t *, const char *, size_t);
|
||||||
static int base32_handles_dots();
|
static int base32_handles_dots();
|
||||||
static int base32_blksize_raw();
|
static int base32_blksize_raw();
|
||||||
static int base32_blksize_enc();
|
static int base32_blksize_enc();
|
||||||
|
@ -69,17 +73,19 @@ base32_blksize_enc()
|
||||||
return BLKSIZE_ENC;
|
return BLKSIZE_ENC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
inline static void
|
||||||
base32_reverse_init()
|
base32_reverse_init()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
static int reverse_init = 0;
|
|
||||||
|
|
||||||
if (!reverse_init) {
|
if (!reverse_init) {
|
||||||
|
memset (rev32, 0, 256);
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
c = cb32[i];
|
c = cb32[i];
|
||||||
rev32[(int) c] = i;
|
rev32[(int) c] = i;
|
||||||
|
c = cb32_ucase[i];
|
||||||
|
rev32[(int) c] = i;
|
||||||
}
|
}
|
||||||
reverse_init = 1;
|
reverse_init = 1;
|
||||||
}
|
}
|
||||||
|
@ -100,123 +106,165 @@ b32_8to5(int in)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
||||||
|
/*
|
||||||
|
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
|
||||||
|
*
|
||||||
|
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
||||||
|
* to hold the trailing '\0'.
|
||||||
|
*
|
||||||
|
* return value : #bytes filled in buf (excluding \0)
|
||||||
|
* sets *buflen to : #bytes encoded from data
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
size_t newsize;
|
unsigned char *udata = (unsigned char *) data;
|
||||||
size_t maxsize;
|
int iout = 0; /* to-be-filled output char */
|
||||||
unsigned char *p;
|
int iin = 0; /* one more than last input byte that can be
|
||||||
unsigned char *q;
|
successfully decoded */
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(buf, 0, *buflen);
|
/* Note: Don't bother to optimize manually. GCC optimizes
|
||||||
|
better(!) when using simplistic array indexing. */
|
||||||
|
|
||||||
/* how many chars can we encode within the buf */
|
while (1) {
|
||||||
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
|
if (iout >= *buflen || iin >= size)
|
||||||
/* how big will the encoded data be */
|
break;
|
||||||
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
|
buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
|
||||||
if (size % BLKSIZE_RAW) {
|
iout++;
|
||||||
newsize += BLKSIZE_ENC;
|
|
||||||
|
if (iout >= *buflen || iin >= size) {
|
||||||
|
iout--; /* previous char is useless */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* if the buffer is too small, eat some of the data */
|
buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
|
||||||
if (*buflen < newsize) {
|
((iin + 1 < size) ?
|
||||||
size = maxsize;
|
((udata[iin + 1] & 0xc0) >> 6) : 0)];
|
||||||
|
iin++; /* 0 complete, iin=1 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size) {
|
||||||
|
iout--; /* previous char is useless */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
|
||||||
|
((iin + 1 < size) ?
|
||||||
|
((udata[iin + 1] & 0xf0) >> 4) : 0)];
|
||||||
|
iin++; /* 1 complete, iin=2 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
|
||||||
|
((iin + 1 < size) ?
|
||||||
|
((udata[iin + 1] & 0x80) >> 7) : 0)];
|
||||||
|
iin++; /* 2 complete, iin=3 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size) {
|
||||||
|
iout--; /* previous char is useless */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
|
||||||
|
((iin + 1 < size) ?
|
||||||
|
((udata[iin + 1] & 0xe0) >> 5) : 0)];
|
||||||
|
iin++; /* 3 complete, iin=4 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb32[((udata[iin] & 0x1f))];
|
||||||
|
iin++; /* 4 complete, iin=5 */
|
||||||
|
iout++;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = (unsigned char *) buf;
|
buf[iout] = '\0';
|
||||||
q = (unsigned char *)data;
|
|
||||||
|
|
||||||
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';
|
|
||||||
p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
|
|
||||||
p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
|
|
||||||
p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
|
|
||||||
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 += BLKSIZE_RAW;
|
|
||||||
p += BLKSIZE_ENC;
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
/* store number of bytes from data that was used */
|
/* store number of bytes from data that was used */
|
||||||
*buflen = size;
|
*buflen = iin;
|
||||||
|
|
||||||
return strlen(buf);
|
return iout;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECODE_ERROR 0xffffffff
|
|
||||||
#define REV32(x) rev32[(int) (x)]
|
#define REV32(x) rev32[(int) (x)]
|
||||||
|
|
||||||
static int
|
|
||||||
decode_token(const unsigned char *t, unsigned char *data, size_t len)
|
|
||||||
{
|
|
||||||
if (len < 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
data[0] = ((REV32(t[0]) & 0x1f) << 3) |
|
|
||||||
((REV32(t[1]) & 0x1c) >> 2);
|
|
||||||
|
|
||||||
if (len < 4)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
data[1] = ((REV32(t[1]) & 0x03) << 6) |
|
|
||||||
((REV32(t[2]) & 0x1f) << 1) |
|
|
||||||
((REV32(t[3]) & 0x10) >> 4);
|
|
||||||
|
|
||||||
if (len < 5)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
data[2] = ((REV32(t[3]) & 0x0f) << 4) |
|
|
||||||
((REV32(t[4]) & 0x1e) >> 1);
|
|
||||||
|
|
||||||
if (len < 7)
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
data[3] = ((REV32(t[4]) & 0x01) << 7) |
|
|
||||||
((REV32(t[5]) & 0x1f) << 2) |
|
|
||||||
((REV32(t[6]) & 0x18) >> 3);
|
|
||||||
|
|
||||||
if (len < 8)
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
data[4] = ((REV32(t[6]) & 0x07) << 5) |
|
|
||||||
((REV32(t[7]) & 0x1f));
|
|
||||||
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
||||||
|
/*
|
||||||
|
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
|
||||||
|
* Decoding stops early when *str contains \0.
|
||||||
|
* Illegal encoded chars are assumed to decode to zero.
|
||||||
|
*
|
||||||
|
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
||||||
|
* to hold a trailing '\0' that is added (though *buf will usually
|
||||||
|
* contain full-binary data).
|
||||||
|
*
|
||||||
|
* return value : #bytes filled in buf (excluding \0)
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
unsigned char *q;
|
unsigned char *ubuf = (unsigned char *) buf;
|
||||||
size_t newsize;
|
int iout = 0; /* to-be-filled output byte */
|
||||||
size_t maxsize;
|
int iin = 0; /* next input char to use in decoding */
|
||||||
const char *p;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
base32_reverse_init();
|
base32_reverse_init ();
|
||||||
|
|
||||||
/* chars needed to decode slen */
|
/* Note: Don't bother to optimize manually. GCC optimizes
|
||||||
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
|
better(!) when using simplistic array indexing. */
|
||||||
/* encoded chars that fit in buf */
|
|
||||||
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;
|
while (1) {
|
||||||
for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
q += len;
|
|
||||||
slen -= BLKSIZE_ENC;
|
|
||||||
|
|
||||||
if (len < BLKSIZE_RAW)
|
|
||||||
break;
|
break;
|
||||||
|
ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
|
||||||
|
((REV32(str[iin + 1]) & 0x1c) >> 2);
|
||||||
|
iin++; /* 0 used up, iin=1 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 2 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0' ||
|
||||||
|
str[iin + 2] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
|
||||||
|
((REV32(str[iin + 1]) & 0x1f) << 1) |
|
||||||
|
((REV32(str[iin + 2]) & 0x10) >> 4);
|
||||||
|
iin += 2; /* 1,2 used up, iin=3 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |
|
||||||
|
((REV32(str[iin + 1]) & 0x1e) >> 1);
|
||||||
|
iin++; /* 3 used up, iin=4 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 2 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0' ||
|
||||||
|
str[iin + 2] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |
|
||||||
|
((REV32(str[iin + 1]) & 0x1f) << 2) |
|
||||||
|
((REV32(str[iin + 2]) & 0x18) >> 3);
|
||||||
|
iin += 2; /* 4,5 used up, iin=6 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |
|
||||||
|
((REV32(str[iin + 1]) & 0x1f));
|
||||||
|
iin += 2; /* 6,7 used up, iin=8 */
|
||||||
|
iout++;
|
||||||
}
|
}
|
||||||
*q = '\0';
|
|
||||||
|
|
||||||
return q - (unsigned char *) buf;
|
ubuf[iout] = '\0';
|
||||||
|
|
||||||
|
return iout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
231
src/base64.c
231
src/base64.c
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
|
||||||
|
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -19,15 +20,16 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#include "common.h"
|
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
#define BLKSIZE_RAW 3
|
#define BLKSIZE_RAW 3
|
||||||
#define BLKSIZE_ENC 4
|
#define BLKSIZE_ENC 4
|
||||||
|
|
||||||
|
/* Note: the "unofficial" char is last here, which means that the \377 pattern
|
||||||
|
in DOWNCODECCHECK1 ('Y' request) will properly test it. */
|
||||||
static const char cb64[] =
|
static const char cb64[] =
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
|
||||||
static unsigned char rev64[128];
|
static unsigned char rev64[256];
|
||||||
static int reverse_init = 0;
|
static int reverse_init = 0;
|
||||||
|
|
||||||
static int base64_encode(char *, size_t *, const void *, size_t);
|
static int base64_encode(char *, size_t *, const void *, size_t);
|
||||||
|
@ -36,8 +38,6 @@ static int base64_handles_dots();
|
||||||
static int base64_blksize_raw();
|
static int base64_blksize_raw();
|
||||||
static int base64_blksize_enc();
|
static int base64_blksize_enc();
|
||||||
|
|
||||||
#define REV64(x) rev64[(int) (x)]
|
|
||||||
|
|
||||||
static struct encoder base64_encoder =
|
static struct encoder base64_encoder =
|
||||||
{
|
{
|
||||||
"Base64",
|
"Base64",
|
||||||
|
@ -73,122 +73,133 @@ base64_blksize_enc()
|
||||||
return BLKSIZE_ENC;
|
return BLKSIZE_ENC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
inline static void
|
||||||
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
base64_reverse_init()
|
||||||
{
|
{
|
||||||
size_t newsize;
|
|
||||||
size_t maxsize;
|
|
||||||
unsigned char *s;
|
|
||||||
unsigned char *p;
|
|
||||||
unsigned char *q;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(buf, 0, *buflen);
|
|
||||||
|
|
||||||
/* how many chars can we encode within the buf */
|
|
||||||
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
|
|
||||||
/* how big will the encoded data be */
|
|
||||||
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
|
|
||||||
if (size % BLKSIZE_RAW) {
|
|
||||||
newsize += BLKSIZE_ENC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the buffer is too small, eat some of the data */
|
|
||||||
if (*buflen < newsize) {
|
|
||||||
size = maxsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = s = (unsigned char *) buf;
|
|
||||||
q = (unsigned char *)data;
|
|
||||||
|
|
||||||
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 += BLKSIZE_RAW;
|
|
||||||
p += BLKSIZE_ENC;
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
/* store number of bytes from data that was used */
|
|
||||||
*buflen = size;
|
|
||||||
|
|
||||||
return strlen(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DECODE_ERROR 0xffffffff
|
|
||||||
|
|
||||||
static int
|
|
||||||
decode_token(const unsigned char *t, unsigned char *data, size_t len)
|
|
||||||
{
|
|
||||||
if (len < 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
data[0] = ((REV64(t[0]) & 0x3f) << 2) |
|
|
||||||
((REV64(t[1]) & 0x30) >> 4);
|
|
||||||
|
|
||||||
if (len < 3)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
data[1] = ((REV64(t[1]) & 0x0f) << 4) |
|
|
||||||
((REV64(t[2]) & 0x3c) >> 2);
|
|
||||||
|
|
||||||
if (len < 4)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
data[2] = ((REV64(t[2]) & 0x03) << 6) |
|
|
||||||
(REV64(t[3]) & 0x3f);
|
|
||||||
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
|
||||||
{
|
|
||||||
unsigned char *q;
|
|
||||||
size_t newsize;
|
|
||||||
size_t maxsize;
|
|
||||||
const char *p;
|
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
unsigned char block[BLKSIZE_ENC];
|
|
||||||
int len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!reverse_init) {
|
if (!reverse_init) {
|
||||||
|
memset (rev64, 0, 256);
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
c = cb64[i];
|
c = cb64[i];
|
||||||
rev64[(int) c] = i;
|
rev64[(int) c] = i;
|
||||||
}
|
}
|
||||||
reverse_init = 1;
|
reverse_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* chars needed to decode slen */
|
|
||||||
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
|
|
||||||
/* encoded chars that fit in buf */
|
|
||||||
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; p += BLKSIZE_ENC) {
|
|
||||||
/* since the str is const, we unescape in another buf */
|
|
||||||
for (i = 0; i < BLKSIZE_ENC; i++) {
|
|
||||||
block[i] = p[i];
|
|
||||||
}
|
|
||||||
len = decode_token(block, (unsigned char *) q, slen);
|
|
||||||
q += len;
|
|
||||||
slen -= BLKSIZE_ENC;
|
|
||||||
|
|
||||||
if (len < BLKSIZE_RAW)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*q = '\0';
|
|
||||||
|
|
||||||
return q - (unsigned char *) buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
|
||||||
|
/*
|
||||||
|
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
|
||||||
|
*
|
||||||
|
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
||||||
|
* to hold the trailing '\0'.
|
||||||
|
*
|
||||||
|
* return value : #bytes filled in buf (excluding \0)
|
||||||
|
* sets *buflen to : #bytes encoded from data
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned char *udata = (unsigned char *) data;
|
||||||
|
int iout = 0; /* to-be-filled output char */
|
||||||
|
int iin = 0; /* one more than last input byte that can be
|
||||||
|
successfully decoded */
|
||||||
|
|
||||||
|
/* Note: Don't bother to optimize manually. GCC optimizes
|
||||||
|
better(!) when using simplistic array indexing. */
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)];
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size) {
|
||||||
|
iout--; /* previous char is useless */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[iout] = cb64[((udata[iin] & 0x03) << 4) |
|
||||||
|
((iin + 1 < size) ?
|
||||||
|
((udata[iin + 1] & 0xf0) >> 4) : 0)];
|
||||||
|
iin++; /* 0 complete, iin=1 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) |
|
||||||
|
((iin + 1 < size) ?
|
||||||
|
((udata[iin + 1] & 0xc0) >> 6) : 0)];
|
||||||
|
iin++; /* 1 complete, iin=2 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin >= size)
|
||||||
|
break;
|
||||||
|
buf[iout] = cb64[(udata[iin] & 0x3f)];
|
||||||
|
iin++; /* 2 complete, iin=3 */
|
||||||
|
iout++;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[iout] = '\0';
|
||||||
|
|
||||||
|
/* store number of bytes from data that was used */
|
||||||
|
*buflen = iin;
|
||||||
|
|
||||||
|
return iout;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REV64(x) rev64[(int) (x)]
|
||||||
|
|
||||||
|
static int
|
||||||
|
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
|
||||||
|
/*
|
||||||
|
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
|
||||||
|
* Decoding stops early when *str contains \0.
|
||||||
|
* Illegal encoded chars are assumed to decode to zero.
|
||||||
|
*
|
||||||
|
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
|
||||||
|
* to hold a trailing '\0' that is added (though *buf will usually
|
||||||
|
* contain full-binary data).
|
||||||
|
*
|
||||||
|
* return value : #bytes filled in buf (excluding \0)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned char *ubuf = (unsigned char *) buf;
|
||||||
|
int iout = 0; /* to-be-filled output byte */
|
||||||
|
int iin = 0; /* next input char to use in decoding */
|
||||||
|
|
||||||
|
base64_reverse_init ();
|
||||||
|
|
||||||
|
/* Note: Don't bother to optimize manually. GCC optimizes
|
||||||
|
better(!) when using simplistic array indexing. */
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |
|
||||||
|
((REV64(str[iin + 1]) & 0x30) >> 4);
|
||||||
|
iin++; /* 0 used up, iin=1 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |
|
||||||
|
((REV64(str[iin + 1]) & 0x3c) >> 2);
|
||||||
|
iin++; /* 1 used up, iin=2 */
|
||||||
|
iout++;
|
||||||
|
|
||||||
|
if (iout >= *buflen || iin + 1 >= slen ||
|
||||||
|
str[iin] == '\0' || str[iin + 1] == '\0')
|
||||||
|
break;
|
||||||
|
ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) |
|
||||||
|
(REV64(str[iin + 1]) & 0x3f);
|
||||||
|
iin += 2; /* 2,3 used up, iin=4 */
|
||||||
|
iout++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ubuf[iout] = '\0';
|
||||||
|
|
||||||
|
return iout;
|
||||||
|
}
|
||||||
|
|
2021
src/client.c
2021
src/client.c
File diff suppressed because it is too large
Load Diff
|
@ -23,9 +23,15 @@ void client_stop();
|
||||||
enum connection client_get_conn();
|
enum connection client_get_conn();
|
||||||
const char *client_get_raw_addr();
|
const char *client_get_raw_addr();
|
||||||
|
|
||||||
void client_set_nameserver(const char *cp);
|
void client_set_nameserver(const char *cp, int port);
|
||||||
void client_set_topdomain(const char *cp);
|
void client_set_topdomain(const char *cp);
|
||||||
void client_set_password(const char *cp);
|
void client_set_password(const char *cp);
|
||||||
|
void set_qtype(char *qtype);
|
||||||
|
char *get_qtype();
|
||||||
|
void set_downenc(char *encoding);
|
||||||
|
void client_set_selecttimeout(int select_timeout);
|
||||||
|
void client_set_lazymode(int lazy_mode);
|
||||||
|
void client_set_hostname_maxlen(int i);
|
||||||
|
|
||||||
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize);
|
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize);
|
||||||
int client_tunnel(int tun_fd, int dns_fd);
|
int client_tunnel(int tun_fd, int dns_fd);
|
||||||
|
|
18
src/common.c
18
src/common.c
|
@ -34,7 +34,8 @@
|
||||||
#else
|
#else
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#ifdef DARWIN
|
#ifdef DARWIN
|
||||||
#include <arpa/nameser8_compat.h>
|
#define BIND_8_COMPAT
|
||||||
|
#include <arpa/nameser_compat.h>
|
||||||
#endif
|
#endif
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
@ -332,3 +333,18 @@ errx(int eval, const char *fmt, ...)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int recent_seqno(int ourseqno, int gotseqno)
|
||||||
|
/* Return 1 if we've seen gotseqno recently (current or up to 3 back).
|
||||||
|
Return 0 if gotseqno is new (or very old).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 4; i++, ourseqno--) {
|
||||||
|
if (ourseqno < 0)
|
||||||
|
ourseqno = 7;
|
||||||
|
if (gotseqno == ourseqno)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
11
src/common.h
11
src/common.h
|
@ -34,12 +34,14 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#else
|
#else
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DNS_PORT 53
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
|
@ -72,6 +74,9 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
|
||||||
# define DONT_FRAG_VALUE 1
|
# define DONT_FRAG_VALUE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define T_UNSET 65432
|
||||||
|
/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */
|
||||||
|
|
||||||
struct packet
|
struct packet
|
||||||
{
|
{
|
||||||
int len; /* Total packet length */
|
int len; /* Total packet length */
|
||||||
|
@ -85,10 +90,14 @@ struct packet
|
||||||
struct query {
|
struct query {
|
||||||
char name[QUERY_NAME_SIZE];
|
char name[QUERY_NAME_SIZE];
|
||||||
unsigned short type;
|
unsigned short type;
|
||||||
|
unsigned short rcode;
|
||||||
unsigned short id;
|
unsigned short id;
|
||||||
struct in_addr destination;
|
struct in_addr destination;
|
||||||
struct sockaddr from;
|
struct sockaddr from;
|
||||||
int fromlen;
|
int fromlen;
|
||||||
|
unsigned short id2;
|
||||||
|
struct sockaddr from2;
|
||||||
|
int fromlen2;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum connection {
|
enum connection {
|
||||||
|
@ -119,4 +128,6 @@ void errx(int eval, const char *fmt, ...);
|
||||||
void warnx(const char *fmt, ...);
|
void warnx(const char *fmt, ...);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int recent_seqno(int , int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
401
src/dns.c
401
src/dns.c
|
@ -27,7 +27,8 @@
|
||||||
#else
|
#else
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#ifdef DARWIN
|
#ifdef DARWIN
|
||||||
#include <arpa/nameser8_compat.h>
|
#define BIND_8_COMPAT
|
||||||
|
#include <arpa/nameser_compat.h>
|
||||||
#endif
|
#endif
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
@ -38,6 +39,10 @@
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#include "read.h"
|
#include "read.h"
|
||||||
|
|
||||||
|
int dnsc_use_edns0 = 1;
|
||||||
|
|
||||||
|
#define CHECKLEN(x) if (buflen - (p-buf) < (x)) return 0
|
||||||
|
|
||||||
int
|
int
|
||||||
dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
|
dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
|
||||||
{
|
{
|
||||||
|
@ -45,6 +50,10 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
|
||||||
short name;
|
short name;
|
||||||
char *p;
|
char *p;
|
||||||
int len;
|
int len;
|
||||||
|
int ancnt;
|
||||||
|
|
||||||
|
if (buflen < sizeof(HEADER))
|
||||||
|
return 0;
|
||||||
|
|
||||||
memset(buf, 0, buflen);
|
memset(buf, 0, buflen);
|
||||||
|
|
||||||
|
@ -62,40 +71,150 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
|
||||||
|
|
||||||
switch (qr) {
|
switch (qr) {
|
||||||
case QR_ANSWER:
|
case QR_ANSWER:
|
||||||
header->ancount = htons(1);
|
|
||||||
header->qdcount = htons(1);
|
header->qdcount = htons(1);
|
||||||
|
|
||||||
name = 0xc000 | ((p - buf) & 0x3fff);
|
name = 0xc000 | ((p - buf) & 0x3fff);
|
||||||
|
|
||||||
putname(&p, sizeof(q->name), q->name);
|
/* Question section */
|
||||||
|
putname(&p, buflen - (p - buf), q->name);
|
||||||
|
|
||||||
|
CHECKLEN(4);
|
||||||
putshort(&p, q->type);
|
putshort(&p, q->type);
|
||||||
putshort(&p, C_IN);
|
putshort(&p, C_IN);
|
||||||
|
|
||||||
|
/* Answer section */
|
||||||
|
|
||||||
|
if (q->type == T_CNAME || q->type == T_A) {
|
||||||
|
/* data is expected to be like "Hblabla.host.name.com\0" */
|
||||||
|
|
||||||
|
char *startp;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
CHECKLEN(10);
|
||||||
|
putshort(&p, name);
|
||||||
|
if (q->type == T_A)
|
||||||
|
/* answer CNAME to A question */
|
||||||
|
putshort(&p, T_CNAME);
|
||||||
|
else
|
||||||
|
putshort(&p, q->type);
|
||||||
|
putshort(&p, C_IN);
|
||||||
|
putlong(&p, 0); /* TTL */
|
||||||
|
|
||||||
|
startp = p;
|
||||||
|
p += 2; /* skip 2 bytes length */
|
||||||
|
putname(&p, buflen - (p - buf), data);
|
||||||
|
CHECKLEN(0);
|
||||||
|
namelen = p - startp;
|
||||||
|
namelen -= 2;
|
||||||
|
putshort(&startp, namelen);
|
||||||
|
ancnt = 1;
|
||||||
|
} else if (q->type == T_MX || q->type == T_SRV) {
|
||||||
|
/* Data is expected to be like
|
||||||
|
"Hblabla.host.name.com\0Hanother.com\0\0"
|
||||||
|
For SRV, see RFC2782.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *mxdata = data;
|
||||||
|
char *startp;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
ancnt = 1;
|
||||||
|
while (1) {
|
||||||
|
CHECKLEN(10);
|
||||||
putshort(&p, name);
|
putshort(&p, name);
|
||||||
putshort(&p, q->type);
|
putshort(&p, q->type);
|
||||||
putshort(&p, C_IN);
|
putshort(&p, C_IN);
|
||||||
putlong(&p, 0);
|
putlong(&p, 0); /* TTL */
|
||||||
|
|
||||||
|
startp = p;
|
||||||
|
p += 2; /* skip 2 bytes length */
|
||||||
|
CHECKLEN(2);
|
||||||
|
putshort(&p, 10 * ancnt); /* preference */
|
||||||
|
|
||||||
|
if (q->type == T_SRV) {
|
||||||
|
/* weight, port (5060 = SIP) */
|
||||||
|
CHECKLEN(4);
|
||||||
|
putshort(&p, 10);
|
||||||
|
putshort(&p, 5060);
|
||||||
|
}
|
||||||
|
|
||||||
|
putname(&p, buflen - (p - buf), mxdata);
|
||||||
|
CHECKLEN(0);
|
||||||
|
namelen = p - startp;
|
||||||
|
namelen -= 2;
|
||||||
|
putshort(&startp, namelen);
|
||||||
|
|
||||||
|
mxdata = mxdata + strlen(mxdata) + 1;
|
||||||
|
if (*mxdata == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
ancnt++;
|
||||||
|
}
|
||||||
|
} else if (q->type == T_TXT) {
|
||||||
|
/* TXT has binary or base-X data */
|
||||||
|
char *startp;
|
||||||
|
int txtlen;
|
||||||
|
|
||||||
|
CHECKLEN(10);
|
||||||
|
putshort(&p, name);
|
||||||
|
putshort(&p, q->type);
|
||||||
|
putshort(&p, C_IN);
|
||||||
|
putlong(&p, 0); /* TTL */
|
||||||
|
|
||||||
|
startp = p;
|
||||||
|
p += 2; /* skip 2 bytes length */
|
||||||
|
puttxtbin(&p, buflen - (p - buf), data, datalen);
|
||||||
|
CHECKLEN(0);
|
||||||
|
txtlen = p - startp;
|
||||||
|
txtlen -= 2;
|
||||||
|
putshort(&startp, txtlen);
|
||||||
|
ancnt = 1;
|
||||||
|
} else {
|
||||||
|
/* NULL has raw binary data */
|
||||||
|
|
||||||
|
CHECKLEN(10);
|
||||||
|
putshort(&p, name);
|
||||||
|
putshort(&p, q->type);
|
||||||
|
putshort(&p, C_IN);
|
||||||
|
putlong(&p, 0); /* TTL */
|
||||||
|
|
||||||
|
datalen = MIN(datalen, buflen - (p - buf));
|
||||||
|
CHECKLEN(2);
|
||||||
putshort(&p, datalen);
|
putshort(&p, datalen);
|
||||||
|
CHECKLEN(datalen);
|
||||||
putdata(&p, data, datalen);
|
putdata(&p, data, datalen);
|
||||||
|
CHECKLEN(0);
|
||||||
|
ancnt = 1;
|
||||||
|
}
|
||||||
|
header->ancount = htons(ancnt);
|
||||||
break;
|
break;
|
||||||
case QR_QUERY:
|
case QR_QUERY:
|
||||||
header->qdcount = htons(1);
|
/* Note that iodined also uses this for forward queries */
|
||||||
header->arcount = htons(1);
|
|
||||||
|
|
||||||
|
header->qdcount = htons(1);
|
||||||
|
|
||||||
|
datalen = MIN(datalen, buflen - (p - buf));
|
||||||
putname(&p, datalen, data);
|
putname(&p, datalen, data);
|
||||||
|
|
||||||
|
CHECKLEN(4);
|
||||||
putshort(&p, q->type);
|
putshort(&p, q->type);
|
||||||
putshort(&p, C_IN);
|
putshort(&p, C_IN);
|
||||||
|
|
||||||
/* EDNS0 */
|
/* EDNS0 to advertise maximum response length
|
||||||
|
(even CNAME/A/MX, 255+255+header would be >512) */
|
||||||
|
if (dnsc_use_edns0) {
|
||||||
|
header->arcount = htons(1);
|
||||||
|
/*XXX START adjust indent 1 tab forward*/
|
||||||
|
CHECKLEN(11);
|
||||||
putbyte(&p, 0x00); /* Root */
|
putbyte(&p, 0x00); /* Root */
|
||||||
putshort(&p, 0x0029); /* OPT */
|
putshort(&p, 0x0029); /* OPT */
|
||||||
putshort(&p, 0x1000); /* Payload size: 4096 */
|
putshort(&p, 0x1000); /* Payload size: 4096 */
|
||||||
putshort(&p, 0x0000); /* Higher bits/edns version */
|
putshort(&p, 0x0000); /* Higher bits/edns version */
|
||||||
putshort(&p, 0x8000); /* Z */
|
putshort(&p, 0x8000); /* Z */
|
||||||
putshort(&p, 0x0000); /* Data length */
|
putshort(&p, 0x0000); /* Data length */
|
||||||
|
/*XXX END adjust indent 1 tab forward*/
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +225,21 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
|
||||||
|
|
||||||
int
|
int
|
||||||
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
|
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
|
||||||
|
/* Only used when iodined gets an NS type query */
|
||||||
|
/* Mostly same as dns_encode_a_response() below */
|
||||||
{
|
{
|
||||||
HEADER *header;
|
HEADER *header;
|
||||||
int len;
|
int len;
|
||||||
short name;
|
short name;
|
||||||
short topname;
|
short topname;
|
||||||
short nsname;
|
short nsname;
|
||||||
char *domain;
|
char *ipp;
|
||||||
int domain_len;
|
int domain_len;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
if (buflen < sizeof(HEADER))
|
||||||
|
return 0;
|
||||||
|
|
||||||
memset(buf, 0, buflen);
|
memset(buf, 0, buflen);
|
||||||
|
|
||||||
header = (HEADER*)buf;
|
header = (HEADER*)buf;
|
||||||
|
@ -137,52 +261,122 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
|
||||||
/* pointer to start of name */
|
/* pointer to start of name */
|
||||||
name = 0xc000 | ((p - buf) & 0x3fff);
|
name = 0xc000 | ((p - buf) & 0x3fff);
|
||||||
|
|
||||||
domain = strstr(q->name, topdomain);
|
domain_len = strlen(q->name) - strlen(topdomain);
|
||||||
if (domain) {
|
if (domain_len < 0 || domain_len == 1)
|
||||||
domain_len = (int) (domain - q->name);
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
if (strcasecmp(q->name + domain_len, topdomain))
|
||||||
/* pointer to start of topdomain */
|
return -1;
|
||||||
|
if (domain_len >= 1 && q->name[domain_len - 1] != '.')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* pointer to start of topdomain; instead of dots at the end
|
||||||
|
we have length-bytes in front, so total length is the same */
|
||||||
topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);
|
topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);
|
||||||
|
|
||||||
/* Query section */
|
/* Query section */
|
||||||
putname(&p, sizeof(q->name), q->name); /* Name */
|
putname(&p, buflen - (p - buf), q->name); /* Name */
|
||||||
|
CHECKLEN(4);
|
||||||
putshort(&p, q->type); /* Type */
|
putshort(&p, q->type); /* Type */
|
||||||
putshort(&p, C_IN); /* Class */
|
putshort(&p, C_IN); /* Class */
|
||||||
|
|
||||||
/* Answer section */
|
/* Answer section */
|
||||||
|
CHECKLEN(12);
|
||||||
putshort(&p, name); /* Name */
|
putshort(&p, name); /* Name */
|
||||||
putshort(&p, q->type); /* Type */
|
putshort(&p, q->type); /* Type */
|
||||||
putshort(&p, C_IN); /* Class */
|
putshort(&p, C_IN); /* Class */
|
||||||
putlong(&p, 0x3ea7d011); /* TTL */
|
putlong(&p, 3600); /* TTL */
|
||||||
putshort(&p, 5); /* Data length */
|
putshort(&p, 5); /* Data length */
|
||||||
|
|
||||||
/* pointer to ns.topdomain */
|
/* pointer to ns.topdomain */
|
||||||
nsname = 0xc000 | ((p - buf) & 0x3fff);
|
nsname = 0xc000 | ((p - buf) & 0x3fff);
|
||||||
|
CHECKLEN(5);
|
||||||
putbyte(&p, 2);
|
putbyte(&p, 2);
|
||||||
putbyte(&p, 'n');
|
putbyte(&p, 'n');
|
||||||
putbyte(&p, 's');
|
putbyte(&p, 's');
|
||||||
putshort(&p, topname); /* Name Server */
|
putshort(&p, topname); /* Name Server */
|
||||||
|
|
||||||
/* Additional data (A-record of NS server) */
|
/* Additional data (A-record of NS server) */
|
||||||
|
CHECKLEN(12);
|
||||||
putshort(&p, nsname); /* Name Server */
|
putshort(&p, nsname); /* Name Server */
|
||||||
putshort(&p, T_A); /* Type */
|
putshort(&p, T_A); /* Type */
|
||||||
putshort(&p, C_IN); /* Class */
|
putshort(&p, C_IN); /* Class */
|
||||||
putlong(&p, 0x3ea7d011); /* TTL */
|
putlong(&p, 3600); /* TTL */
|
||||||
putshort(&p, 4); /* Data length */
|
putshort(&p, 4); /* Data length */
|
||||||
|
|
||||||
/* ugly hack to output IP address */
|
/* ugly hack to output IP address */
|
||||||
domain = (char *) &q->destination;
|
ipp = (char *) &q->destination;
|
||||||
putbyte(&p, *domain++);
|
CHECKLEN(4);
|
||||||
putbyte(&p, *domain++);
|
putbyte(&p, *(ipp++));
|
||||||
putbyte(&p, *domain++);
|
putbyte(&p, *(ipp++));
|
||||||
putbyte(&p, *domain);
|
putbyte(&p, *(ipp++));
|
||||||
|
putbyte(&p, *ipp);
|
||||||
|
|
||||||
len = p - buf;
|
len = p - buf;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dns_encode_a_response(char *buf, size_t buflen, struct query *q)
|
||||||
|
/* Only used when iodined gets an A type query for ns.topdomain or www.topdomain */
|
||||||
|
/* Mostly same as dns_encode_ns_response() above */
|
||||||
|
{
|
||||||
|
HEADER *header;
|
||||||
|
int len;
|
||||||
|
short name;
|
||||||
|
char *ipp;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (buflen < sizeof(HEADER))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* pointer to start of name */
|
||||||
|
name = 0xc000 | ((p - buf) & 0x3fff);
|
||||||
|
|
||||||
|
/* Query section */
|
||||||
|
putname(&p, buflen - (p - buf), q->name); /* Name */
|
||||||
|
CHECKLEN(4);
|
||||||
|
putshort(&p, q->type); /* Type */
|
||||||
|
putshort(&p, C_IN); /* Class */
|
||||||
|
|
||||||
|
/* Answer section */
|
||||||
|
CHECKLEN(12);
|
||||||
|
putshort(&p, name); /* Name */
|
||||||
|
putshort(&p, q->type); /* Type */
|
||||||
|
putshort(&p, C_IN); /* Class */
|
||||||
|
putlong(&p, 3600); /* TTL */
|
||||||
|
putshort(&p, 4); /* Data length */
|
||||||
|
|
||||||
|
/* ugly hack to output IP address */
|
||||||
|
ipp = (char *) &q->destination;
|
||||||
|
CHECKLEN(4);
|
||||||
|
putbyte(&p, *(ipp++));
|
||||||
|
putbyte(&p, *(ipp++));
|
||||||
|
putbyte(&p, *(ipp++));
|
||||||
|
putbyte(&p, *ipp);
|
||||||
|
|
||||||
|
len = p - buf;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CHECKLEN
|
||||||
|
|
||||||
unsigned short
|
unsigned short
|
||||||
dns_get_id(char *packet, size_t packetlen)
|
dns_get_id(char *packet, size_t packetlen)
|
||||||
{
|
{
|
||||||
|
@ -195,6 +389,8 @@ dns_get_id(char *packet, size_t packetlen)
|
||||||
return ntohs(header->id);
|
return ntohs(header->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHECKLEN(x) if (packetlen - (data-packet) < (x)) return 0
|
||||||
|
|
||||||
int
|
int
|
||||||
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
|
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
|
||||||
{
|
{
|
||||||
|
@ -211,6 +407,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
|
||||||
int id;
|
int id;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
q->id2 = 0;
|
||||||
rv = 0;
|
rv = 0;
|
||||||
header = (HEADER*)packet;
|
header = (HEADER*)packet;
|
||||||
|
|
||||||
|
@ -232,65 +429,173 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
|
||||||
|
|
||||||
rlen = 0;
|
rlen = 0;
|
||||||
|
|
||||||
|
if (q != NULL)
|
||||||
|
q->rcode = header->rcode;
|
||||||
|
|
||||||
switch (qr) {
|
switch (qr) {
|
||||||
case QR_ANSWER:
|
case QR_ANSWER:
|
||||||
if(qdcount != 1 || ancount != 1) {
|
if(qdcount < 1) {
|
||||||
switch (header->rcode) {
|
/* We need a question */
|
||||||
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q != NULL)
|
if (q != NULL)
|
||||||
q->id = id;
|
q->id = id;
|
||||||
|
|
||||||
|
/* Read name even if no answer, to give better error message */
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
readname(packet, packetlen, &data, name, sizeof(name));
|
||||||
|
CHECKLEN(4);
|
||||||
readshort(packet, &data, &type);
|
readshort(packet, &data, &type);
|
||||||
readshort(packet, &data, &class);
|
readshort(packet, &data, &class);
|
||||||
|
|
||||||
|
/* if CHECKLEN okay, then we're sure to have a proper name */
|
||||||
|
if (q != NULL) {
|
||||||
|
/* We only need the first char to check it */
|
||||||
|
q->name[0] = name[0];
|
||||||
|
q->name[1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ancount < 1) {
|
||||||
|
/* DNS errors like NXDOMAIN have ancount=0 and
|
||||||
|
stop here. CNAME may also have A; MX/SRV may have
|
||||||
|
multiple results. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here type is still the question type */
|
||||||
|
if (type == T_NULL) {
|
||||||
|
/* Assume that first answer is what we wanted */
|
||||||
readname(packet, packetlen, &data, name, sizeof(name));
|
readname(packet, packetlen, &data, name, sizeof(name));
|
||||||
|
CHECKLEN(10);
|
||||||
readshort(packet, &data, &type);
|
readshort(packet, &data, &type);
|
||||||
readshort(packet, &data, &class);
|
readshort(packet, &data, &class);
|
||||||
readlong(packet, &data, &ttl);
|
readlong(packet, &data, &ttl);
|
||||||
readshort(packet, &data, &rlen);
|
readshort(packet, &data, &rlen);
|
||||||
|
|
||||||
rv = MIN(rlen, sizeof(rdata));
|
rv = MIN(rlen, sizeof(rdata));
|
||||||
rv = readdata(packet, &data, rdata, rv);
|
rv = readdata(packet, &data, rdata, rv);
|
||||||
|
if (rv >= 2 && buf) {
|
||||||
if(type == T_NULL && rv >= 2 && buf) {
|
|
||||||
rv = MIN(rv, buflen);
|
rv = MIN(rv, buflen);
|
||||||
memcpy(buf, rdata, rv);
|
memcpy(buf, rdata, rv);
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if ((type == T_A || type == T_CNAME) && buf) {
|
||||||
|
/* Assume that first answer is what we wanted */
|
||||||
|
readname(packet, packetlen, &data, name, sizeof(name));
|
||||||
|
CHECKLEN(10);
|
||||||
|
readshort(packet, &data, &type);
|
||||||
|
readshort(packet, &data, &class);
|
||||||
|
readlong(packet, &data, &ttl);
|
||||||
|
readshort(packet, &data, &rlen);
|
||||||
|
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
|
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
||||||
|
name[sizeof(name)-1] = '\0';
|
||||||
|
strncpy(buf, name, buflen);
|
||||||
|
buf[buflen - 1] = '\0';
|
||||||
|
rv = strlen(buf);
|
||||||
|
}
|
||||||
|
else if ((type == T_MX || type == T_SRV) && buf) {
|
||||||
|
/* We support 250 records, 250*(255+header) ~= 64kB.
|
||||||
|
Only exact 10-multiples are accepted, and gaps in
|
||||||
|
numbering are not jumped over (->truncated).
|
||||||
|
Hopefully DNS servers won't mess around too much.
|
||||||
|
*/
|
||||||
|
char names[250][QUERY_NAME_SIZE];
|
||||||
|
char *rdatastart;
|
||||||
|
short pref;
|
||||||
|
int i;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
memset(names, 0, sizeof(names));
|
||||||
|
|
||||||
|
for (i=0; i < ancount; i++) {
|
||||||
|
readname(packet, packetlen, &data, name, sizeof(name));
|
||||||
|
CHECKLEN(12);
|
||||||
|
readshort(packet, &data, &type);
|
||||||
|
readshort(packet, &data, &class);
|
||||||
|
readlong(packet, &data, &ttl);
|
||||||
|
readshort(packet, &data, &rlen);
|
||||||
|
rdatastart = data;
|
||||||
|
readshort(packet, &data, &pref);
|
||||||
|
|
||||||
|
if (type == T_SRV) {
|
||||||
|
/* skip weight, port */
|
||||||
|
data += 4;
|
||||||
|
CHECKLEN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pref % 10 == 0 && pref >= 10 &&
|
||||||
|
pref < 2500) {
|
||||||
|
readname(packet, packetlen, &data,
|
||||||
|
names[pref / 10 - 1],
|
||||||
|
QUERY_NAME_SIZE - 1);
|
||||||
|
names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always trust rlen, not name encoding */
|
||||||
|
data = rdatastart + rlen;
|
||||||
|
CHECKLEN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output is like Hname10.com\0Hname20.com\0\0 */
|
||||||
|
offset = 0;
|
||||||
|
i = 0;
|
||||||
|
while (names[i][0] != '\0') {
|
||||||
|
int l = MIN(strlen(names[i]), buflen-offset-2);
|
||||||
|
if (l <= 0)
|
||||||
|
break;
|
||||||
|
memcpy(buf + offset, names[i], l);
|
||||||
|
offset += l;
|
||||||
|
*(buf + offset) = '\0';
|
||||||
|
offset++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
*(buf + offset) = '\0';
|
||||||
|
rv = offset;
|
||||||
|
}
|
||||||
|
else if (type == T_TXT && buf) {
|
||||||
|
/* Assume that first answer is what we wanted */
|
||||||
|
readname(packet, packetlen, &data, name, sizeof(name));
|
||||||
|
CHECKLEN(10);
|
||||||
|
readshort(packet, &data, &type);
|
||||||
|
readshort(packet, &data, &class);
|
||||||
|
readlong(packet, &data, &ttl);
|
||||||
|
readshort(packet, &data, &rlen);
|
||||||
|
|
||||||
|
rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata));
|
||||||
|
if (rv >= 1) {
|
||||||
|
rv = MIN(rv, buflen);
|
||||||
|
memcpy(buf, rdata, rv);
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here type is the answer type (note A->CNAME) */
|
||||||
|
if (q != NULL)
|
||||||
|
q->type = type;
|
||||||
break;
|
break;
|
||||||
case QR_QUERY:
|
case QR_QUERY:
|
||||||
if (qdcount != 1) {
|
if (qdcount < 1) {
|
||||||
warnx("no question section in name query");
|
warnx("no question section in name query");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
||||||
name[sizeof(name)-1] = '\0';
|
name[sizeof(name)-1] = '\0';
|
||||||
|
CHECKLEN(4);
|
||||||
readshort(packet, &data, &type);
|
readshort(packet, &data, &type);
|
||||||
readshort(packet, &data, &class);
|
readshort(packet, &data, &class);
|
||||||
|
|
||||||
|
if (q == NULL) {
|
||||||
|
rv = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
strncpy(q->name, name, sizeof(q->name));
|
strncpy(q->name, name, sizeof(q->name));
|
||||||
q->name[sizeof(q->name) - 1] = '\0';
|
q->name[sizeof(q->name) - 1] = '\0';
|
||||||
q->type = type;
|
q->type = type;
|
||||||
|
|
|
@ -24,8 +24,11 @@ typedef enum {
|
||||||
QR_ANSWER = 1
|
QR_ANSWER = 1
|
||||||
} qr_t;
|
} qr_t;
|
||||||
|
|
||||||
|
extern int dnsc_use_edns0;
|
||||||
|
|
||||||
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_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);
|
int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain);
|
||||||
|
int dns_encode_a_response(char *buf, size_t buflen, struct query *q);
|
||||||
unsigned short dns_get_id(char *packet, size_t packetlen);
|
unsigned short dns_get_id(char *packet, size_t packetlen);
|
||||||
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
|
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,45 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "common.h"
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
build_hostname(char *buf, size_t buflen,
|
||||||
|
const char *data, const size_t datalen,
|
||||||
|
const char *topdomain, struct encoder *encoder, int maxlen)
|
||||||
|
{
|
||||||
|
int encsize;
|
||||||
|
size_t space;
|
||||||
|
char *b;
|
||||||
|
|
||||||
|
space = MIN(maxlen, buflen) - strlen(topdomain) - 8;
|
||||||
|
/* 8 = 5 max header length + 1 dot before topdomain + 2 safety */
|
||||||
|
|
||||||
|
if (!encoder->places_dots())
|
||||||
|
space -= (space / 57); /* space for dots */
|
||||||
|
|
||||||
|
memset(buf, 0, buflen);
|
||||||
|
|
||||||
|
encsize = encoder->encode(buf, &space, data, datalen);
|
||||||
|
|
||||||
|
if (!encoder->places_dots())
|
||||||
|
inline_dotify(buf, buflen);
|
||||||
|
|
||||||
|
b = buf;
|
||||||
|
b += strlen(buf);
|
||||||
|
|
||||||
|
/* move b back one step to see if the dot is there */
|
||||||
|
b--;
|
||||||
|
if (*b != '.')
|
||||||
|
*++b = '.';
|
||||||
|
b++;
|
||||||
|
/* move b ahead of the string so we can copy to it */
|
||||||
|
|
||||||
|
strncpy(b, topdomain, strlen(topdomain)+1);
|
||||||
|
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
|
unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc)
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
#ifndef _ENCODING_H_
|
#ifndef _ENCODING_H_
|
||||||
#define _ENCODING_H_
|
#define _ENCODING_H_
|
||||||
|
|
||||||
|
/* All-0, all-1, 01010101, 10101010: each 4 times to make sure the pattern
|
||||||
|
spreads across multiple encoded chars -> 16 bytes total.
|
||||||
|
Followed by 32 bytes from my /dev/random; should be enough.
|
||||||
|
*/
|
||||||
|
#define DOWNCODECCHECK1 "\000\000\000\000\377\377\377\377\125\125\125\125\252\252\252\252\201\143\310\322\307\174\262\027\137\117\316\311\111\055\122\041\141\251\161\040\045\263\006\163\346\330\104\060\171\120\127\277"
|
||||||
|
#define DOWNCODECCHECK1_LEN 48
|
||||||
|
|
||||||
struct encoder {
|
struct encoder {
|
||||||
char name[8];
|
char name[8];
|
||||||
int (*encode) (char *, size_t *, const void *, size_t);
|
int (*encode) (char *, size_t *, const void *, size_t);
|
||||||
|
@ -27,6 +34,7 @@ struct encoder {
|
||||||
int (*blocksize_encoded)(void);
|
int (*blocksize_encoded)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *, int);
|
||||||
int unpack_data(char *, size_t, char *, size_t, struct encoder *);
|
int unpack_data(char *, size_t, char *, size_t, struct encoder *);
|
||||||
int inline_dotify(char *, size_t);
|
int inline_dotify(char *, size_t);
|
||||||
int inline_undotify(char *, size_t);
|
int inline_undotify(char *, size_t);
|
||||||
|
|
84
src/iodine.c
84
src/iodine.c
|
@ -48,6 +48,8 @@ WSADATA wsa_data;
|
||||||
static char *__progname;
|
static char *__progname;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PASSWORD_ENV_VAR "IODINE_PASS"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sighandler(int sig)
|
sighandler(int sig)
|
||||||
{
|
{
|
||||||
|
@ -59,8 +61,8 @@ usage() {
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
||||||
"[-P password] [-m maxfragsize] [-z context] [-F pidfile] "
|
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
|
||||||
"[nameserver] topdomain\n", __progname);
|
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,20 +72,28 @@ help() {
|
||||||
|
|
||||||
fprintf(stderr, "iodine IP over DNS tunneling client\n");
|
fprintf(stderr, "iodine IP over DNS tunneling client\n");
|
||||||
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
|
||||||
"[-P password] [-m maxfragsize] [-z context] [-F pidfile] "
|
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
|
||||||
"[nameserver] topdomain\n", __progname);
|
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
|
||||||
|
fprintf(stderr, "Options to try if connection doesn't work:\n");
|
||||||
|
fprintf(stderr, " -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
|
||||||
|
fprintf(stderr, " -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n");
|
||||||
|
fprintf(stderr, " Base128, or (only for TXT:) Raw (default: autodetect)\n");
|
||||||
|
fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent DNS timeouts\n");
|
||||||
|
fprintf(stderr, " -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n");
|
||||||
|
fprintf(stderr, " -m max size of downstream fragments (default: autodetect)\n");
|
||||||
|
fprintf(stderr, " -M max size of upstream hostnames (~100-255, default: 255)\n");
|
||||||
|
fprintf(stderr, " -r to skip raw UDP mode attempt\n");
|
||||||
|
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
|
||||||
|
fprintf(stderr, "Other options:\n");
|
||||||
fprintf(stderr, " -v to print version info and exit\n");
|
fprintf(stderr, " -v to print version info and exit\n");
|
||||||
fprintf(stderr, " -h to print this help and exit\n");
|
fprintf(stderr, " -h to print this help and exit\n");
|
||||||
fprintf(stderr, " -f to keep running in foreground\n");
|
fprintf(stderr, " -f to keep running in foreground\n");
|
||||||
fprintf(stderr, " -r to skip raw UDP mode attempt\n");
|
|
||||||
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
|
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
|
||||||
fprintf(stderr, " -t dir to chroot to directory dir\n");
|
fprintf(stderr, " -t dir to chroot to directory dir\n");
|
||||||
fprintf(stderr, " -d device to set tunnel device name\n");
|
fprintf(stderr, " -d device to set tunnel device name\n");
|
||||||
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
|
|
||||||
fprintf(stderr, " -m maxfragsize, to limit size of downstream packets\n");
|
|
||||||
fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n");
|
fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n");
|
||||||
fprintf(stderr, " -F pidfile to write pid to a file\n");
|
fprintf(stderr, " -F pidfile to write pid to a file\n");
|
||||||
fprintf(stderr, "nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
|
fprintf(stderr, "nameserver is the IP number/hostname of the relaying nameserver. if absent, /etc/resolv.conf is used\n");
|
||||||
fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
|
fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -123,6 +133,9 @@ main(int argc, char **argv)
|
||||||
int autodetect_frag_size;
|
int autodetect_frag_size;
|
||||||
int retval;
|
int retval;
|
||||||
int raw_mode;
|
int raw_mode;
|
||||||
|
int lazymode;
|
||||||
|
int selecttimeout;
|
||||||
|
int hostname_maxlen;
|
||||||
|
|
||||||
nameserv_addr = NULL;
|
nameserv_addr = NULL;
|
||||||
topdomain = NULL;
|
topdomain = NULL;
|
||||||
|
@ -130,6 +143,8 @@ main(int argc, char **argv)
|
||||||
pw = NULL;
|
pw = NULL;
|
||||||
#endif
|
#endif
|
||||||
username = NULL;
|
username = NULL;
|
||||||
|
memset(password, 0, 33);
|
||||||
|
srand(time(NULL));
|
||||||
foreground = 0;
|
foreground = 0;
|
||||||
newroot = NULL;
|
newroot = NULL;
|
||||||
context = NULL;
|
context = NULL;
|
||||||
|
@ -140,6 +155,9 @@ main(int argc, char **argv)
|
||||||
max_downstream_frag_size = 3072;
|
max_downstream_frag_size = 3072;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
raw_mode = 1;
|
raw_mode = 1;
|
||||||
|
lazymode = 1;
|
||||||
|
selecttimeout = 4;
|
||||||
|
hostname_maxlen = 0xFF;
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
WSAStartup(req_version, &wsa_data);
|
WSAStartup(req_version, &wsa_data);
|
||||||
|
@ -156,7 +174,7 @@ main(int argc, char **argv)
|
||||||
__progname++;
|
__progname++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:")) != -1) {
|
while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) {
|
||||||
switch(choice) {
|
switch(choice) {
|
||||||
case 'v':
|
case 'v':
|
||||||
version();
|
version();
|
||||||
|
@ -191,12 +209,39 @@ main(int argc, char **argv)
|
||||||
autodetect_frag_size = 0;
|
autodetect_frag_size = 0;
|
||||||
max_downstream_frag_size = atoi(optarg);
|
max_downstream_frag_size = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'M':
|
||||||
|
hostname_maxlen = atoi(optarg);
|
||||||
|
if (hostname_maxlen > 255)
|
||||||
|
hostname_maxlen = 255;
|
||||||
|
if (hostname_maxlen < 10)
|
||||||
|
hostname_maxlen = 10;
|
||||||
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
context = optarg;
|
context = optarg;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
pidfile = optarg;
|
pidfile = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'T':
|
||||||
|
set_qtype(optarg);
|
||||||
|
break;
|
||||||
|
case 'O': /* not -D, is Debug in server */
|
||||||
|
set_downenc(optarg);
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
lazymode = atoi(optarg);
|
||||||
|
if (lazymode > 1)
|
||||||
|
lazymode = 1;
|
||||||
|
if (lazymode < 0)
|
||||||
|
lazymode = 0;
|
||||||
|
if (!lazymode)
|
||||||
|
selecttimeout = 1;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
selecttimeout = atoi(optarg);
|
||||||
|
if (selecttimeout < 1)
|
||||||
|
selecttimeout = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
@ -229,8 +274,9 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nameserv_addr) {
|
if (nameserv_addr) {
|
||||||
client_set_nameserver(nameserv_addr);
|
client_set_nameserver(nameserv_addr, DNS_PORT);
|
||||||
} else {
|
} else {
|
||||||
|
warnx("No nameserver found - not connected to any network?\n");
|
||||||
usage();
|
usage();
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
@ -247,7 +293,10 @@ main(int argc, char **argv)
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_set_selecttimeout(selecttimeout);
|
||||||
|
client_set_lazymode(lazymode);
|
||||||
client_set_topdomain(topdomain);
|
client_set_topdomain(topdomain);
|
||||||
|
client_set_hostname_maxlen(hostname_maxlen);
|
||||||
|
|
||||||
if (username != NULL) {
|
if (username != NULL) {
|
||||||
#ifndef WINDOWS32
|
#ifndef WINDOWS32
|
||||||
|
@ -259,8 +308,12 @@ main(int argc, char **argv)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(password) == 0)
|
if (strlen(password) == 0) {
|
||||||
|
if (NULL != getenv(PASSWORD_ENV_VAR))
|
||||||
|
snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
|
||||||
|
else
|
||||||
read_password(password, sizeof(password));
|
read_password(password, sizeof(password));
|
||||||
|
}
|
||||||
|
|
||||||
client_set_password(password);
|
client_set_password(password);
|
||||||
|
|
||||||
|
@ -276,17 +329,20 @@ main(int argc, char **argv)
|
||||||
signal(SIGINT, sighandler);
|
signal(SIGINT, sighandler);
|
||||||
signal(SIGTERM, sighandler);
|
signal(SIGTERM, sighandler);
|
||||||
|
|
||||||
|
fprintf(stderr, "Sending DNS queries for %s to %s\n",
|
||||||
|
topdomain, nameserv_addr);
|
||||||
|
|
||||||
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
|
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup2;
|
goto cleanup2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_get_conn() == CONN_DNS_NULL) {
|
if (client_get_conn() == CONN_RAW_UDP) {
|
||||||
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
|
fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Connection setup complete, transmitting data.\n");
|
||||||
|
|
||||||
if (foreground == 0)
|
if (foreground == 0)
|
||||||
do_detach();
|
do_detach();
|
||||||
|
|
||||||
|
|
1453
src/iodined.c
1453
src/iodined.c
File diff suppressed because it is too large
Load Diff
61
src/read.c
61
src/read.c
|
@ -125,6 +125,35 @@ readdata(char *packet, char **src, char *dst, size_t len)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain)
|
||||||
|
{
|
||||||
|
unsigned char *uc;
|
||||||
|
int tocopy;
|
||||||
|
int dstused = 0;
|
||||||
|
|
||||||
|
while (srcremain > 0)
|
||||||
|
{
|
||||||
|
uc = (unsigned char*) (*src);
|
||||||
|
tocopy = *uc;
|
||||||
|
(*src)++;
|
||||||
|
srcremain--;
|
||||||
|
|
||||||
|
if (tocopy > srcremain)
|
||||||
|
return 0; /* illegal, better have nothing */
|
||||||
|
if (tocopy > dstremain)
|
||||||
|
return 0; /* doesn't fit, better have nothing */
|
||||||
|
|
||||||
|
memcpy(dst, *src, tocopy);
|
||||||
|
dst += tocopy;
|
||||||
|
(*src) += tocopy;
|
||||||
|
srcremain -= tocopy;
|
||||||
|
dstremain -= tocopy;
|
||||||
|
dstused += tocopy;
|
||||||
|
}
|
||||||
|
return dstused;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
putname(char **buf, size_t buflen, const char *host)
|
putname(char **buf, size_t buflen, const char *host)
|
||||||
{
|
{
|
||||||
|
@ -212,3 +241,35 @@ putdata(char **dst, char *data, size_t len)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puttxtbin(char **buf, size_t bufremain, char *from, size_t fromremain)
|
||||||
|
{
|
||||||
|
unsigned char uc;
|
||||||
|
unsigned char *ucp = &uc;
|
||||||
|
char *cp = (char *) ucp;
|
||||||
|
int tocopy;
|
||||||
|
int bufused = 0;
|
||||||
|
|
||||||
|
while (fromremain > 0)
|
||||||
|
{
|
||||||
|
tocopy = fromremain;
|
||||||
|
if (tocopy > 252)
|
||||||
|
tocopy = 252; /* allow off-by-1s in caches etc */
|
||||||
|
if (tocopy + 1 > bufremain)
|
||||||
|
return -1; /* doesn't fit, better have nothing */
|
||||||
|
|
||||||
|
uc = tocopy;
|
||||||
|
**buf = *cp;
|
||||||
|
(*buf)++;
|
||||||
|
bufremain--;
|
||||||
|
bufused++;
|
||||||
|
|
||||||
|
memcpy(*buf, from, tocopy);
|
||||||
|
(*buf) += tocopy;
|
||||||
|
from += tocopy;
|
||||||
|
bufremain -= tocopy;
|
||||||
|
fromremain -= tocopy;
|
||||||
|
bufused += tocopy;
|
||||||
|
}
|
||||||
|
return bufused;
|
||||||
|
}
|
||||||
|
|
|
@ -21,11 +21,13 @@ int readname(char *, int, char **, char *, size_t);
|
||||||
int readshort(char *, char **, short *);
|
int readshort(char *, char **, short *);
|
||||||
int readlong(char *, char **, uint32_t *);
|
int readlong(char *, char **, uint32_t *);
|
||||||
int readdata(char *, char **, char *, size_t);
|
int readdata(char *, char **, char *, size_t);
|
||||||
|
int readtxtbin(char *, char **, size_t, char *, size_t);
|
||||||
|
|
||||||
int putname(char **, size_t, const char *);
|
int putname(char **, size_t, const char *);
|
||||||
int putbyte(char **, unsigned char);
|
int putbyte(char **, unsigned char);
|
||||||
int putshort(char **, unsigned short);
|
int putshort(char **, unsigned short);
|
||||||
int putlong(char **, uint32_t);
|
int putlong(char **, uint32_t);
|
||||||
int putdata(char **, char *, size_t);
|
int putdata(char **, char *, size_t);
|
||||||
|
int puttxtbin(char **, size_t, char *, size_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -426,7 +426,7 @@ read_tun(int tun_fd, char *buf, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
tun_setip(const char *ip, int netbits)
|
tun_setip(const char *ip, const char *remoteip, int netbits)
|
||||||
{
|
{
|
||||||
char cmdline[512];
|
char cmdline[512];
|
||||||
int netmask;
|
int netmask;
|
||||||
|
@ -458,7 +458,11 @@ tun_setip(const char *ip, int netbits)
|
||||||
"/sbin/ifconfig %s %s %s netmask %s",
|
"/sbin/ifconfig %s %s %s netmask %s",
|
||||||
if_name,
|
if_name,
|
||||||
ip,
|
ip,
|
||||||
|
#ifdef FREEBSD
|
||||||
|
remoteip, /* FreeBSD wants other IP as second IP */
|
||||||
|
#else
|
||||||
ip,
|
ip,
|
||||||
|
#endif
|
||||||
inet_ntoa(net));
|
inet_ntoa(net));
|
||||||
|
|
||||||
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
|
fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip);
|
||||||
|
|
|
@ -21,7 +21,7 @@ int open_tun(const char *);
|
||||||
void close_tun(int);
|
void close_tun(int);
|
||||||
int write_tun(int, char *, size_t);
|
int write_tun(int, char *, size_t);
|
||||||
ssize_t read_tun(int, char *, size_t);
|
ssize_t read_tun(int, char *, size_t);
|
||||||
int tun_setip(const char *, int);
|
int tun_setip(const char *, const char *, int);
|
||||||
int tun_setmtu(const unsigned);
|
int tun_setmtu(const unsigned);
|
||||||
|
|
||||||
#endif /* _TUN_H_ */
|
#endif /* _TUN_H_ */
|
||||||
|
|
38
src/user.c
38
src/user.c
|
@ -21,16 +21,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#ifdef WINDOWS32
|
#ifdef WINDOWS32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#else
|
#else
|
||||||
#include <err.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -83,19 +78,21 @@ init_users(in_addr_t my_ip, int netbits)
|
||||||
users[i].disabled = 0;
|
users[i].disabled = 0;
|
||||||
created_users++;
|
created_users++;
|
||||||
}
|
}
|
||||||
users[i].inpacket.len = 0;
|
users[i].active = 0;
|
||||||
users[i].inpacket.offset = 0;
|
/* Rest is reset on login ('V' packet) */
|
||||||
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;
|
|
||||||
users[i].conn = CONN_DNS_NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return created_users;
|
return created_users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
users_get_first_ip()
|
||||||
|
{
|
||||||
|
struct in_addr ip;
|
||||||
|
ip.s_addr = users[0].tun_ip;
|
||||||
|
return inet_ntoa(ip);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
users_waiting_on_reply()
|
users_waiting_on_reply()
|
||||||
{
|
{
|
||||||
|
@ -134,6 +131,11 @@ find_user_by_ip(uint32_t ip)
|
||||||
|
|
||||||
int
|
int
|
||||||
all_users_waiting_to_send()
|
all_users_waiting_to_send()
|
||||||
|
/* If this returns true, then reading from tun device is blocked.
|
||||||
|
So only return true when all clients have at least one packet in
|
||||||
|
the outpacket-queue, so that sending back-to-back is possible
|
||||||
|
without going through another select loop.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -144,8 +146,14 @@ all_users_waiting_to_send()
|
||||||
for (i = 0; i < USERS; i++) {
|
for (i = 0; i < USERS; i++) {
|
||||||
if (users[i].active && !users[i].disabled &&
|
if (users[i].active && !users[i].disabled &&
|
||||||
users[i].last_pkt + 60 > now &&
|
users[i].last_pkt + 60 > now &&
|
||||||
((users[i].outpacket.len == 0 && users[i].conn == CONN_DNS_NULL)
|
((users[i].conn == CONN_RAW_UDP) ||
|
||||||
|| users[i].conn == CONN_RAW_UDP)) {
|
((users[i].conn == CONN_DNS_NULL)
|
||||||
|
#ifdef OUTPACKETQ_LEN
|
||||||
|
&& users[i].outpacketq_filled < 1
|
||||||
|
#else
|
||||||
|
&& users[i].outpacket.len == 0
|
||||||
|
#endif
|
||||||
|
))) {
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
|
37
src/user.h
37
src/user.h
|
@ -19,6 +19,20 @@
|
||||||
|
|
||||||
#define USERS 16
|
#define USERS 16
|
||||||
|
|
||||||
|
#define OUTPACKETQ_LEN 4 /* Note: 16 users * 1 packet = 1MB */
|
||||||
|
/* Undefine to have no queue for packets coming in from tun device, which may
|
||||||
|
lead to massive dropping in multi-user situations with high traffic. */
|
||||||
|
|
||||||
|
#define DNSCACHE_LEN 4
|
||||||
|
/* Undefine to disable. Should be less than 18; also see comments in iodined.c */
|
||||||
|
|
||||||
|
|
||||||
|
#define QMEMPING_LEN 30
|
||||||
|
/* Max advisable: 64k/2 = 32000. Total mem usage: QMEMPING_LEN * USERS * 6 bytes */
|
||||||
|
|
||||||
|
#define QMEMDATA_LEN 15
|
||||||
|
/* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */
|
||||||
|
|
||||||
struct user {
|
struct user {
|
||||||
char id;
|
char id;
|
||||||
int active;
|
int active;
|
||||||
|
@ -28,18 +42,41 @@ struct user {
|
||||||
in_addr_t tun_ip;
|
in_addr_t tun_ip;
|
||||||
struct in_addr host;
|
struct in_addr host;
|
||||||
struct query q;
|
struct query q;
|
||||||
|
struct query q_sendrealsoon;
|
||||||
|
int q_sendrealsoon_new;
|
||||||
struct packet inpacket;
|
struct packet inpacket;
|
||||||
struct packet outpacket;
|
struct packet outpacket;
|
||||||
|
int outfragresent;
|
||||||
struct encoder *encoder;
|
struct encoder *encoder;
|
||||||
|
char downenc;
|
||||||
int out_acked_seqno;
|
int out_acked_seqno;
|
||||||
int out_acked_fragment;
|
int out_acked_fragment;
|
||||||
int fragsize;
|
int fragsize;
|
||||||
enum connection conn;
|
enum connection conn;
|
||||||
|
int lazy;
|
||||||
|
unsigned char qmemping_cmc[QMEMPING_LEN * 4];
|
||||||
|
unsigned short qmemping_type[QMEMPING_LEN];
|
||||||
|
int qmemping_lastfilled;
|
||||||
|
unsigned char qmemdata_cmc[QMEMDATA_LEN * 4];
|
||||||
|
unsigned short qmemdata_type[QMEMDATA_LEN];
|
||||||
|
int qmemdata_lastfilled;
|
||||||
|
#ifdef OUTPACKETQ_LEN
|
||||||
|
struct packet outpacketq[OUTPACKETQ_LEN];
|
||||||
|
int outpacketq_nexttouse;
|
||||||
|
int outpacketq_filled;
|
||||||
|
#endif
|
||||||
|
#ifdef DNSCACHE_LEN
|
||||||
|
struct query dnscache_q[DNSCACHE_LEN];
|
||||||
|
char dnscache_answer[DNSCACHE_LEN][4096];
|
||||||
|
int dnscache_answerlen[DNSCACHE_LEN];
|
||||||
|
int dnscache_lastfilled;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct user users[USERS];
|
extern struct user users[USERS];
|
||||||
|
|
||||||
int init_users(in_addr_t, int);
|
int init_users(in_addr_t, int);
|
||||||
|
const char* users_get_first_ip();
|
||||||
int users_waiting_on_reply();
|
int users_waiting_on_reply();
|
||||||
int find_user_by_ip(uint32_t);
|
int find_user_by_ip(uint32_t);
|
||||||
int all_users_waiting_to_send();
|
int all_users_waiting_to_send();
|
||||||
|
|
|
@ -29,7 +29,7 @@ get_resolvconf_addr()
|
||||||
rv = NULL;
|
rv = NULL;
|
||||||
|
|
||||||
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
|
if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)
|
||||||
err(1, "/etc/resolve.conf");
|
err(1, "/etc/resolv.conf");
|
||||||
|
|
||||||
while (feof(fp) == 0) {
|
while (feof(fp) == 0) {
|
||||||
fgets(buf, sizeof(buf), fp);
|
fgets(buf, sizeof(buf), fp);
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
/* This is the version of the network protocol
|
/* This is the version of the network protocol
|
||||||
It is usually equal to the latest iodine version number */
|
It is usually equal to the latest iodine version number */
|
||||||
#define VERSION 0x00000501
|
#define VERSION 0x00000502
|
||||||
|
|
||||||
#endif /* _VERSION_H_ */
|
#endif /* _VERSION_H_ */
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,32 @@ typedef unsigned int in_addr_t;
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
|
|
||||||
|
/* Missing from the mingw headers */
|
||||||
|
#ifndef DNS_TYPE_SRV
|
||||||
|
# define DNS_TYPE_SRV 33
|
||||||
|
#endif
|
||||||
|
#ifndef DNS_TYPE_TXT
|
||||||
|
# define DNS_TYPE_TXT 16
|
||||||
|
#endif
|
||||||
|
|
||||||
#define T_A DNS_TYPE_A
|
#define T_A DNS_TYPE_A
|
||||||
#define T_NS DNS_TYPE_NS
|
#define T_NS DNS_TYPE_NS
|
||||||
#define T_NULL DNS_TYPE_NULL
|
#define T_NULL DNS_TYPE_NULL
|
||||||
|
#define T_CNAME DNS_TYPE_CNAME
|
||||||
|
#define T_MX DNS_TYPE_MX
|
||||||
|
#define T_TXT DNS_TYPE_TXT
|
||||||
|
#define T_SRV DNS_TYPE_SRV
|
||||||
|
|
||||||
#define C_IN 1
|
#define C_IN 1
|
||||||
|
|
||||||
|
#define FORMERR 1
|
||||||
#define SERVFAIL 2
|
#define SERVFAIL 2
|
||||||
#define NXDOMAIN 3
|
#define NXDOMAIN 3
|
||||||
#define NOTIMP 4
|
#define NOTIMP 4
|
||||||
#define REFUSED 5
|
#define REFUSED 5
|
||||||
|
|
||||||
|
#define sleep(seconds) Sleep((seconds)*1000)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned id :16; /* query identification number */
|
unsigned id :16; /* query identification number */
|
||||||
/* fields in third byte */
|
/* fields in third byte */
|
||||||
|
|
|
@ -68,9 +68,10 @@ START_TEST(test_encode_query)
|
||||||
struct encoder *enc;
|
struct encoder *enc;
|
||||||
char *d;
|
char *d;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t enclen;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
len = sizeof(buf);
|
enclen = sizeof(resolv);
|
||||||
memset(&buf, 0, sizeof(buf));
|
memset(&buf, 0, sizeof(buf));
|
||||||
memset(&resolv, 0, sizeof(resolv));
|
memset(&resolv, 0, sizeof(resolv));
|
||||||
memset(&q, 0, sizeof(struct query));
|
memset(&q, 0, sizeof(struct query));
|
||||||
|
@ -80,12 +81,13 @@ START_TEST(test_encode_query)
|
||||||
enc = get_base32_encoder();
|
enc = get_base32_encoder();
|
||||||
|
|
||||||
*d++ = 'A';
|
*d++ = 'A';
|
||||||
enc->encode(d, &len, innerData, strlen(innerData));
|
enc->encode(d, &enclen, innerData, strlen(innerData));
|
||||||
d = resolv + strlen(resolv);
|
d = resolv + strlen(resolv);
|
||||||
if (*d != '.') {
|
if (*d != '.') {
|
||||||
*d++ = '.';
|
*d++ = '.';
|
||||||
}
|
}
|
||||||
strcpy(d, topdomain);
|
strcpy(d, topdomain);
|
||||||
|
len = sizeof(buf);
|
||||||
ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
|
ret = dns_encode(buf, len, &q, QR_QUERY, resolv, strlen(resolv));
|
||||||
len = sizeof(query_packet) - 1; /* Skip extra null character */
|
len = sizeof(query_packet) - 1; /* Skip extra null character */
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,12 @@
|
||||||
|
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
#include "base32.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
struct tuple
|
#define TUPLES 4
|
||||||
|
|
||||||
|
static struct tuple
|
||||||
{
|
{
|
||||||
char *a;
|
char *a;
|
||||||
char *b;
|
char *b;
|
||||||
|
@ -39,40 +43,53 @@ struct tuple
|
||||||
|
|
||||||
START_TEST(test_inline_dotify)
|
START_TEST(test_inline_dotify)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
char temp[1024];
|
char temp[1024];
|
||||||
char *b;
|
char *b;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (dottests[i].a) {
|
|
||||||
memset(temp, 0, sizeof(temp));
|
memset(temp, 0, sizeof(temp));
|
||||||
strcpy(temp, dottests[i].a);
|
strcpy(temp, dottests[_i].a);
|
||||||
b = temp;
|
b = temp;
|
||||||
inline_dotify(b, sizeof(temp));
|
inline_dotify(b, sizeof(temp));
|
||||||
|
|
||||||
fail_unless(strcmp(dottests[i].b, temp) == 0,
|
fail_unless(strcmp(dottests[_i].b, temp) == 0,
|
||||||
"'%s' != '%s'", temp, dottests[i].b);
|
"'%s' != '%s'", temp, dottests[_i].b);
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST(test_inline_undotify)
|
START_TEST(test_inline_undotify)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
char temp[1024];
|
char temp[1024];
|
||||||
char *b;
|
char *b;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (dottests[i].a) {
|
|
||||||
memset(temp, 0, sizeof(temp));
|
memset(temp, 0, sizeof(temp));
|
||||||
strcpy(temp, dottests[i].b);
|
strcpy(temp, dottests[_i].b);
|
||||||
b = temp;
|
b = temp;
|
||||||
inline_undotify(b, sizeof(temp));
|
inline_undotify(b, sizeof(temp));
|
||||||
|
|
||||||
fail_unless(strcmp(dottests[i].a, temp) == 0,
|
fail_unless(strcmp(dottests[_i].a, temp) == 0,
|
||||||
"'%s' != '%s'", temp, dottests[i].a);
|
"'%s' != '%s'", temp, dottests[_i].a);
|
||||||
i++;
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_build_hostname)
|
||||||
|
{
|
||||||
|
char data[256];
|
||||||
|
char buf[1024];
|
||||||
|
char *topdomain = "a.c";
|
||||||
|
int buflen;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(data); i++) {
|
||||||
|
data[i] = i & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
buflen = sizeof(buf);
|
||||||
|
|
||||||
|
for (i = 1; i < sizeof(data); i++) {
|
||||||
|
int len = build_hostname(buf, buflen, data, i, topdomain, get_base32_encoder(), sizeof(buf));
|
||||||
|
|
||||||
|
fail_if(len > i);
|
||||||
|
fail_if(strstr(buf, ".."), "Found double dots when encoding data len %d! buf: %s", i, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -83,8 +100,9 @@ test_encoding_create_tests()
|
||||||
TCase *tc;
|
TCase *tc;
|
||||||
|
|
||||||
tc = tcase_create("Encoding");
|
tc = tcase_create("Encoding");
|
||||||
tcase_add_test(tc, test_inline_dotify);
|
tcase_add_loop_test(tc, test_inline_dotify, 0, TUPLES);
|
||||||
tcase_add_test(tc, test_inline_undotify);
|
tcase_add_loop_test(tc, test_inline_undotify, 0, TUPLES);
|
||||||
|
tcase_add_test(tc, test_build_hostname);
|
||||||
|
|
||||||
return tc;
|
return tc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ START_TEST(test_users_waiting)
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 0);
|
fail_unless(users_waiting_on_reply() == 0);
|
||||||
|
|
||||||
|
users[3].conn = CONN_DNS_NULL;
|
||||||
users[3].q.id = 1;
|
users[3].q.id = 1;
|
||||||
|
|
||||||
fail_unless(users_waiting_on_reply() == 1);
|
fail_unless(users_waiting_on_reply() == 1);
|
||||||
|
@ -76,6 +77,7 @@ START_TEST(test_find_user_by_ip)
|
||||||
|
|
||||||
ip = inet_addr("127.0.0.1");
|
ip = inet_addr("127.0.0.1");
|
||||||
init_users(ip, 27);
|
init_users(ip, 27);
|
||||||
|
users[0].conn = CONN_DNS_NULL;
|
||||||
|
|
||||||
testip = (unsigned int) inet_addr("10.0.0.1");
|
testip = (unsigned int) inet_addr("10.0.0.1");
|
||||||
fail_unless(find_user_by_ip(testip) == -1);
|
fail_unless(find_user_by_ip(testip) == -1);
|
||||||
|
@ -104,15 +106,21 @@ START_TEST(test_all_users_waiting_to_send)
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
fail_unless(all_users_waiting_to_send() == 1);
|
||||||
|
|
||||||
|
users[0].conn = CONN_DNS_NULL;
|
||||||
users[0].active = 1;
|
users[0].active = 1;
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
fail_unless(all_users_waiting_to_send() == 1);
|
||||||
|
|
||||||
users[0].last_pkt = time(NULL);
|
users[0].last_pkt = time(NULL);
|
||||||
|
users[0].outpacket.len = 0;
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 0);
|
fail_unless(all_users_waiting_to_send() == 0);
|
||||||
|
|
||||||
|
#ifdef OUTPACKETQ_LEN
|
||||||
|
users[0].outpacketq_filled = 1;
|
||||||
|
#else
|
||||||
users[0].outpacket.len = 44;
|
users[0].outpacket.len = 44;
|
||||||
|
#endif
|
||||||
|
|
||||||
fail_unless(all_users_waiting_to_send() == 1);
|
fail_unless(all_users_waiting_to_send() == 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue