Files
http_vpn/socks5_demo_201909/Python版/server.py
T
2020-02-23 20:44:48 +08:00

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