Skip to content

Instantly share code, notes, and snippets.

@ysc3839
Created August 22, 2016 04:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save ysc3839/aa0f424b0fb4c8b70a612b16663b4a38 to your computer and use it in GitHub Desktop.
Save ysc3839/aa0f424b0fb4c8b70a612b16663b4a38 to your computer and use it in GitHub Desktop.
WallBreaker
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, socket, select, SocketServer, struct, logging
from time import sleep
logging.basicConfig(level=logging.INFO)
BUFLEN = 1024
SLEEPTIME = 0.4
patterns = [
('.apk ', 2),
('\r\nHost:', 4),
('weixin.qq.com', 3),
('.qq.com', 2),
('file.ws.126.net', 10),
('s1.music.126.net', 12),
('.', 2),
('userscripts-mirror', 4),
(':',1)
]
# (pattern, offset)
def splitHttp(data):
list = []
for pattern in patterns:
i = data.find(pattern[0])
if i != -1:
list.append(data[:i + pattern[1]])
data = data[i + pattern[1]:]
list.append(data)
return list
def unpack(self, fmt):
u'''解包
block 是否阻塞
即使非阻塞模式是标准的 recv ,也会阻塞。
阻塞模式会完全阻塞,直到连接关闭或连接超时。
'''
length = struct.calcsize(fmt)
data = self.recv(length)
if len(data) < length:
raise Exception("sock.unpack: bad formatted stream")
return struct.unpack(fmt, data)
def pack(self, fmt, *args):
data = struct.pack(fmt, *args)
return self.sendall(data)
setattr(socket.SocketType, 'unpack', unpack)
setattr(socket.SocketType, 'pack', pack)
class Socks5Handler(SocketServer.BaseRequestHandler):
u'''SOCKS4 SOCKS5 双协议支持 From TcpRoute https://github.com/GameXG/TcpRoute'''
def __init__(self, request, client_address, server):
self.sock = request
SocketServer.BaseRequestHandler.__init__(self, request, client_address, server)
def handle(self):
(ver,) = self.sock.unpack('B')
self.ver = ver
if ver == 0x04:
self.socks4Handle()
elif ver == 0x05:
self.socks5Handle()
else:
logging.error(u'[Socks5Handler]异常的协议类型, ver = %u' % (ver))
self.sock.close()
return
def socks4Handle(self):
logging.info(u'SOCKS4连接 %s:%u' % self.client_address)
cd,port,dstip = self.sock.unpack('!BHI')
if cd != 1:
# 1 == 连接, 2 == 绑定
self.sock.pack('!BBHI',0,91,port,dstip)
self.sock.close()
# userid = self.sock.readline(end='\0')[:-1]
while self.sock.recv(1) != '\0':
pass
hostname = socket.inet_ntoa(struct.pack('!I', dstip))
# if hostname.startswith('0.0.0.'):
# SOCKS4a 支持 ,chrome 不支持 socks4a 扩展。
# hostname = self.sock.readline(end='\0')[:-1]
self.hostname = hostname
self.port = port
# 对外发起请求
try:
remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_sock.connect((hostname, port))
except:
logging.exception(u'所有线路连接 TCP Host:%s Port:%s 失败' % (hostname, port))
# 按照socks4协议,这里返回和请求相同的ip和端口
# https://zh.wikipedia.org/wiki/SOCKS
self.sock.pack('!BBHI', 0, 91, port, dstip)
self.sock.close()
return
logging.info(u'连接 TCP目标 Host:%s Port:%u 建立成功。' % (hostname, port))
# 按照socks4协议,这里返回和请求相同的ip和端口
# https://zh.wikipedia.org/wiki/SOCKS
self.sock.pack('!BBHI', 0, 90, port, dstip)
self.forward(self.sock,remote_sock)
def socks5Handle(self):
logging.info(u'SOCKS5连接 %s:%u' % self.client_address)
# 鉴定
(nmethods,) = self.sock.unpack('B')
if nmethods > 0:
(methods,) = self.sock.unpack('B' * nmethods)
# TODO: 未检查客户端支持的鉴定方式
self.sock.pack('BB', 0x05, 0x00)
logging.debug(u'[Socks5Handler]client login')
# 接收代理请求
ver, cmd, rsv, atyp = self.sock.unpack('BBBB')
if ver != 0x05 or cmd != 0x01:
logging.warn(u'[Socks5Handler]收到未知类型的请求,关闭连接 ver=%s, cmd=%s' % (ver, cmd))
self.sock.pack('BBBBIH', 0x05, 0x07, 0x00, 0x01, 0, 0)
self.sock.close()
return
sock_family = socket.AF_INET
if atyp == 0x01:
# IPv4
host, port = self.sock.unpack('!IH')
hostname = socket.inet_ntoa(struct.pack('!I', host))
elif atyp == 0x03:
# 域名
length = self.sock.unpack('B')[0]
hostname, port = self.sock.unpack("!%usH" % length)
elif atyp == 0x04:
# IPv6
sock_family = socket.AF_INET6
ipv61, ipv62, port = self.sock.unpack('!2QH')
hostname = socket.inet_ntop(socket.AF_INET6, struct.pack('!2Q', ipv61, ipv62))
else:
logging.warn(u'[SClient]收到未知的目的地址类型,关闭连接。 atyp=%s ' % (atyp))
self.sock.pack('!BBBBIH', 0x05, 0x07, 0x00, 0x01, 0, 0)
self.sock.close()
return
logging.debug(u'[SClient] Host:%s Port:%s' % (hostname, port))
self.hostname = hostname
self.port = port
# 对外发起请求
try:
remote_sock = socket.socket(sock_family, socket.SOCK_STREAM)
remote_sock.connect((hostname, port))
except:
logging.exception(u'所有线路连接 TCP Host:%s Port:%s 失败' % (hostname, port))
# TODO: 按照SOCKS5协议,这里应该返回服务器绑定的地址及端口
# http://blog.csdn.net/testcs_dn/article/details/7915505
self.sock.pack('!BBBBIH', 0x05, 0x03, 0x00, 0x01, 0, 0)
self.sock.close()
return
logging.info(u'连接 TCP目标 Host:%s Port:%u 建立成功。' % (hostname, port))
# TODO: 按照SOCKS5协议,这里应该返回服务器绑定的地址及端口
# http://blog.csdn.net/testcs_dn/article/details/7915505
self.sock.pack('!BBBBIH', 0x05, 0x00, 0x00, 0x01, 0, 0)
self.forward(self.sock,remote_sock)
def forward(self, sock, remote):
fdset = [sock, remote]
while True:
r, w, e = select.select(fdset, [], [])
if len(e) != 0:
sock.close()
remote.close()
return
if sock in r:
buf = sock.recv(BUFLEN)
if True:
datalist = splitHttp(buf)
logging.info(datalist)
for data in datalist:
remote.sendall(data)
sleep(SLEEPTIME)
elif remote.send(buf) <= 0: break
if remote in r:
buf = remote.recv(BUFLEN)
i = buf[:512].find('Location: http://172.16.100.2/disable/')
j = buf[:512].find('setURL("172.16.100.2")')
if i == -1 and j == -1:
if sock.send(buf) <= 0: break
else:
logging.info('BLOCKED!!!')
sock.send('HTTP/1.0 403 Forbidden\r\n\r\nBLOCKED!!!')
sock.close()
remote.close()
return
def main():
port = 1080
server = SocketServer.ThreadingTCPServer(('127.0.0.1', port), Socks5Handler)
logging.info('Starting server at 127.0.0.1:%u.' % port)
try:
server.serve_forever()
except socket.error as e:
if e.errno == 10048:
logging.error(u'端口 %u 已被使用.' % port)
except KeyboardInterrupt:
logging.info('Server shutting down.')
exit(0)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment