手动创建ICMP Tunnel实现VPN上网(附Python实现代码)

其实这是一篇讲解利用中国移动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

我自己写了一段代码,checksum的算法参考自 http://code.activestate.com/recipes/409689-icmplib-library-for-creating-and-reading-icmp-pack/

icmp.py

#!/usr/bin/env python
import socket
import binascii
import struct
import ctypes

BUFFER_SIZE = 8192

class IPPacket():
    def _checksum(self, data):
        if len(data) % 2:
            odd_byte = ord(data[-1])
            data = data[:-1]
        else:
            odd_byte = 0
        words = struct.unpack("!%sH" %(len(data)/2), data)
        total = 0
        for word in words:
            total += word
        else:
            total += odd_byte
        total = (total>>16) + (total & 0xffff)
        total += total>>16
        return ctypes.c_ushort(~total).value

    def parse(self, buf, debug = True):
        self.ttl, self.proto, self.chksum = struct.unpack("!BBH", buf[8:12])
        self.src, self.dst = buf[12:16], buf[16:20]
        if debug:
            print "parse IP ttl=", self.ttl, "proto=", self.proto, "src=", socket.inet_ntoa(self.src), \
                "dst=", socket.inet_ntoa(self.dst)
        
class ICMPPacket(IPPacket):
    def parse(self, buf, debug = True):
        IPPacket.parse(self, buf, debug)
        self.type, self.code, self.chksum, self.id, self.seqno = struct.unpack("!BBHHH", buf[20:28])
        if debug:
            print "parse ICMP type=", self.type, "code=", self.code, "id=", self.id, "seqno=", self.seqno
        return buf[28:]

    def create(self, type_, code, id_, seqno, data):
        packfmt = "!BBHHH%ss" % (len(data))
        args = [type_, code, 0, id_, seqno, data]
        args[2] = IPPacket._checksum(self, struct.pack(packfmt, *args))
        return struct.pack(packfmt, *args)

4、我写的Tunnel程序

实现了以下功能:

1)支持多人同时使用这个VPN。每个客户端通过外网IP与ICMP里的ID的组合来决定。所以,即使多个使用者在同一个局域网下,也不会相互使用。参见代码中key的计算。

2)使用密码登录以限制他人访问。初次连接服务器要求密码才能使用该VPN。默认为10分钟收不到来自客户端的数据包就删除会话。这个密码登录做的有点简单,当然只要稍加修改,让服务器返回一个随机字符串,客户端用密码跟这个随机字符串一起hash一下,就很无敌了。

3)服务器端和客户端共用一个tunnel程序。通过参数来指定工作模式。

tunnel.py

#!/usr/bin/env python

import os, sys
import hashlib
import getopt
import fcntl
import icmp
import time
import struct
import socket, select

SHARED_PASSWORD = hashlib.md5("password").digest()
TUNSETIFF = 0x400454ca
IFF_TUN   = 0x0001

MODE = 0
DEBUG = 0
PORT = 0
IFACE_IP = "10.0.0.1"
MTU = 1500
CODE = 86
TIMEOUT = 60*10 # seconds

class Tunnel():
  def create(self):
    self.tfd = os.open("/dev/net/tun", os.O_RDWR)
    ifs = fcntl.ioctl(self.tfd, TUNSETIFF, struct.pack("16sH", "t%d", IFF_TUN))
    self.tname = ifs[:16].strip("\x00")
  
  def close(self):
    os.close(self.tfd)
    
  def config(self, ip):
    os.system("ip link set %s up" % (self.tname))
    os.system("ip link set %s mtu 1000" % (self.tname))
    os.system("ip addr add %s dev %s" % (ip, self.tname))
  
  def run(self):
    self.icmpfd = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp"))
      
    self.clients = {}
    packet = icmp.ICMPPacket()
    self.client_seqno = 1
      
    while True:
      rset = select.select([self.icmpfd, self.tfd], [], [])[0]
      for r in rset:
        if r == self.tfd:
          if DEBUG: os.write(1, ">")
          data = os.read(self.tfd, MTU)
          if MODE == 1: # Server
            for key in self.clients:
              buf = packet.create(0, CODE+1, self.clients[key]["id"], self.clients[key]["seqno"], data)
              self.clients[key]["seqno"] += 1
              self.icmpfd.sendto(buf, (self.clients[key]["ip"], 22))
            # Remove timeout clients
            curTime = time.time()
            for key in self.clients.keys():
              if curTime - self.clients[key]["aliveTime"] > TIMEOUT:
                print "Remove timeout client", self.clients[key]["ip"]
                del self.clients[key]
          else: # Client
            buf = packet.create(8, CODE, PORT, self.client_seqno, data)
            self.client_seqno += 1
            self.icmpfd.sendto(buf, (IP, 22))
        elif r == self.icmpfd:
          if DEBUG: os.write(1, "<")
          buf = self.icmpfd.recv(icmp.BUFFER_SIZE)
          data = packet.parse(buf, DEBUG)
          ip = socket.inet_ntoa(packet.src)
          if packet.code in (CODE, CODE+1):
            if MODE == 1: # Server
              key = struct.pack("4sH", packet.src, packet.id)
              if key not in self.clients:
                # New client comes
                if data == SHARED_PASSWORD:
                  self.clients[key] = {"aliveTime": time.time(), 
                            "ip": ip, 
                            "id": packet.id,
                            "seqno": packet.seqno}
                  print "New Client from %s:%d" % (ip, packet.id)
                else:
                  print "Wrong password from %s:%d" % (ip, packet.id)
                  buf = packet.create(0, CODE+1, packet.id, packet.seqno, "PASSWORD"*10)
                  self.icmpfd.sendto(buf, (ip, 22))
              else:
                # Simply write the packet to local or forward them to other clients ???
                os.write(self.tfd, data)
                self.clients[key]["aliveTime"] = time.time()
            else: # Client
              if data.startswith("PASSWORD"):
                # Do login
                buf = packet.create(8, CODE, packet.id, self.client_seqno, SHARED_PASSWORD)
                self.client_seqno += 1
                self.icmpfd.sendto(buf, (ip, 22))
              else:
                os.write(self.tfd, data)

def usage(status = 0):
  print "Usage: icmptun [-s code|-c serverip,code,id] [-hd] [-l localip]"
  sys.exit(status)

if __name__=="__main__":
  opts = getopt.getopt(sys.argv[1:],"s:c:l:hd")
  for opt,optarg in opts[0]:
    if opt == "-h":
      usage()
    elif opt == "-d":
      DEBUG += 1
    elif opt == "-s":
      MODE = 1
      CODE = int(optarg)
    elif opt == "-c":
      MODE = 2
      IP,CODE,PORT = optarg.split(",")
      CODE = int(CODE)
      PORT = int(PORT)
    elif opt == "-l":
      IFACE_IP = optarg
  
  if MODE == 0 or CODE == 0:
    usage(1)
  
  tun = Tunnel()
  tun.create()
  print "Allocated interface %s" % (tun.tname)
  tun.config(IFACE_IP)
  try:
    tun.run()
  except KeyboardInterrupt:
    tun.close()
    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])

本文主要用于学习交流,欢迎与大家共同探讨!!!

附本文所用代码文件下载:

icmptun.tar

参考文献

http://www.ietf.org/rfc/rfc792.txt

http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers

http://en.wikipedia.org/wiki/IPv4

http://code.activestate.com/recipes/409689-icmplib-library-for-creating-and-reading-icmp-pack/

http://www.cs.uit.no/~daniels/PingTunnel/

手动创建ICMP Tunnel实现VPN上网(附Python实现代码)》上有132条评论

  1. 清风剑

    正点!以前用过利用53端口的VPN,移动和麦当劳的wifi没有屏蔽53端口,于是可以将数据包装成DNS包送出去了。Ping包应该通用性更广啊,口水下

    回复
    1. Xiaoxia 文章作者

      是kubuntu11.04来的,用着稳定所以一直没换,等有需要再弄arch。默认字体是Ubuntu,中文字体是文泉驿微米黑 :-)

      回复
    1. Xiaoxia 文章作者

      嗯,对于我这样有vps的人,是挺方便的。
      而且一个vps可以给大量的人群提供这样的服务。
      最好的防范方法应该是限制IP包里的IP地址,而不是针对 TCP/IP 传输层的东西进行限制。

      回复
    1. Xiaoxia 文章作者

      如果路由是用openwrt或者linux系统,又可以外接3g或edge上网卡,可以这样来架设。
      2g网络响应太慢了,ping回应时间比较长。要不然,我还考虑用多张卡合并,来实现多通道加速呢。

      回复
      1. ljl

        好吧。。虽然有挖坟的嫌疑,但是我想说imorz的意思应该是在家里搭个vpn,然后在外面用edge免费上网

        回复
          1. Xiaoxia 文章作者

            x1是啥?也是2g网络?
            现在大部分地区gprs都升级为edge了吧!!!我这里的三级县所覆盖的地方,包括乡村,都是edge。

            回复
  2. xiaoxins

    USB modems (for plain old telephone service, ISDN or cable) are supposed to conform to the Communication Device Class (CDC) specification, and usually to the Abstract Control Model (ACM) sub-class.
    我的nokia N79需要这个模块来驱动

    回复
    1. Xiaoxia 文章作者

      哦,如果你的笔记本有蓝牙,直接用手机跟笔记本蓝牙连接,系统的蓝牙工具应该会提示是否启动蓝牙modem。
      我之前用手机上网是这么干的,不过现在有USB上网卡了,系统能自动识别。

      回复
    1. Xiaoxia 文章作者

      为了提高窗口的响应速度,我特效全关了。。。
      所以,半透明效果也没了。不过我还是觉得挺好看的呀。

      回复
    1. Xiaoxia 文章作者

      其实觉得python跟其他语言也挺像的,我也只是看看官方手册,然后就开始用了哦。没看过什么书,你想成为高手,经常用或者看别人的代码也该挺有好处的。

      回复
  3. Christopher Meng

    弱弱的问一句哪些专业需要本文的知识,我现在高三只会PYTHON,向您这样完整提出解决方案的思维还没有,应该看什么书?还是选什么专业?

    回复
    1. Xiaoxia 文章作者

      多阅读博文、维基百科、各类网络方面的文档吧。
      实践基础还是需要有的,所以平时需多练习。
      多读代码,多写代码。熟练一种语言之后,你就可以想到什么就去实现什么。

      回复
  4. liam

    俺是也西瓜大的,最近发现了xiaoxia大神的博客,不得不感叹,用西工大的猫免费上网真是太幼稚了,这个才是真正的神作啊!对前辈表示无限崇敬\^_^/

    回复
  5. Eveing

    为什么?移动分地方政策?我从2011年底就无法ping通cmwap代理了,我以为代理服务器已经没有了呢。skype上一个朋友告诉我他用cmwap登录skype,我很惊讶,回头试了一下果然可以,然后把手机的链接代理删掉,只保留cmwap接入点,上网和net已经没有区别。可能我们这新的流量套餐都是不分接入点的,移动不想为了有限几个cmwap包月用户开代理吧。

    回复
    1. Xiaoxia 文章作者

      不同地方,移动的设备和系统是有差别的。最明显的就是移动的Wifi验证网站,每个省都不一样。
      在广东,cmwap和cmnet是有区别的,虽然流量一样算法。我这里连接了cmwap,有时候不可以ping通,有时候又可以ping,看分配到的路由是什么。

      回复
      1. Eveing

        我说的上网和net已经没有区别是指访问端口,以前必须通过代理10.0.0.172:80访问网络,现在这个ip没有了,端口限制也就取消了。接入点还是必须区分,因为我的套餐只包cmwap.

        回复
  6. Bitplus

    请问能否对tunnel的传输进行加密?例如pre shared key或者OpenSSL证书。如果可以,应该在哪一步实现?

    回复
    1. Xiaoxia 文章作者

      可以的!需要自己实现,在封装IP包和解除封装的时候进新加密解密即可。
      有位搞信息安全的师兄说,私人用的软件,用最简单的XOR编码即可,密码要够长。这样也很难破解。

      回复
  7. 永恒沸点

    无意发现了一个另类方法,在实验。用废旧NOKIA E71做猫。联通3G,包流量卡,用PC套件连接上网计算流量,发送+接收=流量。无意中使用“将PC连接至互联网”连接,显示3.5G网络连接。断开后没有收到流量消耗短信,网站清单没有上网记录和损失流量。

    奇怪。如果找到原因,是不是还能省个VPS啊。

    回复
  8. Pingback引用通告: 手动创建ICMP Tunnel实现VPN上网(附Python实现代码) « 细节的力量

  9. Pingback引用通告: Definite Digest » 手动创建ICMP Tunnel实现VPN上网(附Python实现代码)

  10. kong

    对于终端获取的IP为非公网IP,即NAT情况时, 程序不能正常工作。

    不知道我的理解是否正确?

    回复
  11. Craftor

    想知道联通的3G,通过安卓系统,建立WIFI热点给PC使用,怎么能欺骗服务器,不计流量,研究研究~

    回复
  12. komin

    不知道 最近 安卓系统上流行的一款 “畅无线” 应用是不是采用你的这个方法 让大家免费无限上网的

    回复
  13. Lialosiu

    请问下~我部署在vps上,服务端和客户端都是ubuntu10.04,为啥会Wrong password from xxx.xxx.xxx.xxx:xxx的……
    难道我有参数弄错了么……?

    回复
      1. Lialosiu

        嗯,ping不通也连不上。
        试了下在本地用两台虚拟机对连可以通……
        难道是因为icmp包在传输过程中被啥东西篡改了……Orz

        回复
        1. Xiaoxia 文章作者

          嗯,有可能是路由的问题。这个可行性还是要看网络环境的。
          我最近想控制国内到国外的IP数据包的走向路径,但是失败了,主要是因为有一些网关的防火墙会记录TCP的连接状态,如果找不到状态就把数据包丢弃了~~

          回复
          1. Windpro

            我也是在本地vmware搭建测试成功.但是在校园网内就失败了.
            显示Wrong password from xxx.xxx.xxx.xxx:xxx
            ping不通连不上~
            又没有办法可以不验证id呢?
            我觉得是防火墙改了ID
            我直接用ping命令发送数据包是可以的.

            回复
              1. Xiaoxia 文章作者

                推荐你使用udp vpn呀,我现在也在用这个。
                为什么一定要使用icmp vpn呢?网络环境限制?

                回复
                1. Windpro

                  对 校园网是用安腾验证的,没有禁止ICMP包.
                  想通过ICMP 上网
                  应该是不能通过udp VPN上网的,好像除了ICMP 其他协议都不能通过路由器

                  回复
  14. wave

    xiaoxia:请问Host1Free.com免费的vps可以用吗
    在公司上班 屏蔽外网 但是icmp我试过可以连接
    不知道能否提供帮助

    回复
  15. wave

    xiaoxia:Host1Free.com免费vps可以用吗 公司的网络不能连外网 但是icmp试过是可以的年的 可以给我提供帮助吗
    谢谢

    回复
    1. Xiaoxia 文章作者

      没有用过免费的vps耶!理论上说,所有支持使用tun设备的vps都可以用。
      测试tun是否可以用,可以用下面的方法:

      cat /dev/net/tun 或者 cat /dev/tun
      cat: /dev/net/tun: 文件描述符处于错误状态

      如果提示上述错误状态,一般来说都是可以使用 :)

      回复
    1. Xiaoxia 文章作者

      呃,也有可能是我的代码写的不够好,有点过于随意。毕竟这只是一个实验品,而不是一个产品。所以,,,没有做的很到位吧。

      回复
  16. 大笨猫同学

    去年也是用诺基亚当猫免费上网,用的是cmmm接入点,它的代理是192.168.11.5,我把它作为https代理,又用SSH做第二级代理,于是神奇地就能上网了。
    后来失效了,又发现cmwap的ICMP不走流量,可惜我没博主那么博学多才,自己写代码来实现。
    另外,连接到cmmm接入点后用扫描内网端口,会发现很多移动的服务器,有的有服务器的配置,有的是管理登录页面,负载均衡服务器神马的,如果能枚举密码的话,不知道是不是可以搞破坏了。不知道是不是所有2g网络都是这样。

    回复
    1. Xiaoxia 文章作者

      广州这边能用上3g,如果买一3g上网卡的话。可惜我的linux内核对那个3g网卡的识别能力有限。
      还要配置一些复杂的脚本,我就没有研究下去了。。。

      回复
      1. 大笨猫同学

        好吧,貌似我搞错了。不过我记得以前没有这么完善的啊,这次连代码都放出来了。

        回复
    1. Xiaoxia 文章作者

      本来想打算做个手机应用,可以利用移动3g的漏洞,后来没有研究下去了,因为没tdscdma的手机。有tdscdma的上网卡,但是没有linux驱动程序,所以就放弃了!!!

      回复
    1. Xiaoxia 文章作者

      看你是什么需求了。如果用udp就可以,那就没有必要使用icmp了。因为它的确比较复杂的!

      回复
  17. 拉格朗日点

    我突然发现我的手机里没有ip命令,我的手机是n900,我该用啥代替呢?
    还有,由于我的是手机,t0和t1的设置还跟上文一样吗?

    回复
  18. devin

    写得很不错!
    但服务器端从tun上收到数据时,给每一个client都发一份相同icmp,效率会有点问题,对网络带宽也是浪费。
    解决方法似乎是用client端的t0网卡上的ip做key,比用client端的公网ip和icmp.id做key更好。

    回复
  19. Pingback引用通告: 徘徊于网格 |手动创建ICMP Tunnel实现VPN上网(附Python实现代码) « Xiaoxia[PG] - 徘徊于网格

  20. Pingback引用通告: 徘徊于网格 |手动创建ICMP Tunnel实现VPN上网(附Python实现代码) « Xiaoxia[PG] - 徘徊于网格

  21. Pingback引用通告: 手动创建ICMP Tunnel实现VPN上网(附Python实现代码) | 梦想天堂

  22. cheshireCat

    你好,我参考你的代码和其他资料实现了一个ip over icmp。并且成功连通,但是我发现一个问题,我的isp是移动,现在几乎不可能拿到外网IP。这样就有了一个问题,通行数据的时候如果要发送远大于mtu的数据,那么就会拆分在多个ip帧里面,而icmp链接流程却只有 请求-〉回显这个步骤,那么一次请求多出来的回显包有办法送到NAT内的机器上吗?

    回复
      1. cheshireCat

        把代码迁移到udp协议后发还是一样的问题,最后发现是os.read的读取字节数太少了。。。

        现在已经正常工作了,还加了xor加密,不过延时不太稳定,一般会比正常ping多出5ms

        回复
        1. Xiaoxia 文章作者

          抱歉,这个应该改为 BUFFER_SIZE,而不是用MTU的。 我有一个新版,代码没有放上来,我准备更新到github去。

          回复
  23. Jackie

    请问,iphone手机,没有电脑的情况下,能不能连接CMCC-WEB,直接利用这个VPN OVER ICMP上网?
    手机需要安装什么软件吗?好像手机只支持PPTP,L2TP,IPSEC。
    我们这里都可以ping,也可以DNS解析。

    回复
  24. ym

    hi.
    我在vps上的设置都搞好了,但在这一步:在linux桌面系统上运行ip route add my_vps_ip via 10.64.64.64 dev ppp0时,显示cannot find device ppp0.怎么解决这个错误?
    谢谢回复

    回复
  25. ppbox

    把icmp.py和tunnel.py都copy到vps上去。注意要设置为可执行文件。然后用下面的命令来运行。

    ./tunnel.py -s 86 -l 10.1.2.1/24

    我在这一步出错,说tunnel.py的26行和125行有错误。就是tun.creat有问题,请大大指望一下。

    回复
  26. Pingback引用通告: 手动创建ICMP Tunnel实现VPN上网(附Python实现代码) – Xor's Blog

  27. 轻风

    小虾大神,你好,我是来挖坟的,看了以上的精彩评论,对ICMP有了一定了解,也有很多疑问。
    手机上怎么通过和VPS之间的ICMP连接?
    另外VPS怎么把那个从手机上面发过来的ICMP包怎么处理到中国移动服务器上,然后再通过ICMP包返回到手机上来 希望小虾能够为我解答 我的QQ:859585053

    邮箱:859585853@qq.com

    回复
  28. Pingback引用通告: 手动创建ICMP Tunnel实现VPN上网(附Python实现代码) | Xiaoxia[PG] – Log@X.X.B

  29. hhding

    测试了一下,在 Linux 的路由器下似乎无法穿透 NAT。原因看起来是因为 code 不一样导致NAT失效。将 CODE +1 改为 CODE,同时去掉防火墙就可以了。

    回复
  30. CHANDLER

    运行后这是什么问题
    Traceback (most recent call last):
    File “./tunnel.py”, line 129, in
    tun.run()
    File “./tunnel.py”, line 63, in run
    buf = packet.create(8, CODE, PORT, self.client_seqno, data)
    File “/root/icmp.py”, line 46, in create
    args[2] = IPPacket._checksum(self, struct.pack(packfmt, *args))
    struct.error: ‘H’ format requires 0 <= number <= 65535

    回复

Bitplus进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>