ICMPTX (IP-over-ICMP) HOWTOSee the current ICMPTX project home page.
ProblemYou're sitting in an airport or in a cafe, and people want your money for Internet access. They do allow ICMP traffic, though (i.e., you can ping machines on the Internet). Enters ICMPTX. (If you can't use ping, but you can issue name queries, use NSTX: IP-over-DNS.) There are several resources online to point you in the right direction, most notably Case of a wireless hack by Siim Põder. There is a similar, thoroughly undocument program called itun, a simple icmp tunnel that claims to do the same thing. Also, check out PingTunnel which is not IP-over-ICMP, but rather TCP-over-ICMP and, therefore, less useful.
Once you've followed these instructions, you basically have a remote proxy, providing you with access to the Internet. Communication between you and the remote proxy is over ICMP.
Note that these instructions play nicely with NSTX. You can run both on one proxy.
Keywordsicmptx, ip-over-icmp, firewall piercing, ping, icmp, tunnel, ifconfig, route, tun/tap, tun0.
Solution: icmptxThe tarball below is based on slightly buggy code I found through Siim Põder's page. I modified it ever so slightly, but I deserve no credit at all. Also, if you destroy everything or anything using this program, I am not responsible.
You'll need two copies of icmptx-0.01.tar.gz; one copy for the server, one copy for the client.
Download and compile. For example:
$ wget -O - http://thomer.com/icmptx/icmptx-0.01.tar.gz | tar xvfz - $ cd icmptx-0.01/ $ make
Proxy-side icmptx setupYou'll need a machine connected to the Internet to serve as your proxy. Make sure the proxy's firewall does not block ICMP traffic. If you can't simply ping the machine, icmptx will surely not work. Also, make sure your kernel supports TUN devices.
After compilation, run the icmptx server as root (assuming the proxy's end of the tunnel is going to be 10.0.1.1):
# ./icmptx -d 10.0.1.1Now verify you have a tun device:
# /sbin/ifconfig tun0 tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)Configure the tun device. Also, ensure the kernel doesn't intercept and reply to pings.
# /sbin/ifconfig tun0 mtu 65536 up 10.0.1.1 netmask 255.255.255.0 # echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
You need to enable forwarding on this server. I use iptables to implement masquerading. There are many HOWTOs about this (a simple one, for example). On Debian, the configuration file for iptables is in /var/lib/iptables/active. The relevant bit is:
*nat :PREROUTING ACCEPT [6:1596] :POSTROUTING ACCEPT [1:76] :OUTPUT ACCEPT [1:76] -A POSTROUTING -s 10.0.0.0/8 -j MASQUERADE COMMITRestart iptables:
/etc/init.d/iptables restartand enable forwarding:
echo 1 > /proc/sys/net/ipv4/ip_forwardYou can make sure this change (and the modification that disabled echo replies) are permanent by editing /etc/sysctl.conf, and adding:
Client-side icmptx setupThe client's kernel also needs to support TUN devices. Assuming your proxy's IP address is 126.96.36.199, run as root:
# ./icmptx -c 188.8.131.52
Now setup the tun device:
# /sbin/ifconfig tun0 mtu 65536 up 10.0.1.2 netmask 255.255.255.0
By running /sbin/route -n, figure out what your gateway is. It's the record with the "UG" Flags field. For example:
# /sbin/route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 wlan0 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 wlan0OK. So "192.168.1.1" is our gateway. Assuming your wireless network device is called "wlan0" (but it might well be "eth1", or whatever), run:
# /sbin/route del default # /sbin/route add -host 184.108.40.206 gw 192.168.1.1 dev wlan0 # /sbin/route add default gw 10.0.1.1 tun0Obviously, 220.127.116.11 should be replaced with your proxy's IP address.
If all is well, you should have Internet connection now. All traffic will be tunnelled through your proxy, via ICMP.
Problem: some connections seem to hangTry increasing the MTU size (that is the number that comes after "mtu" when invoking /sbin/ifconfig). Do this on both the client and the server. Running it with an MTU of 65536 seems to work fine (since, if I recall correctly, that is the maximum IP packet size). If you want to be dead sure that this is not the problem, crank it up.
This problem will only occur if you are behind a firewall that blocks echo reply packets (see TODO, below). More precisely, some firewalls will only allow a single echo reply for a single echo request. If the payload that needs to be stuffed into the ICMP packet is larger than the maximum size of an ICMP packet, you're out of luck. ssh will probably work, fetching small web pages might still work, but your only hope is increasing the MTU.
Bernd Michael Helm wrote in an email to me:
I managed to get around the *hanging connection* problem and speed up icmptx very much: just open a new console and start ping -f 10.0.1.1 (gateway node) so the client will flood the gateway with icmp requests (which will not be answered).
With this I was able to get stable connections and improve the http download speed to 210 kb/s which is the full physical bandwith of my internet connection.
Open problemsNote that I do not maintain the code. Please see the current ICMPTX project home page.
As of 2006, three things still needed to happen.
First, icmptx needs to be packaged (preferably for Debian), similar to the Debian nstx package.
Secondly, icmptx needs to deal with small MTUs. Right now you're in trouble if an IP packet is larger than the tun device's MTU. Setting the MTU to 65536 works fine for me, but we need to deal with the situation where that does not work (if intermediate routers refuse large ICMP packets, for example). To compound the problem, a lot of NATs seem to allow only one ICMP echo reply packet per ICMP echo request packet.
An idea that arose in a conversation with Bryan Ford is for the proxy to not only wrap the IP packet in the ICMP packet, but to include an additional header that contains the number of additional ICMP packets required to complete the current IP packet; call this number N. If the IP packet is small enough to fit in one ICMP packet, this number will be zero. If, however, the number is greater than zero, the client responds by sending N ICMP echo requests to the proxy. The proxy uses the N ICMP reply packets to transmit the remaining fragments of the IP packet. This solves both the MTU problem and avoids an intermediate NAT blocking multiple ICMP echo reply packets for one ICMP echo request packet.
Finally, I think the client needs to probe the proxy (similar to NSTX) for pending packets. Currently, only the client can initiate connections. The implementation of this may overlap with the previous point. (Note that John Plaxco seems to have resolved this problem, see the ICMPTX project home page.)