Browse Source

update: detailed exception thrown of ProxyBuilder

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

119
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
工作正常: return True
'''
if client == None:
return None
try:
if client['process'].poll() != None:
return False # 死亡 return False # 死亡
else: else:
return True # 正常 return True # 正常
except:
return None # 异常
def destroy(client):
'''
结束客户端并清理
销毁异常: return None
def destroy(taskInfo): # 结束客户端并清理 客户端退出: return True
if taskInfo == None: '''
return if client == None:
process = taskInfo['process'] return None
try:
process = client['process']
if process.poll() == None: # 未死亡 if process.poll() == None: # 未死亡
process.terminate() # SIGTERM process.terminate() # SIGTERM
while process.poll() == None: # 等待退出 while process.poll() == None: # 等待退出
time.sleep(1) time.sleep(1)
process.terminate() process.terminate()
except:
return None
try: try:
os.remove(taskInfo['file']) # 删除配置文件 file = client['file']
except: pass if os.path.exists(file) and os.path.isfile(file):
os.remove(file) # 删除配置文件
else:
return None
except:
return None
return True # 销毁完成

91
demo.py

@ -1,14 +1,20 @@
#!/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'
ssTest = {
'tag': 'f43c9bae21ae8693',
'check': [
'http'
],
'info': {
'type': 'ss', 'type': 'ss',
'server': '127.0.0.1', 'server': '127.0.0.1',
'port': 12345, 'port': 12345,
@ -17,34 +23,59 @@ testInfo = {
'plugin': '', 'plugin': '',
'pluginParam': '', 'pluginParam': '',
} }
}
# testInfo = { ssrTest = {
# 'type': 'ssr', 'tag': 'f43c9bae21ae8693',
# "server": "127.0.0.1", 'check': [
# "port": 23456, 'http'
# "password": "dnomd343", ],
# "method": "table", 'info': {
# "protocol": "auth_aes128_md5", 'type': 'ssr',
# "protocolParam": "", "server": "127.0.0.1",
# "obfs": "tls1.2_ticket_auth", "port": 23456,
# "obfsParam": "" "password": "dnomd343",
# } "method": "table",
"protocol": "auth_aes128_md5",
print("start") "protocolParam": "",
print(testInfo) "obfs": "tls1.2_ticket_auth",
task = Builder.build(testInfo, '/tmp/ProxyC') "obfsParam": ""
print(task) }
time.sleep(1) }
if Builder.check(task) == False:
print("error exit") def loadDir(folderPath): # 创建文件夹
Builder.destroy(task) try:
else: if os.path.exists(folderPath): # 文件 / 文件夹 存在
print("http check") if not os.path.isdir(folderPath): # 文件
health, delay = Checker.httpCheck(task['port']) 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)) 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