Browse Source

update: detailed exception thrown of ProxyBuilder

master
Dnomd343 2 years ago
parent
commit
3c6743f23b
  1. 143
      ProxyBuilder/builder.py
  2. 105
      demo.py
  3. 4
      test.py

143
ProxyBuilder/builder.py

@ -36,12 +36,18 @@ def __checkPortAvailable(port): # 检测端口可用性
return True # IPv4 TCP / IPv4 UDP / IPv6 TCP / IPv6 UDP 均无占用
except:
return False
finally:
try: # 关闭socket
if ipv4_tcp: ipv4_tcp.close()
if ipv4_udp: ipv4_udp.close()
if ipv6_tcp: ipv6_tcp.close()
if ipv6_udp: ipv6_udp.close()
finally: # 关闭socket
try:
ipv4_tcp.close()
except: pass
try:
ipv4_udp.close()
except: pass
try:
ipv6_tcp.close()
except: pass
try:
ipv6_udp.close()
except: pass
def __genTaskFlag(length = 16): # 生成任务代号
@ -63,11 +69,28 @@ def __getAvailablePort(rangeStart, rangeEnd): # 获取一个空闲端口
return port
time.sleep(0.1) # 100ms
def build(proxyInfo, configDir): # 构建代理节点连接
taskFlag = __genTaskFlag()
socksPort = __getAvailablePort(1024, 65535) # Socks5测试端口
if not 'type' in proxyInfo:
return None
def build(proxyInfo, configDir, portRangeStart = 1024, portRangeEnd = 65535):
'''
创建代理节点客户端
程序内部错误:
return None, {reason}
代理节点无效:
return False, {reason}
代理工作正常:
return True, {
'flag': taskFlag,
'port': socksPort,
'file': configFile,
'process': process
}
'''
taskFlag = __genTaskFlag() # 生成测试标志
socksPort = __getAvailablePort(portRangeStart, portRangeEnd) # 获取Socks5测试端口
if not 'type' in proxyInfo: # 未指定节点类型
return False, 'Proxy type not specified'
proxyType = proxyInfo['type'] # 节点类型
proxyInfo.pop('type')
@ -77,19 +100,16 @@ def build(proxyInfo, configDir): # 构建代理节点连接
elif proxyType == 'ssr': # ShadowsocksR节点
startCommand, fileContent = ShadowsocksR.load(proxyInfo, socksPort, configFile)
else: # 未知类型
print("Unknown proxy type")
return None
return False, 'Unknown proxy type'
if startCommand == None: # 格式出错
print("Format error with " + proxyType)
return None
return False, 'Format error with ' + str(proxyType)
try:
with open(configFile, 'w') as fileObject:
fileObject.write(fileContent) # 保存配置文件
except:
print("Unable write to file " + configFile)
return None # 配置文件写入失败
except: # 配置文件写入失败
return None, "Unable write to file " + str(configFile)
try:
try: # 子进程形式启动
for libcPath in libcPaths:
if os.path.exists(libcPath): # 定位libc.so文件
break
@ -99,37 +119,68 @@ def build(proxyInfo, configDir): # 构建代理节点连接
stderr = subprocess.DEVNULL,
preexec_fn = exitWithMe) # 子进程跟随退出
except:
print("WARNING: Subprocess may become a Orphan Process")
process = subprocess.Popen(startCommand,
stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL) # prctl失败 回退正常启动
try:
process = subprocess.Popen(startCommand,
stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL) # prctl失败 回退正常启动
except: pass
if not 'process' in vars(): # 启动失败
return None, 'Subprocess start failed by `' + ' '.join(startCommand) + '`'
return { # 返回连接参数
return True, { # 返回连接参数
'flag': taskFlag,
'port': socksPort,
'file': configFile,
'process': process,
'pid': process.pid,
'process': process
}
def check(taskInfo): # 检查客户端是否正常
if taskInfo == None:
return False
process = taskInfo['process']
if process.poll() != None:
return False # 死亡
else:
return True # 正常
def destroy(taskInfo): # 结束客户端并清理
if taskInfo == None:
return
process = taskInfo['process']
if process.poll() == None: # 未死亡
process.terminate() # SIGTERM
while process.poll() == None: # 等待退出
time.sleep(1)
process.terminate()
def check(client):
'''
检查客户端是否正常运行
检测出错: return None
工作异常: return False
工作正常: return True
'''
if client == None:
return None
try:
if client['process'].poll() != None:
return False # 死亡
else:
return True # 正常
except:
return None # 异常
def destroy(client):
'''
结束客户端并清理
销毁异常: return None
客户端退出: return True
'''
if client == None:
return None
try:
os.remove(taskInfo['file']) # 删除配置文件
except: pass
process = client['process']
if process.poll() == None: # 未死亡
process.terminate() # SIGTERM
while process.poll() == None: # 等待退出
time.sleep(1)
process.terminate()
except:
return None
try:
file = client['file']
if os.path.exists(file) and os.path.isfile(file):
os.remove(file) # 删除配置文件
else:
return None
except:
return None
return True # 销毁完成

105
demo.py

@ -1,50 +1,81 @@
#!/usr/bin/python
# -*- coding:utf-8 -*-
import os
import time
import socket
import requests
import ProxyBuilder as Builder
import ProxyChecker as Checker
testInfo = {
'type': 'ss',
'server': '127.0.0.1',
'port': 12345,
'password': 'dnomd343',
'method': 'aes-256-ctr',
'plugin': '',
'pluginParam': '',
workDir = '/tmp/ProxyC'
ssTest = {
'tag': 'f43c9bae21ae8693',
'check': [
'http'
],
'info': {
'type': 'ss',
'server': '127.0.0.1',
'port': 12345,
'password': 'dnomd343',
'method': 'aes-256-ctr',
'plugin': '',
'pluginParam': '',
}
}
ssrTest = {
'tag': 'f43c9bae21ae8693',
'check': [
'http'
],
'info': {
'type': 'ssr',
"server": "127.0.0.1",
"port": 23456,
"password": "dnomd343",
"method": "table",
"protocol": "auth_aes128_md5",
"protocolParam": "",
"obfs": "tls1.2_ticket_auth",
"obfsParam": ""
}
}
# testInfo = {
# '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")
print(testInfo)
task = Builder.build(testInfo, '/tmp/ProxyC')
print(task)
time.sleep(1)
if Builder.check(task) == False:
print("error exit")
Builder.destroy(task)
else:
print("http check")
health, delay = Checker.httpCheck(task['port'])
def loadDir(folderPath): # 创建文件夹
try:
if os.path.exists(folderPath): # 文件 / 文件夹 存在
if not os.path.isdir(folderPath): # 文件
return False # 无法创建
else: # 不存在
os.makedirs(folderPath) # 递归创建文件夹
return True # 文件夹正常
except:
return False
def proxyTest(rawInfo, startDelay = 1, destroyDelay = 0.5):
if loadDir(workDir) == False: # 工作文件夹无效
return None
if not 'info' in rawInfo:
return None
status, client = Builder.build(rawInfo['info'], workDir)
if status != True:
print(client)
return None
time.sleep(startDelay)
if Builder.check(client) != True:
print("client error")
return None
health, httpDelay = Checker.httpCheck(client['port'])
print("health = " + str(health))
if delay < 0:
print("error")
if httpDelay < 0:
print("http error")
else:
print("delay = " + format(delay, '.2f') + 'ms')
Builder.destroy(task)
print("delay = " + format(httpDelay, '.2f') + 'ms')
if Builder.destroy(client) != True:
print("client destroy error")
time.sleep(destroyDelay)
print("done")
proxyTest(ssrTest)

4
test.py

@ -23,9 +23,9 @@ def startTest(testList):
print("server unexpected exit")
continue
print(field['caption'] + ' => ', end = '')
client = Builder.build(field['proxyInfo'], '/tmp/ProxyC')
status, client = Builder.build(field['proxyInfo'], '/tmp/ProxyC')
time.sleep(0.5) # 等待初始化完成
if not Builder.check(client):
if Builder.check(client) != True:
print("client unexpected exit") # 客户端启动失败
else:
print(format(Checker.httpPing(client['port']), '.2f') + 'ms')

Loading…
Cancel
Save