From ab66f9fca8b074e22f4acf4257c32b0e32fe0a5c Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Wed, 2 Mar 2022 11:12:17 +0800 Subject: [PATCH] update: next subprocess exec and kill process group --- ProxyBuilder/builder.py | 41 ++++++++++++++++++++++++----------------- ProxyTester/TrojanGo.py | 6 +++--- Test.py | 5 ++++- demo.py | 11 +++++++++-- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/ProxyBuilder/builder.py b/ProxyBuilder/builder.py index d33dfe0..938b586 100644 --- a/ProxyBuilder/builder.py +++ b/ProxyBuilder/builder.py @@ -17,13 +17,21 @@ from ProxyBuilder import Trojan from ProxyBuilder import TrojanGo libcPaths = [ - '/usr/lib64/libc.so.6', # CentOS - '/lib/libc.musl-x86_64.so.1', # Alpine + '/usr/lib/libc.so.6', # CentOS + '/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/x86_64-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: # 检测端口可用性 ipv4_tcp = None ipv4_udp = None @@ -59,6 +67,7 @@ def __checkPortAvailable(port: int) -> bool: # 检测端口可用性 ipv6_udp.close() except: pass + def __genTaskFlag(length: int = 16) -> str: # 生成任务标志 flag = '' for i in range(0, length): @@ -69,6 +78,7 @@ def __genTaskFlag(length: int = 16) -> str: # 生成任务标志 flag += str(tmp) # 0 ~ 9 return flag + def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or None: # 获取一个空闲端口 if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535: return None @@ -78,6 +88,7 @@ def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or return port time.sleep(0.1) # wait for 100ms + def build(proxyInfo: dict, configDir: str, portRangeStart: int = 1024, portRangeEnd: int = 65535) -> tuple[bool, str or dict]: """ @@ -135,7 +146,7 @@ def build(proxyInfo: dict, configDir: str, env = envVar, stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL, - preexec_fn = lambda: ctypes.CDLL(libcPath).prctl(1, 15) # 子进程跟随退出 + preexec_fn = lambda: __preExec(libcPath) ) except: process = subprocess.Popen( # prctl失败 回退正常启动 @@ -154,6 +165,7 @@ def build(proxyInfo: dict, configDir: str, 'process': process } + def check(client: dict) -> bool or None: """ 检查客户端是否正常运行 @@ -164,8 +176,6 @@ def check(client: dict) -> bool or None: """ return client['process'].poll() is None -def skipDestroy() -> None: - pass def destroy(client: dict) -> bool: """ @@ -175,21 +185,18 @@ def destroy(client: dict) -> bool: 销毁成功: return True """ - signal.signal(signal.SIGINT, skipDestroy) # 捕获SIGINT - signal.signal(signal.SIGTERM, skipDestroy) # 捕获SIGTERM try: + maxTermTime = 100 # SIGTERM -> SIGKILL process = client['process'] - os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 杀进程组 + os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 杀死子进程组 time.sleep(0.2) - maxWait = 100 - if process.poll() is None: # 未死亡 - while process.poll() is None: # 等待退出 - process.terminate() # SIGTERM - time.sleep(0.2) - maxWait -= 1 - if maxWait < 0: - process.kill() # SIGKILL - time.sleep(0.5) + while process.poll() is None: # 等待退出 + maxTermTime -= 1 + if maxTermTime < 0: + process.kill() # SIGKILL -> force kill + else: + process.terminate() # SIGTERM -> soft kill + time.sleep(0.2) except: return False diff --git a/ProxyTester/TrojanGo.py b/ProxyTester/TrojanGo.py index 0b417d0..ba754ec 100644 --- a/ProxyTester/TrojanGo.py +++ b/ProxyTester/TrojanGo.py @@ -152,13 +152,13 @@ def trojanGoTest(trojanGoConfig: dict) -> list: for key, value in trojanGoConfig.items(): # trojanGoConfig -> config config[key] = value - result += loadTrojanGoConfig([loadTrojanGo(False, None)]) + result += loadTrojanGoConfig([loadTrojanGo(False, None)]) # basic test result += loadTrojanGoConfig([loadTrojanGo(True, None)]) for ssMethod in trojanGoMethod: - result += loadTrojanGoConfig([loadTrojanGo(False, ssMethod)]) + result += loadTrojanGoConfig([loadTrojanGo(False, ssMethod)]) # basic test with shadowsocks 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)) return result diff --git a/Test.py b/Test.py index 78a310b..d755efd 100644 --- a/Test.py +++ b/Test.py @@ -4,6 +4,7 @@ import os import sys import time +import signal import subprocess import Check as Checker @@ -31,11 +32,13 @@ def testBuild(config: dict): # load file and start process config['startCommand'], env = config['envVar'], 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 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 process.terminate() # SIGTERM time.sleep(0.2) diff --git a/demo.py b/demo.py index 6a822ce..76c1a77 100644 --- a/demo.py +++ b/demo.py @@ -1,3 +1,5 @@ +import time + import ProxyBuilder as Builder import ProxyDecoder as Decoder import ProxyFilter as Filter @@ -10,8 +12,6 @@ info = { 'passwd': 'dnomd343', 'sni': 'local.343.re', 'plugin': { - # 'type': 'obfs-local', - # 'param': 'obfs=http;obfs-host=www.bing.com' 'type': 'simple-tls', 'param': 'n=local.343.re;no-verify' } @@ -27,3 +27,10 @@ data = Checker.proxyTest({ }) print(data) + +# status, client = Builder.build(ret, '/tmp/ProxyC') +# print(status) +# print(client) +# +# time.sleep(300) +# Builder.destroy(client)