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.
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):
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:
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.)
from http://thomer.com/icmptx/
-----------------------------------------
from http://web.archive.org/web/20160228091754/https://briteming.blogspot.com/2012/02/ping-tunnel.html
在mac上,编译ptunnel:
brew install libpcap
wget http://www.cs.uit.no/~daniels/PingTunnel/PingTunnel-0.72.tar.gz
tar zxvf PingTunnel-0.72.tar.gz
cd PingTunnel
make
(在PingTunnel目录下,就会生成可执行文件ptunnel)
Ptunnel is an application that allows you to reliably tunnel TCP
connections to a remote host using ICMP echo request and reply packets,
commonly known as ping requests and replies. At first glance, this might
seem like a rather useless thing to do, but it can actually come in
handy in some cases. The following example illustrates the main
motivation in creating ptunnel:
Setting: You're on the go, and stumble across an open wireless network.
The network gives you an IP address, but won't let you send TCP or UDP
packets out to the rest of the internet, for instance to check
your mail. What to do? By chance, you discover that the network will
allow you to ping any computer on the rest of the internet. With
ptunnel, you can utilize this feature to check your mail, or do other
things that require TCP.
Ptunnel is not a feature-rich tool by any means, but it does what it advertises. So here is what it can do:
Tunnel TCP using ICMP echo request and reply packets
Connections are reliable (lost packets are resent as necessary)
Handles multiple connections
Acceptable bandwidth (150 kb/s downstream and about 50 kb/s upstream
are the currently measured maximas for one tunnel, but with tweaking
this can be improved further)
Authentication, to prevent just anyone from using your proxy
So what do you need for all this to work?
One computer accessible on the internet that is not firewalled (or at least allows incoming ICMP packets)
A computer to act as the client (this will usually be your laptop, on the go..)
Root access, preferably on both computers
A posix-compliant OS, with libpcap (for packet capturing) and its
associated headers installed (typically available in a dev-package on
Ubuntu)
Or: Windows with mingw and WinPcap installed
Compiling the sources simply consists of running make. No ./configure,
make, make install, just make. On Windows, you'll need to run make
ptunnel.exe, but that's it. The resulting binary is called ptunnel. See the usage section below for info on running it.
This is a technical description of how ptunnel works. If you're not
interested in low-level networking details, you can skip this section.
It might help to read it either way, as it provides some insights into the situations where ptunnel doesn't work.
Ptunnel works by tunneling TCP connections over ICMP packets. In the following, we will talk about the proxy, the client and the destination.
The proxy is the "endpoint" for our ping packets, i.e. the computer
that we send the ping packets to. The client is the computer we're
trying to surf the net from, and the destination is the computer we
would normally be trying to access over TCP (such as a web site or an
ssh server somewhere).
So, in order to accomplish this, we need the ability to send and receive
ping packets. Many operating systems enable us to do this using
so-called raw sockets. Raw sockets is the preferred mechanism for
sending ICMP packets, and is used by both the proxy and the client.
Unfortunately, raw sockets require root, so there is a provision for
using standard datagram sockets if they are supported by the operating
system (Mac OS X 10.2 or later supports this, but Linux systems will
require root either way). Ptunnel supports this, however it is not
recommended for actual use. We'll get back to the reason later.
The client will perform all its communications using ICMP echo request
(ping) packets (type 8), whereas the proxy will use echo reply packets
(type 0). In theory, it is possible to have the proxy also use echo
request packets (and thus make it operate without root), but these
packets are not necessarily forwarded to the client beyond the host
network, so they are not used.
Figure 1. Networking setup.
The protocol
The proxy protocol uses four different message types combined with
sequence numbers and an acknowledgement field. A magic number is used to
differentiate our ping requests and replies from "usual" pings. The
general packet format (not including the IP or ICMP headers) can be seen
in the figure below.
Figure 2. The packet format used to exchange messages between client and proxy.
The IP and port fields are only used in packets from the client to the
proxy. They indicate where the client wants the received packets to be
forwarded (they are really only used once - when the proxy receives the
first message with state code kProxy_start).
The state code serves a dual purpose. First, it indicates what kind of
message is being received - either a message starting a new proxy
session (kProxy_start), a message containing data to be forwarded (kProto_data), an explicit acknowledgement of received packets (kProto_ack, a close message (kProto_close) or an authentication challenge/response (kProto_authenticate). Second, it indicates who sent the message: A message sent by the client will have the kUser_flag bit set, whereas a message sent by the proxy has the kProxy_flag
bit set. This is necessary since a ping request will cause the
operating system on the proxy computer to return its own echo reply,
which is identical to the packet we just sent to the proxy.
The ack and seq fields are tightly related. Modelled after the use of
acknowledgements in TCP, the ptunnel protocol places the sequence number
of the last packet received into the ack field of any outgoing message.
The seq field is a monotonically increasing 16-bit counter, that is
allowed to wrap around (ok, so I guess it's monotonic until it
wraps around). Whenever an outgoing packet has been waiting for an
acknowledgement too long, the peer will attempt to resend the first
packet not yet acknowledged.
The length field simply indicates the length of the data portion of the packet, and is 0 for all other state values than kProto_data. Finally the rsv field contains two bytes that are reserved (for now they serve as padding).
On receiving a kProxy_start request, a proxy will open a TCP
connection to the server given by the ip and port fields. As data comes
in over the TCP connection, the proxy will convert
the data to ICMP echo reply packets, and send them to the remote peer.
The client will do the same, except its packets will always be echo
request packets.
Authentication
As of version 0.60, Ping Tunnel supports authentication. The
authentication used is very simple, and works as follows. The user first
specifies a password or passphrase, which is then hashed using the MD5
algorithm (Ping Tunnel uses the implementation by L. Peter Deutsch,
available here. Note that the implementation is included with Ping Tunnel, so there is no need to download it separately).
Whenever a proxy receives a request for a new tunnel, it will respond
with an authentication challenge. The challenge consists of a timestamp
augmented with random data, totalling 32 bytes. The response is
calculated as follows (the + denotes string concatenation): md5(challenge + md5(password))
The proxy verifies the result by computing the same md5 sums, and then
comparing the two. If authentication succeeds, the proxy allows TCP
traffic to start flowing in either direction; if not, the connection is
torn down.
Handling multiple connections
The proxy handles multiple different connections by using the ICMP
identifier field. A client will randomly generate an identifier when it
starts a session, and the remote peer will use this identifier to
associate the packets with a connection. The mechanism is not foolproof,
but works acceptably as long as no two instances attempt to use the
same identifier (there is currently no mechanism for reporting such
errors).
The ICMP sequence number field is not used by ptunnel, mostly due to
fears that some routers might drop packets whose sequence number
repeats. Instead, a separate sequence number is used as part of the
ptunnel packet format (see above).
Send and receive windows
Ptunnel uses the simple concept of send and receive windows for
controlling the number of packets that can be in-flight at the same
time. The window is currently statically allocated at 64 packets, but
the number can be tweaked by modifying the ptunnel header file (yes, a
recompile is required). Increasing the window size will improve the
maximum potential bandwidth.
The send and receive windows are simply implemented as a set of circular
arrays, with pointers indicating the next available send/receive slot,
and the first non-acked packet.
Handling packet loss
Ptunnel handles packet loss by resending (presumably) lost packets. As
it sends packets, it will increment a sequence number. Both the client
and proxy maintain their own sequence number, and also a number
indicating the last sequence number acknowledged by the remote peer.
Whenever too much time (1.5 seconds) passes without a packet being
acknowledged, the peer will resend that packet.
Note that the peer will only resend the first missing packet. Once that packet has been acknowledged, it may
resend the next packet(s), depending on how many packets were
acknowledged. If the next few packets are acknowlegded as well, they are
removed from the send queue. It is not uncommon for one packet to get
lost, with most of the others making it through. This mechanism avoids
unecessary resends as much as possible.
Congestion control
Ptunnel currently does no explicit congestion control. It will send as
many ping packets as the window size allows, as slowly or as quickly as
it sees fit. This might be improved in the future, if it turns out to be
a problem (which is not at all unlikely..).
When things don't work
There are a number of situations where ptunnel will fail. They can briefly be put into the following categories:
Outgoing/incoming ping not allowed, or filtered by a gateway somewhere along the way
Operating system causing trouble
Probably some other failures as well ;)
We can't handle the first failure - if our packets are filtered before
we can get at them, there's little we can do. It is possible to deal
with the second scenario by using the packet capturing library to get
the packets before the OS sees them. This is necessary on Mac OS X, and
may be necessary on other platforms as well. The problem lies in that
the OS may occasionally not deliver ICMP packets to the raw socket we
have opened for sending and receiving. This happens when the ICMP packet
is an echo request (which the OS handles by itself) or when the ICMP
packet is a resend (for some weird reason). The workaround is to use
packet capture, however this tends to diminish bandwidth by quite a bit.
For this reason, you should always try to run the proxy without packet
capturing, and see if that works first. (This is the default mode.)
iPhone version
(requires a jailbroken iPhone/iPod touch running iPhone OS 3.0 or later
with libpcap installed through Cydia), by Rudolf Spring. (Added 29.
January 2010)
Ptunnel has so far been tested on a variety of configurations, including Linux Fedora Core 2 and Mac OS X 10.3.6 and above.
Debian users can install Ping Tunnel by adding the following to /etc/apt/sources.listdeb http://www.cti.ecp.fr/~beauxir5/debian binary/
deb-src http://www.cti.ecp.fr/~beauxir5/debian source/
And then run apt-get update followed by apt-get install ptunnel. A big thanks to Romain Beauxis for taking the time to create a Debian package for ptunnel!
As of version 0.70, ptunnel has support for Windows built-in, thanks to Mike Miller. You will need mingw and WinPcap(download here)
installed to compile on Windows. Please note that I don't use Windows,
so I can not provide support for compilation-specific issues regarding
the Windows port. Wouter van der Veer has been kind enough to provide a
compiled Windows binary on his website, which you can download here.
Client: ./ptunnel -p -lp -da -dp
[-c ] [-v ] [-f ]
[-u] [-x password] Proxy: ./ptunnel [-c ] [-v ] [-f ] [-u] [-x password]
The -p switch sets the address of the host on which the proxy
is running. A quick test to see if the proxy will work is simply to try
pinging this host - if you get replies, you should be able to make the
tunnel work.
The -lp, -da and -dp switches set the local
listening port, destination address and destination port. For instance,
to tunnel ssh connections from the client machine via a proxy running on
proxy.pingtunnel.com to the computer login.domain.com, the following
command line would be used: sudo ./ptunnel -p proxy.pingtunnel.com -lp 8000 -da login.domain.com -dp 22
An ssh connection to login.domain.com can now be established as follows: ssh -p 8000 localhost
If ssh complains about potential man-in-the-middle attacks, simply remove the offending key from the known_hosts file. The warning/error is expected if you have previously ssh'd to your local computer (i.e., ssh localhost), or you have used ptunnel to forward ssh connections to different hosts.
Of course, for all of this to work, you need to start the proxy on your
proxy-computer (we'll call it proxy.pingtunnel.com here). Doing this is very simple: sudo ./ptunnel
If you find that the proxy isn't working, you will need to enable packet
capturing on the main network device. Currently this device is assumed
to be an ethernet-device (i.e., ethernet or wireless). Packet capturing
is enabled by giving the -c switch, and supplying the device name to capture packets on (for instance eth0 or en1).
The same goes for the client. On versions of Mac OS X prior to 10.4
(Tiger), packet capturing must always be enabled (both for proxy and
client), as resent packets won't be received otherwise.
To protect yourself from others using your proxy, you can protect access to it with a password using the -x
switch. The password is never sent in the clear, but keep in mind that
it may be visible from tools like top or ps, which can display the
command line used to start an application.
Finally, the -u switch will attempt to run the proxy in unprivileged mode (i.e., no need for root access), and the -v
switch controls the amount of output from ptunnel. -1 indicates no
output, 0 shows errors only, 1 shows info messages, 2 gives more output,
3 provides even more output, level 4 displays debug info and level 5 displays absolutely everything, including the nasty details of sends and
receives. The -f switch allows output to be saved to a logfile.
Fixes an authentication bug that would manifest as hung
connections with protocols that send data from the client-side before
receiving data from the server-side. Thanks to StalkR for locating the
bug and fixing it.
Fixes a crash when attempting to enable packet-capture for
non-existing network devices. Thanks to Steffen Wendzel for the patch.
0.71 - 22. June 2009
Added security features and SELinux support, courtesy of Sebastien Raveau.
0.70 - 12. January 2009
Added rudimentary support for tunneling over UDP port 53. This may or may not be useful.
Added built-in support for compiling on Windows, thanks to Mike Miller.
Added syslog support, also courtesy of Mike Miller.
Experimental support for spoofing the source IP address. The source
address must be explicitly configured in the source code, and it might
not work (which is why it's experimental). To enable, define
kPT_add_iphdr to 1.
0.62 - Never released
Added many comments to the ptunnel header file.
Moved most include directives to the header file.
Fixed crash if proxy or destination hostnames could not be looked up.
0.61 - 26. May 2005
Noted that ptunnel now works without packet capturing on Mac OS X 10.4 Tiger.
Log files are now opened in append-mode (i.e., not truncated).
Fixed a bug that could cause ptunnel to crash if passwords shorter
than 16 characters were used (the overwhelming majority of passwords,
most likely!).
0.60 - 15. Apr 2005
Added authentication support, changing parts of the ptunnel protocol.
Added a manpage.
Added MD5 implementation by L. Peter Deutsch for authentication.
Moved declaration of a variable to allow ptunnel to compile cleanly on gcc 2.95 - thanks Choong!
Added error handling for proxy connections.
Fixed a problem with printing send/recv info. All verbosity levels should work now.
Updated contact info.
0.55 - 18. Feb 2005
Fixed a locking bug that would manifest itself when the maximum connection count on the proxy was reached.
Fixed ptunnel to compile correctly on 64-bit architectures (thanks
to Åsmund Grammeltvedt for pointing out the necessary changes!)
Added a new logging level (level 5). Level 4 no longer outputs send and receive info; for this info level 5 is necessary.
When libpcap is in use, the interface is no longer put in promiscous
mode. This has never been necessary, and also makes it impossible to
use ptunnel with more than one client on the same network.
Discovered a problem with pcap that would cause ptunnel to hang when
pcap was in use. This problem has not been resolved; the workaround is
to simply re-execute the client, or disable pcap if possible.
Added support for specifying a log file on the command line, using the -f switch.
0.54 - 1. Feb 2005
Fixed a byte-order bug (thanks Alfred!)
0.53 - 31. Jan 2005
Fixed a threading bug, and implemented support for limiting the maximum number of tunnels.
Thanks to Alfred Young for reporting and fixing the following bugs:
Fixed a bug with packets captured via libpcap, where the struct sockaddr wasn't properly zeroed.
Fixed a byte order bug in create_and_insert_proxy_desc.
Fixed a memory leak in remove_proxy_desc.
0.52 - 3. Jan 2005
Fixed a problem introduced by the ICMP ID field changes. The
proxy didn't retain the ID of the packets received from clients,
resulting in dropped ICMP packets at the router. This in turn lead to
the tunnel no longer working, depending on the strictness of the router.
This version fixes that problem.
Makefile is better now, thanks to Dries Verachtert.
0.51 - 2. Jan 2005
Fixed incorrect checksum calculation for resent packets.
Stopped relying on the ICMP packet's "built-in" ID field, and moved the information to the data portion of the packet.
Changed default verbosity level from debug to verbose.
Feedback
I'd be grateful for any feedback you may have - send it to me here:
daniels@cs.uit.no. I'm interested in hearing about bugs, suggestions and
naturally general criticism. If you find it useful, I'd love to know
about that too :)