top image
home  /  pages  /  tech tips  /  contact about

ICMPTX (IP-over-ICMP) HOWTO

See the current ICMPTX project home page.

Problem

You'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.

Keywords

icmptx, ip-over-icmp, firewall piercing, ping, icmp, tunnel, ifconfig, route, tun/tap, tun0.

Solution: icmptx

The 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 setup

You'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.1
Now 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
COMMIT
Restart iptables:
/etc/init.d/iptables restart
and enable forwarding:
echo 1 > /proc/sys/net/ipv4/ip_forward
You can make sure this change (and the modification that disabled echo replies) are permanent by editing /etc/sysctl.conf, and adding:
net/ipv4/ip_forward=1
net/ipv4/icmp_echo_ignore_all=1

Client-side icmptx setup

The client's kernel also needs to support TUN devices. Assuming your proxy's IP address is 212.25.23.52, run as root:
# ./icmptx -c 212.25.23.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 wlan0
OK. 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 212.25.23.52 gw 192.168.1.1 dev wlan0
# /sbin/route add default gw 10.0.1.1 tun0
Obviously, 212.25.23.52 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 hang

Try 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 problems

Note 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.)

URL: http://thomer.com/icmptx/index.html
Copyright © 1994-2011 by Thomer M. Gil
Updated: 2009/02/17