mirror of
https://gitee.com/willfree/http_vpn.git
synced 2026-06-05 15:39:40 +08:00
119 lines
4.2 KiB
Python
119 lines
4.2 KiB
Python
import logging
|
|
import select
|
|
import socket
|
|
import struct
|
|
from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
SOCKS_VERSION = 5
|
|
socks_address='127.0.0.1'
|
|
socks_port=9011
|
|
|
|
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
|
|
pass
|
|
|
|
class SocksProxy(StreamRequestHandler):
|
|
|
|
def handle(self):
|
|
logging.info('Accepting connection from %s:%s' % self.client_address)
|
|
|
|
# 从客户端获取两个字节的连接代理服务器请求
|
|
header = self.connection.recv(2) #11111111111111111111111-2
|
|
# !表示network
|
|
version, nmethods = struct.unpack("!BB", header)
|
|
|
|
# socks 5
|
|
assert version == SOCKS_VERSION
|
|
assert nmethods > 0
|
|
|
|
# 获取客户端提供的子协商方法
|
|
methods = self.get_available_methods(nmethods)
|
|
|
|
# 如果子协商方法中不存在不需要子协商验证,就关闭此次连接
|
|
if 0 not in set(methods):
|
|
self.server.close_request(self.request)
|
|
return
|
|
|
|
# 返回选择的验证方式及socks版本
|
|
self.connection.sendall(struct.pack("!BB", SOCKS_VERSION, 0))
|
|
|
|
# 客户端获得url请求的前几个字节
|
|
version, cmd, _, address_type = struct.unpack("!BBBB", self.connection.recv(4))
|
|
assert version == SOCKS_VERSION
|
|
|
|
if address_type == 1: # IPv4
|
|
address = socket.inet_ntoa(self.connection.recv(4))
|
|
elif address_type == 3: # Domain name
|
|
domain_length = ord(self.connection.recv(1)[0])
|
|
address = self.connection.recv(domain_length)
|
|
|
|
port = struct.unpack('!H', self.connection.recv(2))[0]
|
|
|
|
# 代理服务器对url请求在尝试进行连接之后,向客户端进行连接状态的答复
|
|
try:
|
|
if cmd == 1: # CONNECT
|
|
remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
remote.connect((address, port))
|
|
bind_address = remote.getsockname()
|
|
logging.info('Connected to %s %s' % (address, port))
|
|
else:
|
|
self.server.close_request(self.request)
|
|
|
|
addr = struct.unpack("!I", socket.inet_aton(bind_address[0]))[0]
|
|
port = bind_address[1]
|
|
reply = struct.pack("!BBBBIH", SOCKS_VERSION, 0, 0, address_type,
|
|
addr, port)
|
|
|
|
except Exception as err:
|
|
logging.error(err)
|
|
reply = self.generate_failed_reply(address_type, 5)
|
|
|
|
self.connection.sendall(reply)
|
|
|
|
# 建立一个数据交换连接
|
|
if reply[1] == 0 and cmd == 1:
|
|
self.exchange_loop(self.connection, remote)
|
|
|
|
# 数据交换结束,关闭此次代理请求
|
|
self.server.close_request(self.request)
|
|
|
|
def get_available_methods(self, n):
|
|
methods = []
|
|
for i in range(n):
|
|
methods.append(ord(self.connection.recv(1)))
|
|
return methods
|
|
|
|
# 代理服务器对发生错误的url请求进行
|
|
def generate_failed_reply(self, address_type, error_number):
|
|
return struct.pack("!BBBBIH", SOCKS_VERSION, error_number, 0, address_type, 0, 0)
|
|
|
|
# 作为代理服务器,交换客户端与远程目的服务器的数据
|
|
def exchange_loop(self, client, remote):
|
|
count = 0
|
|
while True:
|
|
count = count + 1
|
|
r, w, e = select.select([client, remote], [], [])
|
|
|
|
# 如果client监听到了来自客户端的数据,读取这个数据;
|
|
# 并让remoto发送这个数据到远程目的服务器。
|
|
if client in r:
|
|
data = client.recv(4096)
|
|
print("client recv: " )
|
|
if remote.send(data) <= 0:
|
|
break
|
|
|
|
# 如果remote监听到了来自远程目的服务器的数据,读取这个数据;
|
|
# 并让client发送给客户端。
|
|
if remote in r:
|
|
data = remote.recv(4096)
|
|
print("server recv: " )
|
|
if client.send(data) <= 0:
|
|
break
|
|
|
|
if __name__ == '__main__':
|
|
# 创建一个代理服务器监听
|
|
with ThreadingTCPServer(('127.0.0.1', 9011), SocksProxy) as server:
|
|
server.serve_forever()
|
|
|
|
# curl -v --socks5 127.0.0.1:9011 https://github.com
|