Iodine: DNS tunnel through closed WiFi

    Given: the complete absence of the Internet and the prominent WiFi hot-spot, in which they suggest entering 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 it.
    Task: to get the Internet (legal?) Method by tunneling it through DNS.
    Solution: linux + iodine + routing + NAT + squid, and all this is managed by a network manager.
    In the article: a description of the organization of a DNS tunnel using the iodine program, the nuances of organizing routing through the formed tunnel, a self-help helper for iodine and network manager.

    Lyrics: Fate brought me to the glorious island of Cyprus, which is famous for its P / pathos, frappe and the Internet, after which Russian opsos 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 (Сyta) would have mercy, but would end up drinking this frappe and reach out to me the filthy ADSL 4Mb / 768kbit for only € 151 (connection) + € 40 per month (for 4 megabits) !> _ <). The wait dragged on and stretched (as if the third week had already gone), and nearby was the glorious PrimeTel, who 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 one solution (in addition to hacking the WEP network of neighbors,

    Those who are interested in “howto” will find the solution later in the text, but for now let's start with the theory of the process.

    DNS tunneling


    If we have at hand a working DNS resolver (that is, a DNS server with recursion enabled), then it can go to our request for the IP address of the foobar.example.com host on .com, find out the address of the server responding to example there. com, go to example.com, find out who is responsible for foobar, and check with the specified server for details. It can recognize not only the IP address (A and AAAA records), but also a bunch of other information that can be stored in DNS. In particular:
    • MX - contains a line with a description of who to send mail to foobar.example.com
    • SRV - contains a line with information about which (new) services are and at 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 foobar.example.com domain).

    (here a 300kb lecture on what DNS is and how it works is lost).
    For our needs, a simple thing follows from this: we can ask the resolver to find out a little information from foobar.example.com. Resolver will go, find out, cache (if we request it again, then he will answer from the cache) and give it to us. If each time we request a different record (for a different name in this zone or a different type of record), then the resolver will obediently walk and resolve. Everytime. Note that to speed up the process, it will cache the information “who should I go to for such and such information” and the process will continue in one hop.

    Hurray, there is a channel for transmitting information from the server to us. 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 website address on the Internet, written in a column for the convenience of maintaining your friend's interest)

    Resolver will go to example.com and ask him about this address. And if the address is encoded message? (The crypto-elites began to stir - the message encoded in the name!)
    And if? .. Yes, exactly. The name contains an encrypted message. We found a method of transmitting information to the server. DNS server Or a fake server that pretends to be a DNS server, but actually listens to messages encrypted in the names and answers them with encrypted messages in response to requests.

    In other words, we get the data channel to the server and from the server to the client through the DNS resolver.

    The iodine utility is based on this principle. At the moment, according to my observations, this is the only really working application with a reasonable amount of customization.

    Iodine setup


    Configuring iodine comes down to three important steps.
    Prepare a domain zone.
    Start the server with the settings.
    Run the client with the settings.

    After that, we still 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.

    Setting up in one sentence: we need to delegate the domain zone to the future iodine server.
    Setting detail:
    We need to have access to administer the domain name. If the domain is delegated to our server - no problem, we can register a subdomain in the bind and delegate it to the iodine server. If we only have a “provider admin panel” - then the problem is much more complicated - you need to somehow register two subdomains, on one of them indicate NS, indicating 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 a j.example.com server as its NS, which has an IP address of 256.257.258.259.

    On a habr there is an article on how to solve a problem without control over a domain name. But for a real admin, not having control over at least some domain name would be strange, right?

    The second part is the server setup. It is quite simple, although there is an important detail: You can not run iodine on a server that runs a regular DNS server . The reason is simple - the port number is 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 simply will not reach our iodine). -c disables IP checking. I did not go into details, but it is better to have this thing working BEFORE you are left 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 starting iodine script, you can still add a password: iodined -P SECRET 10.99.99.1/24 -c i.example.com. You need to run from root so that iodined can add a tunnel. In principle, it can be added to rc.local, or just run with & after the name.

    Important: iodine / iodined versions must match. Strictly. Otherwise, there will be no connection. If on the desktop there is 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 install (no dependencies there).

    Starting the client as simple: iodine -P SECRET i.example.com.

    After the connection, we get a tunnel with the address through which the remote server is available (in our case - 10.99.99.1).

    You can use it.

    Can.

    To use.

    But as?

    Life at the end of the tunnel


    If we are interested in something other than the ability to make ssh to a remote server, then you have to do a bunch of everything else. Fasting 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, maintaining the “normal” route for DNS servers and overcoming problems with fragmented packets.

    If it’s rough, then there are three methods of using the resulting tunnel:
    • Routing and NAT on the server
    • socks-proxy
    • http-proxy (squid)


    We will analyze 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 of not your provider, which you use (in the negative sense, “use”), you get an MTU from 1344 (ideal scenario) to 740 bytes. In other words, packet fragmentation occurs. And packet fragmentation is very bad. This means that the likelihood of losing a package increases by 2-3 times, because if you lose the tail of the package, you lose it whole. The plus is the simplicity and elegance of the solution, as well as zero configuration for all software. Turned on and work. And some stupid CDN / IDCs on some sites block fragmented packets.

    On the other hand, we have the opportunity to establish a TCP session with a remote server (on which iodined) through the tunnel, in which case packets will go with the tunnel MTU size - no fragmentation. If we multiplex other tcp connections into this tunnel (at the flow level, i.e. sockets), then we will be able to communicate with the outside world packets of this size that suit us. However, here we are waiting for another setup. TCP is VERY disliked when the channel is bad. What is this expressed in? The longer TCP works on a channel with sudden losses and retries, the less it sends (assuming that packets are lost “due to congestion”). As a result, the speed of the multiplexed channel gradually drops, drops, drops ... If tunneling occurs through SSH, then the overhead from encryption is also superimposed on this. After about ten minutes, with poor DNS, passing TCP segments can be examined individually at tcpdump / wireshark. Another issue is the sudden delays with late replies, which lead to multiple dup ack (I don't know TCP so well to say if it's bad or really bad). However, I could not find the kernel settings for changing the timeout for sending the segment to TCP (except for one define in raws, but I did not manage to get to rebuilding my kernel under dns-tunnel - the Internet was connected, and the interest in the development of the issue fell off a bit ) Note that this is the only way that you can use it if it is better not to make any major changes on the remote server. In this case, we connect to the server with the command Another issue is the sudden delays with late replies, which lead to multiple dup ack (I don't know TCP so well to say if it's bad or really bad). However, I could not find the kernel settings for changing the timeout for sending the segment to TCP (except for one define in raws, but I did not manage to get to rebuilding my kernel under dns-tunnel - the Internet was connected, and the interest in the development of the issue fell off a bit ) Note that this is the only way that you can use it if it is better not to make any major changes on the remote server. In this case, we connect to the server with the command Another issue is the sudden delays with late replies, which lead to multiple dup ack (I don't know TCP so well to say if it's bad or really bad). However, I could not find the kernel settings for changing the timeout for sending the segment to TCP (except for one define in raws, but I did not manage to get to rebuilding my kernel under dns-tunnel - the Internet was connected, and the interest in developing the issue a bit disappeared ) Note that this is the only way that you can use it if it is better not to make any major changes on the remote server. In this case, we connect to the server with the command I could not find the kernel settings for changing the timeout for sending the segment to TCP (except for one define in raws, but I did not manage to get to rebuilding my kernel under dns-tunnel - the Internet was connected, and the interest in developing the issue a bit disappeared). Note that this is the only way that you can use it if it is better not to make any major changes on the remote server. In this case, we connect to the server with the command I could not find the kernel settings for changing the timeout for sending the segment to TCP (except for one define in raws, but I did not manage to get to rebuilding my kernel under dns-tunnel - the Internet was connected, and the interest in developing the issue a bit disappeared). Note that this is the only way that you can use it if it is better not to make any major changes on the remote server. In this case, we connect to the server with the commandssh -CD 1080 10.99.99.1, register 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, forcibly wrapping traffic from the application to socks-proxy. It is used like this: register the correct proxy address in /etc/tsocks.conf (127.0.0.1, port 1080, I remind you), and then run it tsocks my_net_appication app-arguments.

    There is another, more interesting method: we can raise squid on the server with iodined, tell it to listen on the iodined interface (or at all - but with acl to the tunnel addresses) and use unencrypted connections between the client and server. Thus, we firstly receive unfragmented packets, and secondly, we have many TCP sessions that are much less prone to degradation due to short-term lags of the DNS server.

    There are two downsides: firstly, we do not have compression (ssh can reap traffic, that is, all the transmitted headers in http turn out to be perfectly reaped), 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 the default gateway in the tunnel. Since squid is http-only, routing for everything else (IMAP mail, Jabber, etc) needs to be done through NAT.

    The problem is the organization of the default gateway. The essence of the problem is if our dns servers are not in the segment that was given to us (for example, we were given 5.10.10.10/24 and the DNS server was on 5.11.11.22 and 5.11.12.33), then if we change the default gateway, we will lose communication with DNS servers.

    Finding current DNS servers is also pretty boring. After some torment, I wrote a helper script: github.com/amarao/iodine-nm-helper

    It is very imperfect, and further improvements are welcome. But it is clearly more convenient than the iodine-client-start script (attached to the package with iodine), which does not know how to resolve DNS problems.

    The script is designed to use NetworkManger. Unfortunately, I did not master the restart of the script after updating the DHCP lease, so every time the lease is updated, the routing breaks and the script needs to be restarted.

    Performance and call quality


    Honorable lovers of freebies, I hasten to disappoint. DNS tunnels in real conditions (outside the laboratory) are very slow and are not a substitute for the normal Internet. Even the edge from tele2, as far as braking, is even faster. Below is a picture from a firebug when opening github. Behold and shed a tear - these are minutes of loading, everything is just that.



    The speed changes extremely unevenly. I spent some time studying what is happening with tcp when working through tunnels - due to the specific behavior, there are many retransmits and duplicate ack, that is, tcp cannot adapt to extremely uneven latency, when any packet can "dull" for a few seconds, and it can take several tens / hundreds of milliseconds.

    As a minimal “something instead of nothing” it can be used. For example, at the peak of the download (um ... a giant file of 1.6MB in size), I observed a speed of up to 8kb / s, but it quickly dropped to zero, and the process had to be restarted several times. If the good cyta doesn’t connect me in the next few days, then I will dig into the wilds of TCP a little deeper to find this treasured “retransmission timeout”.

    The problem with dhcp. PrimeTel has a short lease for DHCP. At the same time, when updating the lease, automatic updating of the routes also takes place, that is, our default gateway is replaced by Paimtelovsky. After scratching my head, I decided that the route to the network 0.0.0.0/0 (oops, divided by zero again) would be cooler. At the same time, there remains the problem of disappearing routes to DHCP, the solution of which I have not yet come up with (addresses are issued from different networks, each such network has its own gateway, so nailed routes are not suitable, but I considered it unethical and static to grab the address on another network's network) network usage).

    So the question, generally speaking, is open.

    The question of legality


    Probably the most difficult of. Formally, I get what I should not have received without paying many, many, many euros for this. 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 carry out any kind of hacking (for example, password guessing is already an obvious criminal offense, 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 a lawyer in court). In real life, all do not care. More precisely, the operator may not care if his DNS server is screwed up, but as long as it works - no problem. In light of the fantastic speeds that iodine shows, it’s not even possible to seriously discuss the “loss” of hundreds of kilobits of traffic. In principle, the most unpleasant for the operator in this case is the load on the DNS and spurious traffic in the wifi network.

    Settings


    (further boring for everyone except those who will tune).

    On the 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 routing through the tunnel)

    In firefox, set the http proxy through the tunnel server ip. Squid config

    :

    acl good src 10.99.99 / 24
    http_access allow good localhost
    http_access deny all

    Also popular now: