Browse Source

update: next subprocess exec and kill process group

master
Dnomd343 3 years ago
parent
commit
ab66f9fca8
  1. 37
      ProxyBuilder/builder.py
  2. 6
      ProxyTester/TrojanGo.py
  3. 5
      Test.py
  4. 11
      demo.py

37
ProxyBuilder/builder.py

@ -17,13 +17,21 @@ from ProxyBuilder import Trojan
from ProxyBuilder import TrojanGo from ProxyBuilder import TrojanGo
libcPaths = [ libcPaths = [
'/usr/lib64/libc.so.6', # CentOS '/usr/lib/libc.so.6', # CentOS
'/lib/libc.musl-x86_64.so.1', # Alpine '/usr/lib64/libc.so.6',
'/lib/libc.musl-i386.so.1', # Alpine
'/lib/libc.musl-x86_64.so.1',
'/lib/libc.musl-aarch64.so.1',
'/lib/i386-linux-gnu/libc.so.6', # Debian / Ubuntu '/lib/i386-linux-gnu/libc.so.6', # Debian / Ubuntu
'/lib/x86_64-linux-gnu/libc.so.6', '/lib/x86_64-linux-gnu/libc.so.6',
'/lib/aarch64-linux-gnu/libc.so.6', '/lib/aarch64-linux-gnu/libc.so.6',
] ]
def __preExec(libcPath) -> None:
ctypes.CDLL(libcPath).prctl(1, signal.SIGTERM) # 子进程跟随退出
os.setpgrp() # 新进程组
def __checkPortAvailable(port: int) -> bool: # 检测端口可用性 def __checkPortAvailable(port: int) -> bool: # 检测端口可用性
ipv4_tcp = None ipv4_tcp = None
ipv4_udp = None ipv4_udp = None
@ -59,6 +67,7 @@ def __checkPortAvailable(port: int) -> bool: # 检测端口可用性
ipv6_udp.close() ipv6_udp.close()
except: pass except: pass
def __genTaskFlag(length: int = 16) -> str: # 生成任务标志 def __genTaskFlag(length: int = 16) -> str: # 生成任务标志
flag = '' flag = ''
for i in range(0, length): for i in range(0, length):
@ -69,6 +78,7 @@ def __genTaskFlag(length: int = 16) -> str: # 生成任务标志
flag += str(tmp) # 0 ~ 9 flag += str(tmp) # 0 ~ 9
return flag return flag
def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or None: # 获取一个空闲端口 def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or None: # 获取一个空闲端口
if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535: if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535:
return None return None
@ -78,6 +88,7 @@ def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or
return port return port
time.sleep(0.1) # wait for 100ms time.sleep(0.1) # wait for 100ms
def build(proxyInfo: dict, configDir: str, def build(proxyInfo: dict, configDir: str,
portRangeStart: int = 1024, portRangeEnd: int = 65535) -> tuple[bool, str or dict]: portRangeStart: int = 1024, portRangeEnd: int = 65535) -> tuple[bool, str or dict]:
""" """
@ -135,7 +146,7 @@ def build(proxyInfo: dict, configDir: str,
env = envVar, env = envVar,
stdout = subprocess.DEVNULL, stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL, stderr = subprocess.DEVNULL,
preexec_fn = lambda: ctypes.CDLL(libcPath).prctl(1, 15) # 子进程跟随退出 preexec_fn = lambda: __preExec(libcPath)
) )
except: except:
process = subprocess.Popen( # prctl失败 回退正常启动 process = subprocess.Popen( # prctl失败 回退正常启动
@ -154,6 +165,7 @@ def build(proxyInfo: dict, configDir: str,
'process': process 'process': process
} }
def check(client: dict) -> bool or None: def check(client: dict) -> bool or None:
""" """
检查客户端是否正常运行 检查客户端是否正常运行
@ -164,8 +176,6 @@ def check(client: dict) -> bool or None:
""" """
return client['process'].poll() is None return client['process'].poll() is None
def skipDestroy() -> None:
pass
def destroy(client: dict) -> bool: def destroy(client: dict) -> bool:
""" """
@ -175,21 +185,18 @@ def destroy(client: dict) -> bool:
销毁成功: return True 销毁成功: return True
""" """
signal.signal(signal.SIGINT, skipDestroy) # 捕获SIGINT
signal.signal(signal.SIGTERM, skipDestroy) # 捕获SIGTERM
try: try:
maxTermTime = 100 # SIGTERM -> SIGKILL
process = client['process'] process = client['process']
os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 杀进程组 os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 杀死子进程组
time.sleep(0.2) time.sleep(0.2)
maxWait = 100
if process.poll() is None: # 未死亡
while process.poll() is None: # 等待退出 while process.poll() is None: # 等待退出
process.terminate() # SIGTERM maxTermTime -= 1
if maxTermTime < 0:
process.kill() # SIGKILL -> force kill
else:
process.terminate() # SIGTERM -> soft kill
time.sleep(0.2) time.sleep(0.2)
maxWait -= 1
if maxWait < 0:
process.kill() # SIGKILL
time.sleep(0.5)
except: except:
return False return False

6
ProxyTester/TrojanGo.py

@ -152,13 +152,13 @@ def trojanGoTest(trojanGoConfig: dict) -> list:
for key, value in trojanGoConfig.items(): # trojanGoConfig -> config for key, value in trojanGoConfig.items(): # trojanGoConfig -> config
config[key] = value config[key] = value
result += loadTrojanGoConfig([loadTrojanGo(False, None)]) result += loadTrojanGoConfig([loadTrojanGo(False, None)]) # basic test
result += loadTrojanGoConfig([loadTrojanGo(True, None)]) result += loadTrojanGoConfig([loadTrojanGo(True, None)])
for ssMethod in trojanGoMethod: for ssMethod in trojanGoMethod:
result += loadTrojanGoConfig([loadTrojanGo(False, ssMethod)]) result += loadTrojanGoConfig([loadTrojanGo(False, ssMethod)]) # basic test with shadowsocks
result += loadTrojanGoConfig([loadTrojanGo(True, ssMethod)]) result += loadTrojanGoConfig([loadTrojanGo(True, ssMethod)])
for plugin in sip003PluginList: for plugin in sip003PluginList: # plugin test -> cause zombie process (imperfect trojan-go)
result += loadTrojanGoConfig(loadTrojanGoPlugin(plugin)) result += loadTrojanGoConfig(loadTrojanGoPlugin(plugin))
return result return result

5
Test.py

@ -4,6 +4,7 @@
import os import os
import sys import sys
import time import time
import signal
import subprocess import subprocess
import Check as Checker import Check as Checker
@ -31,11 +32,13 @@ def testBuild(config: dict): # load file and start process
config['startCommand'], config['startCommand'],
env = config['envVar'], env = config['envVar'],
stdout = subprocess.DEVNULL, stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL stderr = subprocess.DEVNULL,
preexec_fn = os.setpgrp # new process group
) )
def testDestroy(config: dict, process): # remove file and kill process def testDestroy(config: dict, process): # remove file and kill process
if process is not None and process.poll() is None: # still alive if process is not None and process.poll() is None: # still alive
os.killpg(os.getpgid(process.pid), signal.SIGTERM) # kill process group
while process.poll() is None: # wait for exit while process.poll() is None: # wait for exit
process.terminate() # SIGTERM process.terminate() # SIGTERM
time.sleep(0.2) time.sleep(0.2)

11
demo.py

@ -1,3 +1,5 @@
import time
import ProxyBuilder as Builder import ProxyBuilder as Builder
import ProxyDecoder as Decoder import ProxyDecoder as Decoder
import ProxyFilter as Filter import ProxyFilter as Filter
@ -10,8 +12,6 @@ info = {
'passwd': 'dnomd343', 'passwd': 'dnomd343',
'sni': 'local.343.re', 'sni': 'local.343.re',
'plugin': { 'plugin': {
# 'type': 'obfs-local',
# 'param': 'obfs=http;obfs-host=www.bing.com'
'type': 'simple-tls', 'type': 'simple-tls',
'param': 'n=local.343.re;no-verify' 'param': 'n=local.343.re;no-verify'
} }
@ -27,3 +27,10 @@ data = Checker.proxyTest({
}) })
print(data) print(data)
# status, client = Builder.build(ret, '/tmp/ProxyC')
# print(status)
# print(client)
#
# time.sleep(300)
# Builder.destroy(client)

Loading…
Cancel
Save