Total Pageviews

Friday 18 September 2015

手动创建ICMP Tunnel,实现VPN上网

其实这是一篇讲解利用中国移动CMWAP的一些特性来实现免费上网的博文,但是没有以这个为标题,因为
1、用的是2G的EDGE网络,跟2G手机上网一样,速度有限.
2、各地区的移动设备有差别,例如在广州,这种方法行不通。但是广州的移动Wifi是可以通过UDP建立VPN来免费使用的。
3、不想吸引太多人的注意。
我见过很多公共网络都对UDP和TCP有不少限制,以致于我们不能自由地访问互联网。为了摆脱这种束缚,很多人都为此付出了很多努力,例如各种代理软件,各种隧道,各种VPN等。本文介绍的是一种比较罕见的ICMP隧道方式建立VPN。
背景
一年前,因为在县城里没有网络使用,又不想晚上跑到外面上,所以经常使用笔记本连接手机的GPRS网络来上网。打开一些网页或者聊天工具之类的,网 速的快慢并不是很重要。但是流量有限,当时开通了300MB的套餐也很快被消耗尽了。有一次,在Ubuntu下创建了一个cmwap网络,cmwap是需 要设置代理IP为10.0.0.172才能上网的。但是奇怪的是,我竟然可以ping通我自己博客服务器的IP。所以我想cmwap对外网IP的访问只是 限制了TCP和UDP类型的数据包进出而已。
为了验证我的想法是否正确,我在网上查找到了一些现成的Ping Tunnel工具,例如ptunnel。ptunnel至今还可以使用,但是问题很多,
1、ptunnel只支持TCP。
2、我使用了ptunnel之后,我ping不了自己的服务器了。显然ptunnel截获了所有ping包。(或者我用的版本太低?)
3、速度不稳定,可能是因为自己实现的可靠协议不是很完善?
用cmwap连接后,我使用ptunnel从我博客上下载一个5MB大小的文件。然后用手机查询流量,发现没有少。
由此说明,移动的cmwap是不计算ping的流量的。同时可以大胆猜测,流量计费功能应该是在10.0.0.172的代理服务器上进行的。这就是为何访问移动的一些服务(例如飞信网站)不会收流量费的原因。
我在国内似乎还没有搜索到有文章关于这方面的介绍。同时我在广州用cmwap连接后,无法发送ping包,难道是这个漏洞修补了?有兴趣的朋友可以 在自己的地区测试一下。先把连接方式更改为cmwap,然后连上后,ping一下8.8.8.8,看是否收到pong!!!如果能收到,恭喜!你可以利用 此特性免费上网。(另外,移动的路由很多,每次连接后得到的IP都不一样,路由也不一定一样。多换几次IP,可以得到能够ping的路由。——2012年 1月29日补充)
我发现这个问题后本来打算发博文的,后来不知道为何忘记了。只是偶尔跟身边一些朋友说了一下。
原理
回到主题上!
前段时间使用UDP隧道建立了一个VPN,把我学校里的一个VPS跟美国的VPS接入了同一个网络。参考了这篇文章《SSH_VPN》,有兴趣的同学可以看一下如何使用系统工具手动建立一个VPN。
这次要做的是,让从笔记本输出的IP包,使用ICMP协议封装后,像ping包一样发送到我的服务器,然后我的服务器解除ICMP的封装,把得到的 IP包写入本地路由。接着,把捕获到的发送给笔记本的IP包,使用ICMP封装,像pong包(ping的reply)一样发送到我的笔记本。到达笔记本 之后,接触ICMP封装,把得到的IP包写入本地路由。这样就在两个机器之间建立了点对点网络了。在此基础上,使用ip,iptables命令设置一下规 则,就建立了一个VPN。
模拟一个网页请求流程,
1、Firefox在笔记本发出一个请求。
2、内核使用默认路由发送这个请求的IP包。
3、因为默认路由的设备设置的是tun0,所以被tunnel程序捕获。
4、tunnel程序读取ip包后,用icmp封装,发送到远程vps。
5、icmp无障碍地通过cmwap网络,发送到远程vps上。
6、远程vps收到后,被服务器端的tunnel程序捕获(tunnel程序捕获所有的icmp数据包)。
7、tunnel程序读取icmp包,获取里面的ip包,写入到本地网络中。
8、因为通过iptables设置了nat,所以该ip包的源地址被改为vps ip后,发送到了所请求的服务器上。
9、一个IP包从请求的服务器上返回到vps,经过nat后,进入tunnel程序建立的网络,被tunnel程序捕获。
10、tunnel程序读取ip包后,用icmp封装,发送到笔记本。
11、icmp回应包无障碍地通过cmwap网络,发送到笔记本上。
12、笔记本接收到该icmp包,被笔记本上的tunnel程序捕获。
13、tunnel程序读取icmp包,获取里面的ip包,写入到本地网络中。
14、内核得到这个ip包,通知指定的应用程序响应。
15、Firefox收到了回应。
很详细吧!!!完整的工作流程就是这样。但关键需要解决的是封装ip包和解除封装。
步骤
需要解决以下一些问题:
1、如何捕获与发送icmp包
用socket的RAW模式即可。
2、如何不影响vps上正常的ping回应
给icmp里的code字段设置一个固定值,默认是0,这个值可以随便设置。例如86。这样我们只捕获与发送code值为86的icmp数据包。跟普通的ping区别开来,互不影响。
同时,避免vps的内核回应我们的icmp包。添加下面的iptables规则。使用到–icmp-type type/code选项。type的值中,8是ping请求,0是ping响应,所以只针对响应包屏蔽。但是为了让服务器端的tunnel程序的icmp 能发出去,服务器端在发送的时候,可以把code+1,也就变为87,发送出去。
iptables -A OUTPUT -p icmp –icmp-type 0/86 -j DROP
了解更多关于ICMP的选项,请参见RFC792.
3、MTU问题
因为IP包被封装到ICMP里之后,体积肯定会变大,如果超出网络的MTU,内核就会用两个IP包来装。导致第一个IP包装满了,第二个IP包可能只有几十个字节。十分浪费。为了避免这种现象,可以设置虚拟网卡的mtu为1000或更少。
ip link set t0 mtu 1000
4、Python里处理ICMP
icmp.py
  1. #!/usr/bin/env python
  2. import socket
  3. import binascii
  4. import struct
  5. import ctypes
  6. BUFFER_SIZE = 8192
  7. class IPPacket():
  8.     def _checksum(self, data):
  9.         if len(data) % 2:
  10.             odd_byte = ord(data[-1])
  11.             data = data[:-1]
  12.         else:
  13.             odd_byte = 0
  14.         words = struct.unpack(“!%sH” %(len(data)/2), data)
  15.         total = 0
  16.         for word in words:
  17.             total += word
  18.         else:
  19.             total += odd_byte
  20.         total = (total>>16) + (total & 0xffff)
  21.         total += total>>16
  22.         return ctypes.c_ushort(~total).value
  23.     def parse(self, buf, debug = True):
  24.         self.ttl, self.proto, self.chksum = struct.unpack(“!BBH”, buf[8:12])
  25.         self.src, self.dst = buf[12:16], buf[16:20]
  26.         if debug:
  27.             print “parse IP ttl=”, self.ttl, “proto=”, self.proto, “src=”, socket.inet_ntoa(self.src), \
  28.                 “dst=”, socket.inet_ntoa(self.dst)
  29. class ICMPPacket(IPPacket):
  30.     def parse(self, buf, debug = True):
  31.         IPPacket.parse(self, buf, debug)
  32.         self.type, self.code, self.chksum, self.id, self.seqno = struct.unpack(“!BBHHH”, buf[20:28])
  33.         if debug:
  34.             print “parse ICMP type=”, self.type, “code=”, self.code, “id=”, self.id, “seqno=”, self.seqno
  35.         return buf[28:]
  36.     def create(self, type_, code, id_, seqno, data):
  37.         packfmt = “!BBHHH%ss” % (len(data))
  38.         args = [type_, code, 0, id_, seqno, data]
  39.         args[2] = IPPacket._checksum(self, struct.pack(packfmt, *args))
  40.         return struct.pack(packfmt, *args)
4、我写的Tunnel程序
实现了以下功能:
1)支持多人同时使用这个VPN。每个客户端通过外网IP与ICMP里的ID的组合来决定。所以,即使多个使用者在同一个局域网下,也不会相互使用。参见代码中key的计算。
2)使用密码登录以限制他人访问。初次连接服务器要求密码才能使用该VPN。默认为10分钟收不到来自客户端的数据包就删除会话。这个密码登录做的有点简单,当然只要稍加修改,让服务器返回一个随机字符串,客户端用密码跟这个随机字符串一起hash一下,就很无敌了。
3)服务器端和客户端共用一个tunnel程序。通过参数来指定工作模式。
tunnel.py
  1. #!/usr/bin/env python
  2. import os, sys
  3. import hashlib
  4. import getopt
  5. import fcntl
  6. import icmp
  7. import time
  8. import struct
  9. import socket, select
  10. SHARED_PASSWORD = hashlib.md5(“password”).digest()
  11. TUNSETIFF = 0x400454ca
  12. IFF_TUN   = 0x0001
  13. MODE = 0
  14. DEBUG = 0
  15. PORT = 0
  16. IFACE_IP = “10.0.0.1”
  17. MTU = 1500
  18. CODE = 86
  19. TIMEOUT = 60*10 # seconds
  20. class Tunnel():
  21.   def create(self):
  22.     self.tfd = os.open(“/dev/net/tun”, os.O_RDWR)
  23.     ifs = fcntl.ioctl(self.tfd, TUNSETIFF, struct.pack(“16sH”, “t%d”, IFF_TUN))
  24.     self.tname = ifs[:16].strip(“\x00”)
  25.   def close(self):
  26.     os.close(self.tfd)
  27.   def config(self, ip):
  28.     os.system(“ip link set %s up” % (self.tname))
  29.     os.system(“ip link set %s mtu 1000” % (self.tname))
  30.     os.system(“ip addr add %s dev %s” % (ip, self.tname))
  31.   def run(self):
  32.     self.icmpfd = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname(“icmp”))
  33.     self.clients = {}
  34.     packet = icmp.ICMPPacket()
  35.     self.client_seqno = 1
  36.     while True:
  37.       rset = select.select([self.icmpfd, self.tfd], [], [])[0]
  38.       for r in rset:
  39.         if r == self.tfd:
  40.           if DEBUG: os.write(1, “>”)
  41.           data = os.read(self.tfd, MTU)
  42.           if MODE == 1: # Server
  43.             for key in self.clients:
  44.               buf = packet.create(0, CODE+1, self.clients[key][“id”], self.clients[key][“seqno”], data)
  45.               self.clients[key][“seqno”] += 1
  46.               self.icmpfd.sendto(buf, (self.clients[key][“ip”], 22))
  47.             # Remove timeout clients
  48.             curTime = time.time()
  49.             for key in self.clients.keys():
  50.               if curTime – self.clients[key][“aliveTime”] > TIMEOUT:
  51.                 print “Remove timeout client”, self.clients[key][“ip”]
  52.                 del self.clients[key]
  53.           else: # Client
  54.             buf = packet.create(8, CODE, PORT, self.client_seqno, data)
  55.             self.client_seqno += 1
  56.             self.icmpfd.sendto(buf, (IP, 22))
  57.         elif r == self.icmpfd:
  58.           if DEBUG: os.write(1, “<“)
  59.           buf = self.icmpfd.recv(icmp.BUFFER_SIZE)
  60.           data = packet.parse(buf, DEBUG)
  61.           ip = socket.inet_ntoa(packet.src)
  62.           if packet.code in (CODE, CODE+1):
  63.             if MODE == 1: # Server
  64.               key = struct.pack(“4sH”, packet.src, packet.id)
  65.               if key not in self.clients:
  66.                 # New client comes
  67.                 if data == SHARED_PASSWORD:
  68.                   self.clients[key] = {“aliveTime”: time.time(),
  69.                             “ip”: ip,
  70.                             “id”: packet.id,
  71.                             “seqno”: packet.seqno}
  72.                   print “New Client from %s:%d” % (ip, packet.id)
  73.                 else:
  74.                   print “Wrong password from %s:%d” % (ip, packet.id)
  75.                   buf = packet.create(0, CODE+1, packet.id, packet.seqno, “PASSWORD”*10)
  76.                   self.icmpfd.sendto(buf, (ip, 22))
  77.               else:
  78.                 # Simply write the packet to local or forward them to other clients ???
  79.                 os.write(self.tfd, data)
  80.                 self.clients[key][“aliveTime”] = time.time()
  81.             else: # Client
  82.               if data.startswith(“PASSWORD”):
  83.                 # Do login
  84.                 buf = packet.create(8, CODE, packet.id, self.client_seqno, SHARED_PASSWORD)
  85.                 self.client_seqno += 1
  86.                 self.icmpfd.sendto(buf, (ip, 22))
  87.               else:
  88.                 os.write(self.tfd, data)
  89. def usage(status = 0):
  90.   print “Usage: icmptun [-s code|-c serverip,code,id] [-hd] [-l localip]”
  91.   sys.exit(status)
  92. if __name__==”__main__”:
  93.   opts = getopt.getopt(sys.argv[1:],”s:c:l:hd”)
  94.   for opt,optarg in opts[0]:
  95.     if opt == “-h”:
  96.       usage()
  97.     elif opt == “-d”:
  98.       DEBUG += 1
  99.     elif opt == “-s”:
  100.       MODE = 1
  101.       CODE = int(optarg)
  102.     elif opt == “-c”:
  103.       MODE = 2
  104.       IP,CODE,PORT = optarg.split(“,”)
  105.       CODE = int(CODE)
  106.       PORT = int(PORT)
  107.     elif opt == “-l”:
  108.       IFACE_IP = optarg
  109.   if MODE == 0 or CODE == 0:
  110.     usage(1)
  111.   tun = Tunnel()
  112.   tun.create()
  113.   print “Allocated interface %s” % (tun.tname)
  114.   tun.config(IFACE_IP)
  115.   try:
  116.     tun.run()
  117.   except KeyboardInterrupt:
  118.     tun.close()
  119.     sys.exit(0)
用法:
root@244754:~/lab/icmptun# ./tunnel.py
Usage: icmptun [-s code|-c serverip,code,id] [-hd] [-l localip]

5、VPS服务器端部署
把icmp.py和tunnel.py都copy到vps上去。注意要设置为可执行文件。然后用下面的命令来运行。
./tunnel.py -s 86 -l 10.1.2.1/24
Allocated interface t1
tunnel.py会创建一个虚拟网卡(tun)。上述命令中,虚拟网卡的IP为10.1.2.1,子网掩码为255.255.255.0。
查看已经建立的网卡,我这里显示为t1. 因为t0已经被我用作udp隧道。
root@244754:~/lab/icmptun# ip route show
184.22.224.0/24 dev venet0  proto kernel  scope link  src 184.22.224.212
10.1.1.0/24 dev t0  proto kernel  scope link  src 10.1.1.1
10.1.2.0/24 dev t1  proto kernel  scope link  src 10.1.2.1
default dev venet0  scope link
6、笔记本上客户端部署
以客户端模式启动tunnel.py,
root@xiaoxia-pc:~/project/icmptun# ./tunnel.py -c 184.22.224.212,86,2012 -l 10.1.2.2/24
Allocated interface t0
-c的参数指定三项内容,用道号分隔,分别是远程服务器端的IP,发送ping时所使用的code,发送ping时所使用的id。code是区别普通的ping包,id是区别不同的客户端。
注意,如果在局域网环境下,经过网关后,这个id可能会变化,但不影响使用,因为回应包进入内网时,id会变回原值。
启动客户端后,在本地可以ping一下IP。
root@xiaoxia-pc:~/project/icmptun# ping 10.1.2.2
PING 10.1.2.2 (10.1.2.2) 56(84) bytes of data.
64 bytes from 10.1.2.2: icmp_req=1 ttl=64 time=0.065 ms
64 bytes from 10.1.2.2: icmp_req=2 ttl=64 time=0.065 ms
64 bytes from 10.1.2.2: icmp_req=3 ttl=64 time=0.059 ms
很快就响应了,本地直接返回。
此时ping一下在vps的虚拟网卡,正常情况下,应该能得到回应了。
root@xiaoxia-pc:~/project/icmptun# ping 10.1.2.1
PING 10.1.2.1 (10.1.2.1) 56(84) bytes of data.
64 bytes from 10.1.2.1: icmp_req=1 ttl=64 time=322 ms
64 bytes from 10.1.2.1: icmp_req=2 ttl=64 time=545 ms
64 bytes from 10.1.2.1: icmp_req=3 ttl=64 time=400 ms
到目前为止,已经在两台机器之间通过icmp建立了点对点隧道。
7、构建VPN
先在服务器端设置NAT。
iptables -t nat -A POSTROUTING -s 10.1.2.0/24 -j SNAT –to-source 184.22.224.212
再在本地设置路由表,让默认网关为新创建的t0. 同时注意把vps的ip设置为例外。
ip route add 184.22.224.212 via 10.64.64.64 dev ppp0
ip route del default
ip route add default dev t0
我的路由表如下:
root@xiaoxia-pc:~/project/icmptun# ip route show
10.64.64.64 dev ppp0  proto kernel  scope link  src 10.134.75.35
184.22.224.212 via 10.64.64.64 dev ppp0
10.1.2.0/24 dev t0  proto kernel  scope link  src 10.1.2.2
169.254.0.0/16 dev ppp0  scope link  metric 1000
default dev t0  scope link
到此,已经可以通过t0访问网络了。
root@xiaoxia-pc:~/project/icmptun# telnet www.google.com 80
Trying 203.208.46.180…
Connected to www.google.com.
Escape character is ‘^]’.
最后
可以把启动客户端以及设置路由的命令,写进一个脚本文件里,这样只需要一个命令,就能使用VPN了!像在我这个地方,就可以用这个工具实现在CMWAP的网络上免费上网,没有流量的限制。
当然,ICMP Tunnel在很多场合下都可以使用,只要ICMP没有被封,就有办法通过ICMP来建立隧道和VPN来摆脱网络限制。
我使用中的抓包,
Wireshark很好用,在我分析ICMP的过程中,帮助很大。当然在服务器上使用tcpdump -n icmp来查看ICMP是否工作也很有用。
184.22.224.213是我的VPS上IP之一。
现在已经夜深了,EDGE的速度还行吧。
root@xiaoxia-pc:~/project/icmptun# wget http://xiaoxia.org/upfiles/a.zip
--2012-01-16 04:22:54--  http://xiaoxia.org/upfiles/a.zip
正在解析主机 xiaoxia.org... 184.22.224.213
正在连接 xiaoxia.org|184.22.224.213|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 262194 (256K) [application/zip]
正在保存至: “a.zip.1”

100%[============================================>] 262,194     18.8K/s   花时 14s   

2012-01-16 04:23:09 (18.5 KB/s) - 已保存 “a.zip.1” [262194/262194])
本文主要用于学习交流,欢迎与大家共同探讨!!!
附本文所用代码文件下载:
参考文献
来源:http://xiaoxia.org/2012/01/16/cmwap-vpn-over-icmp-tunnel-python-code-2/
--------------------------------------------------------------------------------------------------------------------

Transparently tunnel your IP traffic through ICMP echo and reply packets. 

icmptunnel Build Status 

(这个DhavalKapil写的icmptunnel只能运行在linux桌面系统。暂时还不能运行在mac上。)

Transparently tunnel your IP traffic through ICMP echo and reply packets.
'icmptunnel' works by encapsulating your IP traffic in ICMP echo packets and sending them to your own proxy server. The proxy server decapsulates the packet and forwards the IP traffic. The incoming IP packets which are destined for the client are again encapsulated in ICMP reply packets and sent back to the client. The IP traffic is sent in the 'data' field of ICMP packets.
RFC 792, which is IETF's rules governing ICMP packets, allows for an arbitrary data length for any type 0 (echo reply) or 8 (echo message) ICMP packets.
So basically the client machine uses only the ICMP protocol to communicate with the proxy server. Applications running on the client machine are oblivious to this fact and work seamlessly.

Use Cases

  1. Bypassing Captive Portals: Many public Wi-Fi use Captive Portals to authenticate users, i.e. after connecting to the Wi-Fi the user is redirected to a webpage that requires a login. icmptunnel can be used to bypass such authentications in transport/application layers.
  2. Bypassing firewalls: Firewalls are set up in various networks to block certain type of traffic. icmptunnel can be used to bypass such firewall rules. Obfuscating the data payload can also be helpful to bypass some firewalls.
  3. Encrypted Communication Channel: Adding sufficient encryption to the data, icmptunnel can be used to establish an encrypted communication channel between two host machines.

Requirements

  1. A POSIX-compliant host with root access that will be communicating with only ICMP protocol. This will be the client.
  2. A POSIX-compliant host with root access with full access to the internet. This will act as our proxy server.
  3. The proxy server should be accessible from the client host.
Note: Although icmptunnel has been successfully tested on Ubuntu 14.04 LTS, it should work on others as well.

Step-by-step instructions

  1. Install make on both machines.
  2. Clone this repository using this command:
git clone https://github.com/DhavalKapil/icmptunnel
  1. Run make:
make
  1. On the server side run the tunnel with root privileges:
[sudo] ./icmptunnel -s 10.0.1.1
  1. On the client side, find out your gateway and the corresponding interface:
route -n

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

0.0.0.0         172.25.30.1     0.0.0.0         UG    0      0        0 eth0
Edit client.sh and replace <server> with the IP address of the proxy server. <gateway> with gateway address obtained above and similarly for <interface>.
  1. Check the DNS server at client side. Make sure it does not use any server not accessible by our proxy server. One suggestion is to use 8.8.8.8(Google's DNS server) which will be accessible to the proxy server. You would need to edit your DNS settings for this. You might need to manually delete the route for your local DNS server from your routing table.
  2. Run the tunnel on your client with root privileges:
[sudo] ./icmptunnel -c <server>
The tunnel should run and your client machine should be able to access the internet. All traffic will be tunneled through ICMP.

Architecture

icmptunnel works by creating a virtual tunnel interface(say tun0). All the user traffic on the client host is routed to tun0. icmptunnel listens on this interface for IP packets. These packets are encapsulated in an ICMP echo packet(i.e. the payload of the ICMP packet is nothing but the original IP packet). This newly generated ICMP packet is sent outside the client machine, to the proxy server, through the restricted internet connection.
The proxy server receives these ICMP packets and decapsulates the original IP packet. This is retransmitted onto the Internet after implementing IP masquerading. Hence, the target believes that it's the proxy server making the request. The target then responds back to the proxy server with an IP packet. This is again captured by icmptunnel, encapsulated in an ICMP reply packet and send back to the client.
On the client side, the IP packet is retrieved from the payload of the ICMP reply packet and injected in tun0. The user applications read from this virtual interface and hence get the proper IP packet.

Overall Architecture

+--------------+                         +------------+
|              |       ICMP traffic      |            |       IP traffic
|    Client    |  ------------------->   |   Proxy    |   ------------------>
|              |  <-------------------   |   Server   |   <------------------
|              |    through restricted   |            |     proper internet
+--------------+         internet        +------------+

Client Architecture

+--------------+                                    +------------+
|              |  IP traffic  +------+  IP traffic  |            |   ICMP traffic
|     User     |  --------->  | tun0 |  --------->  | icmptunnel | --------------->
| Applications |  <---------  +------+  <---------  |  program   | <---------------
|              |        (Virtual Interface)         |            |    restricted 
+--------------+                                    +------------+     internet

Proxy Server Architecture

                 +------------+
  ICMP traffic   |            |  IP traffic     +------+       NAT/Masquerading
---------------> | icmptunnel | ------------>   | tun0 |    ---------------------> 
<--------------- |  program   | <------------   +------+    <---------------------
   restricted    |            |           (Virtual Interface)   proper internet
    internet     +------------+

Implementation

  • ICMP is implemented using raw C sockets.
  • The checksum is calculated using the algorithm given in RFC 1071.
  • Tun driver is used for creating a virtual interface and binding to user space programs.
  • The virtual interface is configured through ifconfig.
  • route is used to change the routing tables of the client so as to route all traffic to the virtual tunnel interface.
  • dd is used to temporarily change the setting of IP forwarding and replying back to ICMP requests on the side of the proxy server.
  • iptables is used to set up nat on the server side.

Demo

Network Setup

Proxy server is connected to eth0. This interface provides full internet connection.
Both the client and proxy server are connected to wlan0(a WiFi hotspot). This hotspot is configured not to provide any internet connection.
tun0 will be created in both the client and the proxy server.
The client will make an HTTP request to dhavalkapil.com.
Wireshark is used to capture network traffic at both ends on various interface.
from https://github.com/DhavalKapil/icmptunnel
------------------------------

Tunnel IP over ICMP.  

icmptunnel is a tool to tunnel IP traffic within ICMP echo request and response (ping) packets. It’s intended for bypassing firewalls in a semi-covert way, for example when pivoting inside a network where ping is allowed. It might also be useful for egress from a corporate network to the Internet, although it is quite common for ICMP echo traffic to be filtered at the network perimeter.
While there are a couple of existing tools which implement this technique, icmptunnel provides a more reliable protocol and a mechanism for tunneling through stateful firewalls and NAT.
Compiling:
The tool uses a plain Makefile to compile and install.
Use make to compile icmptunnel.
Quickstart:
First, disable ICMP echo responses on both the client and server. This prevents the kernel from responding to ping packets itself.
# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
On the server-side, start icmptunnel in server mode, and assign an IP address to the new tunnel interface.
# ./icmptunnel –s
opened tunnel device: tun0
(ctrl-z)
# bg
# /sbin/ifconfig tun0 10.0.0.1 netmask 255.255.255.0
On the client-side, point icmptunnel at the server, and assign an IP address.
# ./icmptunnel 
opened tunnel device: tun0
connection established.
(ctrl-z)
# bg
# /sbin/ifconfig tun0 10.0.0.2 netmask 255.255.255.0
At this point, you should have a functioning point-to-point tunnel via ICMP packets. The server side is 10.0.0.1, and the client-side is 10.0.0.2. On the client, try connecting to the server via SSH:
# ssh root@10.0.0.1
Password:
To use the remote server as an encrypted SOCKS proxy:
# ssh -D 8080 -N root@10.0.0.1
Password:
Now point your web browser at the local SOCKS server.
Further Information
See ./icmptunnel -h for a list of options.
Bugs
Please report any bugs on the Github project page at:
https://github.com/jamesbarlow/icmptunnel/issues

from https://github.com/jamesbarlow/icmptunnel
------------------

相关帖子:
http://briteming.blogspot.de/2012/02/ping-tunnel.html
http://briteming.blogspot.com/2016/10/ip-over-icmp-proxy.html