It is given: the complete absence of the Internet and the rising WiFi hot-spot, in which they offer to enter a login-password. Or 3G, in which there is no Internet (because the money ran out), but there is a provider page with a proposal to give this money.
The task: to get the Internet (legal?) Method by tunneling it through DNS.
Solution: linux + iodine + routing + NAT + squid, and all this under the control of the network manager.
In the article: a description of the organization of the DNS tunnel through the iodine program, the nuances of routing through the resulting tunnel, a self-written assistant for the iodine and network manager.
Lyric: Destiny brought me to the glorious island of Cyprus, which is famous for its P / pathos, frappe and such an Internet, after which the Russian opsocks begin to look like angels in the flesh. In particular, the attempt to connect to the Internet ended with the expectation that the local provider (Cyta) would have mercy, they would stop drinking this frappe and the filthy ADSL 4Mb / 768kbit would reach me for only € 151 (connection) + € 40 per month (for 4 megabits !> _ <). Waiting was going on (as if the third week had already gone), and nearby was the glorious PrimeTel, which offered for € 4 / hour (172r / hour) to make me happy with the Internet right here and now through barely visible WiFi. I would even agree, but the access point was visible only on the balcony, and in the apartment the connection was unstable and was often lost. So there was only one solution left (apart from hacking into the neighbors' WEP network, which is absolutely criminal) to abuse the DNS service, which is donated, that is, free of charge, by PrimeTel for its unregistered subordinates.
Those who are interested in “howto” are the solution further in the text, but for now let's start with the theory of the process.
DNS tunneling
If we have a working DNS resolver at our hands (that is, a DNS server with recursion enabled), then we can go to .com at our request for the IP address of foobar.example.com and find out the address of the server that responds to the example. com, go to example.com, clarify who is responsible for foobar, and specify the details of the specified server. It can identify not only the IP address (A and AAAA records), but also a bunch of other information that can be stored in the DNS. In particular:
- MX - contains a string describing who to send mail for foobar.example.com
- SRV - contains a line with information about what (new) services are and what addresses - for example, it is used by jabber
- TXT - random information in text form. Most often it is used in practice for SPF (rules that describe who can send mail from the domain foobar.example.com).
(300kb lecture about what DNS is and how it works here is lost).For our needs, a simple thing follows from this: we can ask the resolver to get some information from foobar.example.com. The resolver will go, find out, cache (if we request it again, it will respond from the cache) and give it to us. If we each time request another record (for a different name in this zone or another type of record), then the resolver will obediently walk and resolve. Everytime. Note that in order to speed up the process, he will cache the information “to whom to go for such and such information” and the process will continue to happen in one hop.
')
Hurray, the channel of information transfer from the server to us is. And back? But we can ask to learn from example.com not foobar.example.com, but, for example,
0ahb282M-J2hbM-> M-nYM-VgdM-OJM-
CM-> M-nivlm4M-T5M-FM-p1M-t5M-
fM-uM-IvLM-HM-NM-aM-IM-eLAM-
BM-TM-qM-KM-UDM-NM-uM-] M-WM-
jM-DdbM-> Mk.QVM-lM-uM-`v
M-@3kGfM-fqFa.example.com
(This is one long URL of the site on the Internet, written in a column for the convenience of your friendsline to be unbreakable)
Resolver will go to example.com and ask him about this address. And if the address is encoded message? (Cryptoglossians are startled - a message encoded in the name!)
And if? .. Yes, exactly. The name contains an encrypted message. We found a method to send information to the server. DNS server. Or a fake server that pretends to be a DNS server, but actually listens to the messages encrypted in the names and responds to them with the encrypted messages in response to requests.
In other words, we receive a data transmission channel to the server and from the server to the client through a DNS resolver.
This principle is based on the work of the iodine utility. At the moment, according to my observations, this is the only really working application with a reasonable amount of settings.
Iodine setup
Setting up iodine comes down to three important steps.
Prepare the domain zone.
Start the server with the settings.
Run the client with the settings.
After that, we will have to learn how to use this channel, but this is the next chapter.
So let's start with the hard part - preparing the DNS.
Setup in one sentence: we need to delegate a domain zone to the future iodine-server.
Setup details:
We need to have access to the administration of the domain name. If the domain is delegated to our server - no problems, we can register a subdomain in the binde and delegate it to the iodine server. If we only have an “admin’s admin panel” - then the problem is much more complicated - you need to somehow register two subdomains, specify NS on one of them, pointing to the second subdomain, which, in turn, already has an A-record.
Confused? Let's do it again. Here is an example from my config bind:
i IN NS j
j IN A 256.257.258.259
It says: i.example.com has as NS an j.example.com server that has an IP address of 256.257.258.259.
On Habré there is
an article on how to solve the problem without controlling the domain name. But for a real admin, not having control over at least some domain name would be strange, right?
The second part is server setup. It is quite simple, although there is an important detail:
You can not run iodine on a server that runs a normal DNS server . The reason is simple - port number 53 / UDP without the right to change it.
Starting the server (iodined) is simple:
iodined 10.99.99.1/24 -c i.example.com
(you need to specify the name for which we specified NS, and not the name with the 'A' record. - if this is not done, then the resolver will not reach our iodine). -c disables IP checking. I did not go into details, but it’s better to have this thing working BEFORE you stay alone with someone else's DNS. The address at the beginning is the address in the tunnel (tuntap) that the server will have. Customers will receive the following addresses (.2, .3, etc.).
If iodine launch is scripted, you can also add a password:
iodined -P SECRET 10.99.99.1/24 -c i.example.com
. You need to run as root so iodined can add a tunnel. In principle, it can be added to rc.local, or simply run with & after the name.
Important: iodine / iodined versions must match. Strictly. Otherwise there will be no connection. If on the desktop one version of Linux, and on the server another (which is typical), it is better to install the version from the client on the server. Just download deb'ku from the repository and put (no dependencies there).
Starting a client is just plain:
iodine -P SECRET i.example.com
.
After connecting, we get a tunnel with the address through which the remote server is accessible (in our case - 10.99.99.1).
You can use.
Can.
Enjoy.
But as?
Life at the end of the tunnel
If we are interested in something other than the ability to do ssh on a remote server, then we have to do a lot of everything else. Post up to this point was just an artistic explanation of mana. But the practical use of the resulting tunnel requires us to solve problems with changing the gateway, preserving the “normal” route for DNS servers and overcoming problems with fragmented packets.
If roughly, then there are three methods of using the resulting tunnel:
- Routing and NAT on the server
- socks proxy
- http-proxy (squid)
Let's sort them all (and then we will discuss how to configure them). The main problem with routing is that the MTU of packets passing through the network is less than 1500 bytes. Much less. Depending on the DNS server not of your provider, which you use (in a negative sense, “use”), you get MTU from 1344 (ideal scenario) up to 740 bytes. In other words, packet fragmentation occurs. And packet fragmentation is very bad. This means that the probability of losing a package increases by a factor of 2-3, because if you lose the tail of the package, you lose it entirely. The advantage is the simplicity and elegance of the solution, as well as the zero configuration for the entire software. Turned on and work. And some stupid CDN / IDC on some sites block fragmented packets.
On the other hand, we have the ability to establish a TCP session with a remote server (which is iodined) through the tunnel, in which case the packets will come with the tunnel MTU size - no fragmentation. If in this tunnel you multiplex other tcp connections (at the stream level, that is, sockets), then we will be able to communicate with the outside world with packages of the size that suit us. However, here we are waiting for another setup. TCP doesn’t like it when the channel is bad. What is it expressed in? The longer TCP runs on a channel with sudden losses and retries, the less it sends (assuming packets are lost “due to congestion”). As a result, the speed of the multiplexed channel gradually drops, falls, falls ... In the event that tunneling occurs via SSH, then the overhead projector from encryption is superimposed on it. Somewhere in ten minutes with a bad DNS, passing TCP segments can be viewed individually in tcpdump / wireshark. Another problem is the sudden delays with late responses that lead to numerous dup ack (I don’t know TCP so well to say if this is bad or very bad). However, I did not manage to find the kernel settings to change the timeout for resending a segment to TCP (except for one define raw, but I did not have time to rebuild my kernel under dns-tunnel - the Internet was hooked up, and interest in the development of the question disappeared a bit ). Note that this is the only way that you can use if you don’t make any major changes on a remote server. In this case, we connect to the server with the command
ssh -CD 1080 10.99.99.1
, prescribe socks-proxy in the browser at 127.0.0.1:1080 and have access to the Internet. From the browser. Only. The rest of the software is configured accordingly.
In principle, for some programs, the tsocks utility can help, forcing traffic from an application to socks-proxy. It is used like this: set the correct proxy address (127.0.0.1, port 1080, I remind) in
tsocks my_net_appication app-arguments
, then run
tsocks my_net_appication app-arguments
.
There is another, more curious method: we can raise squid on the server with iodined, tell it to listen on the iodined interface (or at all - but with acl'koy at the tunnel addresses) and use unencrypted connections between the client and the server. Thus, we get firstly unfragmented packets, and secondly, we have a lot of TCP sessions, which are much less susceptible to degradation due to the short-term lags of the DNS server.
There are two minuses: firstly, we do not have compression (ssh is able to reap traffic, that is, all the transmitted headers in http turn out to be excellent), and secondly, ssl passes “as is” or does not pass at all.
Life at the beginning of the tunnel: iodine-mn-helper
Another problem is configuring a default gateway in a tunnel. Since squid is http-only, routing for everything else (mail via IMAP, Jabber, etc) must be done via NAT.
The problem is the organization of the default gateway. The essence of the problem is that if our dns servers are not in the segment given to us (for example, they gave us 5.10.10.10/24, but DNS servers in 5.11.11.22 and 5.11.12.33), then if we change the default gateway, we will lose connection to DNS servers.
Determining the current DNS servers is also pretty boring. After some torment, I wrote a script helper:
github.com/amarao/iodine-nm-helperIt is very imperfect, and further improvements are welcome. But it is clearly more convenient than the iodine-client-start script (included with the iodine package), which cannot resolve problems with DNS.
The script is designed to use NetworkManger'a. Unfortunately, I didn’t master the repeated self-restart of the script after renewing the DHCP lease, so every time the rent is updated, the routing breaks down and the script needs to be restarted.
Productivity and quality of communication
Honorable lovers of freebies, I hasten to disappoint. DNS tunnels in real conditions (outside the lab) are very slow and are not a replacement for the normal Internet. Even edge from tele2, so far as the brake, and then faster. Below is a picture from firebug when opening github. Behold and shed tears - these are the minutes of loading, everything is exactly that.

The speed varies extremely unevenly. I spent some time studying what was happening with tcp when working through tunnels - due to the specific behavior, there are a lot of retransmitters and duplicate ack'ov, that is, tcp can not adapt to extremely uneven latency, when any package can "blunt" for a few seconds, or it may take a few tens / hundreds of milliseconds.
As a minimal “something instead of nothing” it can be used. For example, at the peak of download'a (uh ... giant file in 1.6Mb in size) I watched the speed up to 8kb / s, but it quickly fell to zero, and the process had to be restarted several times. If the good cyta doesn’t connect me in the coming days, then I will dig into the jungle of TCP a little deeper to find this cherished “retransmission timeout”.
The problem with dhcp. In PrimeTel, DHCP has a small lease term. At the same time, when updating the lease, the automatic update of the routes takes place, that is, our default gateway is replaced with paymtelovsky. Scratching the back of my head, I decided that the route to the network 0.0.0.0/0 (oops, divided by zero again) would be better. At the same time, there remains the problem of missing routes to DHCP, which I haven’t yet come up with solutions (addresses are issued from different networks, each such network has its own gateway, so routes nailed with nails are not suitable, and I consider the address in a foreign network to be static as unethical and breaking the rules use the network).
So the question, generally speaking, is open.
Question of legality
Probably the most difficult of all. Formally, I get what I should not have received without paying for many, many, many euros. On the other hand, the WiFi hotspot operator opened access to its DNS servers voluntarily and consciously. How exactly I use the service is already my problem, it is important that I do not perform any kind of hacking (for example, selecting a password is already an obvious criminal act, unauthorized access to the computer system).
I believe that this issue is in the gray zone (that is, the point of view depends on the skill of the lawyer in court). In real life, everyone doesn't care. More precisely, the operator may not care if his DNS servers come on, but while it works, no problem. In the light of the fantastic speeds that iodine shows, seriously discussing the “loss” of hundreds of kilobits of traffic does not even work. In principle, the most unpleasant for the operator in this case is the load on the DNS and parasitic traffic on the wifi network.
Settings
(further boring for everyone except those who will customize).
On server:
sysctl net.ipv4.ip_forward = 1
iptables -t nat -A POSTROUTING -s 10.99.99.0/24 -j MASQUERADE
iodined -P SECRET 10.99.99.1/24 -c i.example.com
On the client:
vim /etc/iodine-nm-helper.conf (add settings)
./iodine-nm-helper
(the script will correct the routing through the tunnel)
In firefox, set HTTP proxies via the tunnel server’s ip.
Squid config:
acl good src 10.99.99 / 24
http_access allow good localhost
http_access deny all