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 均无占用 return True # IPv4 TCP / IPv4 UDP / IPv6 TCP / IPv6 UDP 均无占用
except: except:
return False return False
finally: finally: # 关闭socket
try: # 关闭socket try:
if ipv4_tcp: ipv4_tcp.close() ipv4_tcp.close()
if ipv4_udp: ipv4_udp.close() except: pass
if ipv6_tcp: ipv6_tcp.close() try:
if ipv6_udp: ipv6_udp.close() ipv4_udp.close()
except: pass
try:
ipv6_tcp.close()
except: pass
try:
ipv6_udp.close()
except: pass except: pass
def __genTaskFlag(length = 16): # 生成任务代号 def __genTaskFlag(length = 16): # 生成任务代号
@ -63,11 +69,28 @@ def __getAvailablePort(rangeStart, rangeEnd): # 获取一个空闲端口
return port return port
time.sleep(0.1) # 100ms time.sleep(0.1) # 100ms
def build(proxyInfo, configDir): # 构建代理节点连接 def build(proxyInfo, configDir, portRangeStart = 1024, portRangeEnd = 65535):
taskFlag = __genTaskFlag() '''
socksPort = __getAvailablePort(1024, 65535) # Socks5测试端口 创建代理节点客户端
if not 'type' in proxyInfo:
return None 程序内部错误:
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'] # 节点类型 proxyType = proxyInfo['type'] # 节点类型
proxyInfo.pop('type') proxyInfo.pop('type')
@ -77,19 +100,16 @@ def build(proxyInfo, configDir): # 构建代理节点连接
elif proxyType == 'ssr': # ShadowsocksR节点 elif proxyType == 'ssr': # ShadowsocksR节点
startCommand, fileContent = ShadowsocksR.load(proxyInfo, socksPort, configFile) startCommand, fileContent = ShadowsocksR.load(proxyInfo, socksPort, configFile)
else: # 未知类型 else: # 未知类型
print("Unknown proxy type") return False, 'Unknown proxy type'
return None
if startCommand == None: # 格式出错 if startCommand == None: # 格式出错
print("Format error with " + proxyType) return False, 'Format error with ' + str(proxyType)
return None
try: try:
with open(configFile, 'w') as fileObject: with open(configFile, 'w') as fileObject:
fileObject.write(fileContent) # 保存配置文件 fileObject.write(fileContent) # 保存配置文件
except: except: # 配置文件写入失败
print("Unable write to file " + configFile) return None, "Unable write to file " + str(configFile)
return None # 配置文件写入失败
try: try: # 子进程形式启动
for libcPath in libcPaths: for libcPath in libcPaths:
if os.path.exists(libcPath): # 定位libc.so文件 if os.path.exists(libcPath): # 定位libc.so文件
break break
@ -99,37 +119,68 @@ def build(proxyInfo, configDir): # 构建代理节点连接
stderr = subprocess.DEVNULL, stderr = subprocess.DEVNULL,
preexec_fn = exitWithMe) # 子进程跟随退出 preexec_fn = exitWithMe) # 子进程跟随退出
except: except:
print("WARNING: Subprocess may become a Orphan Process") try:
process = subprocess.Popen(startCommand, process = subprocess.Popen(startCommand,
stdout = subprocess.DEVNULL, stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL) # prctl失败 回退正常启动 stderr = subprocess.DEVNULL) # prctl失败 回退正常启动
except: pass
if not 'process' in vars(): # 启动失败
return None, 'Subprocess start failed by `' + ' '.join(startCommand) + '`'
return { # 返回连接参数 return True, { # 返回连接参数
'flag': taskFlag, 'flag': taskFlag,
'port': socksPort, 'port': socksPort,
'file': configFile, 'file': configFile,
'process': process, 'process': process
'pid': process.pid,
} }
def check(taskInfo): # 检查客户端是否正常 def check(client):
if taskInfo == None: '''
return False 检查客户端是否正常运行
process = taskInfo['process']
if process.poll() != None: 检测出错: return None
return False # 死亡
else: 工作异常: return False
return True # 正常
工作正常: return True
def destroy(taskInfo): # 结束客户端并清理 '''
if taskInfo == None: if client == None:
return return None
process = taskInfo['process'] try:
if process.poll() == None: # 未死亡 if client['process'].poll() != None:
process.terminate() # SIGTERM return False # 死亡
while process.poll() == None: # 等待退出 else:
time.sleep(1) return True # 正常
process.terminate() except:
return None # 异常
def destroy(client):
'''
结束客户端并清理
销毁异常: return None
客户端退出: return True
'''
if client == None:
return None
try: try:
os.remove(taskInfo['file']) # 删除配置文件 process = client['process']
except: pass 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 #!/usr/bin/python
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import os
import time import time
import socket
import requests
import ProxyBuilder as Builder import ProxyBuilder as Builder
import ProxyChecker as Checker import ProxyChecker as Checker
testInfo = { workDir = '/tmp/ProxyC'
'type': 'ss',
'server': '127.0.0.1', ssTest = {
'port': 12345, 'tag': 'f43c9bae21ae8693',
'password': 'dnomd343', 'check': [
'method': 'aes-256-ctr', 'http'
'plugin': '', ],
'pluginParam': '', '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 = { def loadDir(folderPath): # 创建文件夹
# 'type': 'ssr', try:
# "server": "127.0.0.1", if os.path.exists(folderPath): # 文件 / 文件夹 存在
# "port": 23456, if not os.path.isdir(folderPath): # 文件
# "password": "dnomd343", return False # 无法创建
# "method": "table", else: # 不存在
# "protocol": "auth_aes128_md5", os.makedirs(folderPath) # 递归创建文件夹
# "protocolParam": "", return True # 文件夹正常
# "obfs": "tls1.2_ticket_auth", except:
# "obfsParam": "" return False
# }
def proxyTest(rawInfo, startDelay = 1, destroyDelay = 0.5):
print("start") if loadDir(workDir) == False: # 工作文件夹无效
print(testInfo) return None
task = Builder.build(testInfo, '/tmp/ProxyC') if not 'info' in rawInfo:
print(task) return None
time.sleep(1) status, client = Builder.build(rawInfo['info'], workDir)
if Builder.check(task) == False: if status != True:
print("error exit") print(client)
Builder.destroy(task) return None
else: time.sleep(startDelay)
print("http check") if Builder.check(client) != True:
health, delay = Checker.httpCheck(task['port']) print("client error")
return None
health, httpDelay = Checker.httpCheck(client['port'])
print("health = " + str(health)) print("health = " + str(health))
if delay < 0: if httpDelay < 0:
print("error") print("http error")
else: else:
print("delay = " + format(delay, '.2f') + 'ms') print("delay = " + format(httpDelay, '.2f') + 'ms')
Builder.destroy(task) if Builder.destroy(client) != True:
print("client destroy error")
time.sleep(destroyDelay)
print("done") print("done")
proxyTest(ssrTest)

4
test.py

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

Loading…
Cancel
Save