From 79336f90de651858142e0402bf5b21281b376f18 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Tue, 8 Feb 2022 14:37:22 +0800 Subject: [PATCH] feat: ssr build supported, struct adjustment --- ProxyBuilder/Shadowsocks.py | 16 ++---- ProxyBuilder/ShadowsocksR.py | 94 ++++++++++++++++++++++++++++++++++++ ProxyBuilder/main.py | 25 ++++++++-- demo.py | 32 +++++++++--- 4 files changed, 144 insertions(+), 23 deletions(-) create mode 100644 ProxyBuilder/ShadowsocksR.py diff --git a/ProxyBuilder/Shadowsocks.py b/ProxyBuilder/Shadowsocks.py index f260984..c21cd56 100644 --- a/ProxyBuilder/Shadowsocks.py +++ b/ProxyBuilder/Shadowsocks.py @@ -173,9 +173,8 @@ def __pluginUdpCheck(plugin, pluginArg): # 插件是否使用UDP通讯 if plugin in onlyUdpPlugin: return True if plugin == 'v2ray-plugin' or plugin == 'xray-plugin' or plugin == 'gost-plugin': - if 'mode=quic' in pluginArg.split(';'): - return True - return False + if not 'mode=quic' in pluginArg.split(';'): + return False return True # 默认假定占用UDP def __ssPython(proxyInfo, socksPort, isLegacy = False): # ss-python配置文件生成 @@ -216,7 +215,7 @@ def __ssRust(proxyInfo, socksPort): # ss-rust配置文件生成 jsonContent['mode'] = 'tcp_and_udp' return jsonContent, 'ss-rust-local' -def load(proxyInfo, socksPort, configFile): # shadowsocks配置载入 +def load(proxyInfo, socksPort, configFile): # Shadowsocks配置载入 proxyInfo['udp'] = not __pluginUdpCheck(proxyInfo['plugin'], proxyInfo['pluginArg']) if proxyInfo['method'] in ssMethodList['ss-libev']: jsonContent, ssFile = __ssLibev(proxyInfo, socksPort) @@ -229,10 +228,5 @@ def load(proxyInfo, socksPort, configFile): # shadowsocks配置载入 elif proxyInfo['method'] in ssMethodList['ss-rust']: jsonContent, ssFile = __ssRust(proxyInfo, socksPort) else: - return None # 匹配不到加密方式 - try: - with open(configFile, 'w') as fileObject: - fileObject.write(json.dumps(jsonContent)) # 保存配置文件 - except: - return None # 配置文件写入失败 - return [ ssFile, '-c', configFile ] + return None, None # 匹配不到加密方式 + return [ ssFile, '-c', configFile ], json.dumps(jsonContent) diff --git a/ProxyBuilder/ShadowsocksR.py b/ProxyBuilder/ShadowsocksR.py new file mode 100644 index 0000000..617790d --- /dev/null +++ b/ProxyBuilder/ShadowsocksR.py @@ -0,0 +1,94 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +import json + +ssrMethodList = [ # 加密方法 + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-cfb1", + "aes-192-cfb1", + "aes-256-cfb1", + "aes-128-cfb8", + "aes-192-cfb8", + "aes-256-cfb8", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "aes-128-gcm", + "aes-192-gcm", + "aes-256-gcm", + "aes-128-ofb", + "aes-192-ofb", + "aes-256-ofb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "none", + "table", + "rc4", + "rc4-md5", + "rc4-md5-6", + "bf-cfb", + "cast5-cfb", + "des-cfb", + "idea-cfb", + "seed-cfb", + "rc2-cfb", + "salsa20", + "xsalsa20", + "chacha20", + "xchacha20", + "chacha20-ietf", +] + +ssrProtocolList = [ # 协议 + "origin", + "verify_sha1", + "verify_simple", + "verify_deflate", + "auth_simple", + "auth_sha1", + "auth_sha1_v2", + "auth_sha1_v4", + "auth_aes128", + "auth_aes128_md5", + "auth_aes128_sha1", + "auth_chain_a", + "auth_chain_b", + "auth_chain_c", + "auth_chain_d", + "auth_chain_e", + "auth_chain_f", +] + +ssrObfsList = [ # 混淆方式 + "plain", + "http_post", + "http_simple", + "tls_simple", + "tls1.2_ticket_auth", + "tls1.2_ticket_fastauth", + "random_head", +] + +def load(proxyInfo, socksPort, configFile): # ShadowsocksR配置载入 + if not proxyInfo['method'] in ssrMethodList: + return None, None # 匹配不到加密方法 + if not proxyInfo['protocol'] in ssrProtocolList: + return None, None # 匹配不到协议 + if not proxyInfo['obfs'] in ssrObfsList: + return None, None # 匹配不到混淆方式 + return [ 'ssr-local', '-c', configFile ], json.dumps({ + 'server': proxyInfo['server'], + 'server_port': proxyInfo['port'], + 'local_address': '127.0.0.1', + 'local_port': socksPort, + 'password': proxyInfo['password'], + 'method': proxyInfo['method'], + 'protocol': proxyInfo['protocol'], + 'protocol_param': proxyInfo['protocolParam'], + 'obfs': proxyInfo['obfs'], + 'obfs_param': proxyInfo['obfsParam'] + }) \ No newline at end of file diff --git a/ProxyBuilder/main.py b/ProxyBuilder/main.py index 39e1458..18409fd 100644 --- a/ProxyBuilder/main.py +++ b/ProxyBuilder/main.py @@ -8,6 +8,7 @@ import random import socket import subprocess from ProxyBuilder import Shadowsocks +from ProxyBuilder import ShadowsocksR libcPaths = [ '/usr/lib64/libc.so.6', # CentOS @@ -31,11 +32,11 @@ def __checkPortAvailable(port): # 检测端口可用性 ipv6_udp.bind(('::', port)) ipv6_tcp.close() ipv6_udp.close() - return True + return True # IPv4 TCP / IPv4 UDP / IPv6 TCP / IPv6 UDP 均无占用 except: return False finally: - try: + try: # 关闭socket if ipv4_tcp: ipv4_tcp.close() if ipv4_udp: ipv4_udp.close() if ipv6_tcp: ipv6_tcp.close() @@ -70,10 +71,20 @@ def build(proxyInfo, configDir): # 构建代理节点连接 proxyInfo.pop('type') configFile = configDir + '/' + taskFlag + '.json' # 配置文件路径 - if (proxyType == 'shadowsocks'): # Shadowsocks节点 - startCommand = Shadowsocks.load(proxyInfo, socksPort, configFile) + if proxyType == 'ss': # Shadowsocks节点 + startCommand, fileContent = Shadowsocks.load(proxyInfo, socksPort, configFile) + elif proxyType == 'ssr': # ShadowsocksR节点 + startCommand, fileContent = ShadowsocksR.load(proxyInfo, socksPort, configFile) else: # 未知类型 return None + if startCommand == None: # 格式出错 + return None + try: + with open(configFile, 'w') as fileObject: + fileObject.write(fileContent) # 保存配置文件 + except: + print("Unable write to file " + configFile) + return None # 配置文件写入失败 try: for libcPath in libcPaths: @@ -98,6 +109,8 @@ def build(proxyInfo, configDir): # 构建代理节点连接 } def check(taskInfo): # 检查客户端是否正常 + if taskInfo == None: + return False process = taskInfo['process'] if process.poll() != None: return False # 死亡 @@ -105,6 +118,8 @@ def check(taskInfo): # 检查客户端是否正常 return True # 正常 def destroy(taskInfo): # 结束客户端并清理 + if taskInfo == None: + return process = taskInfo['process'] if process.poll() == None: # 未死亡 process.terminate() # SIGTERM @@ -112,5 +127,5 @@ def destroy(taskInfo): # 结束客户端并清理 time.sleep(1) process.terminate() try: - os.remove(taskInfo.file) # 删除配置文件 + os.remove(taskInfo['file']) # 删除配置文件 except: pass diff --git a/demo.py b/demo.py index 9ab8e51..28d0d59 100644 --- a/demo.py +++ b/demo.py @@ -5,23 +5,38 @@ import ProxyBuilder def checkSocksPort(port): try: + startTime = time.time_ns() r = requests.get('http://gstatic.com/generate_204', proxies = { 'http': 'socks5://127.0.0.1:' + str(port), 'https': 'socks5://127.0.0.1:' + str(port), }) if r.status_code == 204: + delay = (time.time_ns() - startTime) / (10 ** 6) + print(format(delay, '.2f') + 'ms') return True except: pass return False +# testInfo = { +# 'type': 'ss', +# 'server': '127.0.0.1', +# 'port': 12345, +# 'password': 'dnomd343', +# 'method': 'aes-256-ctr', +# 'plugin': '', +# 'pluginArg': '', +# } + testInfo = { - 'type': 'shadowsocks', - 'server': '127.0.0.1', - 'port': 12345, - 'password': 'dnomd343', - 'method': 'aes-256-ctr', - 'plugin': '', - 'pluginArg': '', + 'type': 'ssr', + "server": "127.0.0.1", + "port": 23456, + "password": "dnomd343", + "method": "table", + "protocol": "auth_aes128_md5", + "protocolParam": "", + "obfs": "tls1.2_ticket_auth", + "obfsParam": "" } print("start") @@ -33,6 +48,9 @@ if ProxyBuilder.check(task) == False: print("error exit") else: print("test with gstatic") + checkSocksPort(task['port']) + checkSocksPort(task['port']) + checkSocksPort(task['port']) if checkSocksPort(task['port']): print("ok") else: