The ancient art of tunneling, rediscovered. By Daniel [Originally appeared in 2600 - The Hacker Quarterly, Autumn 2005 issue.] 0. Intro This article will teach you how to use pay-per-use wireless networks for free. It works on many (but not all) networks (wireless or not), and is based on a very simple principle: Tunneling. I'm sure we have all seen how useful tunnels can be, be it for making our communications secure over an ssh tunnel or to spoof your IP. This article will show you how to tunnel TCP connections over ICMP packets. 1. Why tunnel over ICMP? I have been traveling a lot over the past year. During that time, I've come across many wireless networks, aimed specifically at internet-hungry travelers dying to check their mail. Of course, most of these networks will redirect you to a "we accept the following credit cards.."-page whenever you try to surf the web, and simply drop any other traffic (such as that on port 22). Remarkably, however, it turns out that many of these wireless networks allow you to ping remote hosts. This makes tunneling over ICMP a very attractive prospect, especially as they don't impose any particular size or content limitations on the ping packets. Alas, after a search of the net for a tool to do the job turned up nothing, I decided to write my own, called ptunnel (see below for link). The remaining part of this article will explain how ptunnel works, how you can set it up yourself, some situations where it might be useful, and finally some performance numbers. 2. The basics of ICMP messages. ICMP stands for Internet Control Message Protocol. It has many different message types, but the most well known are probably echo request/reply (ping) and time-to-live exceeded error messages (traceroute). We will build our tunnel using the echo request and reply packets, which look like this: [ IP header (20 bytes) ] [ Type | Code | Checksum ] [ Identifier | Seq. no ] [ Data..arbitrary length ] Type and code are 8-bit values, with type 0 indicating an echo reply, and type 8 indicating an echo request. The checksum, identifier and seq.no fields are 16-bit values. The checksum is the usual IP checksum, calculated over the entire ICMP packet, starting with the type field, with the checksum field set to zero for the calculation. For more details, see RFC 792 (ICMP). The nice thing about these packets is that they allow an arbitrarily long data chunk at the end, which makes them well suited for carrying our tunnel data. 3. Tunneling Tunneling naturally requires two parties, a proxy and a client. The proxy will be responsible for relaying the packets it receives over TCP to the host we wish to connect to, and the client will be our computer, accessing the net from some public wlan. We will use the identifier field of the ICMP packet to identify different tunnel sessions. The tunnel setup looks something like this: App <-- TCP --> [client] | ICMP tunnel | [proxy] <-- TCP --> Destination server The client receives incoming connections from clients (that would be your ssh client, for instance), and sets up a bidirectional tunnel with the proxy, using ICMP packets. The proxy deals with connecting to the destination server (for instance your ssh login server) using normal a TCP connection. The ICMP message exchange basically goes like this: 1. The client sends an echo request packet with some data to the proxy 2. The proxy responds with an echo reply packet The proxy's reply will be in addition to the automatically generated OS response (which contains the data we just sent to the proxy). Every packet includes a sequence number (different from the one in the ICMP header), an acknowledgement number, message type, and the destination's IP address and port. The message type simply specifies what kind of message we're dealing with: new tunnel request, data, acknowledgement or close. Most messages fall in the data and ack categories. Whenever the proxy receives data from the destination server, it is sent to the client as echo reply messages. We can't use echo request packets here, as they may not make it past the (possibly) NAT'ed network on the other end, causing our tunnel to break down. Similarly, the client will forward data from the connecting application using echo request packets. 3.1 Reliable tunneling In order to tunnel TCP over ICMP, we will need to re-implement TCP's reliability and message ordering, as ping packets have a nasty tendency to get lost or swapped a long their way. For reliability, the two peers maintain a record of the last packet acknowledged by the remote end, and will initiate packet resends of the first non-acked packet after some delay. The sequence numbers ensure that we maintain TCP's ordered message delivery. Finally, send and receive windows prevent the two peers from having too many non-acked packets in-flight, much in the way TCP uses a window size to constrain the amount of outstanding, non-acked data, although the window size used in ptunnel is static. 4. Surfing for free To use ptunnel, you need to have a computer somewhere that is ping-able from the rest of the internet. You'll also need root access on that computer, and it should run some flavour of Linux, Un*x or BSD. A similar setup is required for the client, although our only requirement for the network is that we can ping hosts outside the network (this can be easily verified by ping-ing your proxy host). All other protocols can be blocked. Before using ptunnel to surf from the client computer, you'll need to start ptunnel up on your proxy computer: [root@proxy]# ./ptunnel [-c ] The -c argument is optional, and specifies whether (and on which device) packet capturing is to be used. You should test without it in a controlled environment first, as using packet capturing on the proxy tends to diminish bandwidth quite a lot. I know Mac OS X requires it either way, but YMMV. Next, on your client computer, start ping tunnel as follows: [root@client]# ./ptunnel -p -lp 8000 -da somehost.somewhere.com -dp 22 [-c ] Again, the -c argument is optional. Here, we specify where our proxy runs (this is the host we will be pinging) using the -p switch, and a local listening port using -lp. Applications can now connect to your client computer on that port, and get their connections tunneled over ICMP. The -da and -dp switches specify the destination address and port. In this case I've specified port 22, as I want to tunnel an ssh connection over ICMP. To use the tunnel, I would simply do the following: [user@client] ssh -l user -p 8000 localhost user@localhost's password: Note that tunneling ssh makes the tunnel very versatile, as you can then tunnel additional TCP connections over TCP, adding encryption to the existing ICMP tunnel. This can be very useful when you're surfing in such a (presumably) hostile environment as this. 5. Where to use it In general, ping tunnel is only useful if you find yourself in a situation where you need to access the net but your only network access is blocked by port, protocol or content filters. Your employer may be monitoring/blocking TCP traffic, but not ICMP packets. Many wireless network providers charge a fee for using their networks, but fail to block outgoing and incoming ICMP packets; this is another area of potential use for ptunnel. I can't speak for the US, but in Europe many wlans fit the above description, including wlans on airports in Norway and Germany. I have tested ptunnel on some of these networks, and it does indeed fulfill its promises... Keep in mind though that you are _not_ surfing anonymously here - all your connections will appear to come from the proxy computer. It would also be trivial to detect the IP address of the proxy computer for the person(s) running the network your client is running on, as there would be a lot of "strange" ICMP traffic to and from that IP. 6. Performance Ptunnel performs well enough for my needs. In my testing, it has reached speeds of 150 kb/s down, and about 50 kb/s up. This can be further improved on by tuning various parts of the code (the ack intervals and window sizes are the most obvious candidates here, but gains may also be possible by tweaking the max size of the ping packets sent), but that is left as an exercise to the reader. The source code is available and freely distributable (see references). 7. And finally: It _can_ fail. Ptunnel isn't perfect, and there are some problems that it can't get around. If you can't ping your proxy computer, then you're out of luck. If the service provider you're using is doing some sort of filtering of incoming echo replies, you may also find yourself out of luck. Finally, I won't say anything as to the legality of this technique, so use it at your own risk. Keep in mind that tracing you to the proxy you are using is trivial. 8. References For more info on ICMP, check out RFC 792. Ptunnel's source code can be downloaded from this URL: http://www.cs.uit.no/~daniels/PingTunnel/. There are also some more in-depth technical details explained there, if you're interested.