From a966c8cf5d42b8664fb2beeb5b1c7cd0b676033d Mon Sep 17 00:00:00 2001 From: dnomd343 Date: Mon, 8 Aug 2022 14:48:45 +0800 Subject: [PATCH] feat: add build exception --- Basis/Constant.py | 6 ++++++ Basis/Exception.py | 6 ++++++ Basis/Functions.py | 4 ++++ Builder/Brook.py | 26 ++++++++++++-------------- Builder/Hysteria.py | 6 +++--- Builder/Shadowsocks.py | 25 +++++++++++++------------ Builder/ShadowsocksR.py | 7 ++++--- Builder/Trojan.py | 2 +- Builder/V2ray.py | 7 ++++--- Builder/VLESS.py | 5 ++++- Builder/VMess.py | 3 ++- Builder/Xray.py | 7 ++++--- Builder/__init__.py | 12 +++++++----- 13 files changed, 70 insertions(+), 46 deletions(-) create mode 100644 Basis/Exception.py diff --git a/Basis/Constant.py b/Basis/Constant.py index 9ffbc7f..c17a187 100644 --- a/Basis/Constant.py +++ b/Basis/Constant.py @@ -40,6 +40,12 @@ if 'api' in envOptions: if 'token' in envOptions['api']: ApiToken = envOptions['api']['token'] +# WorkDir Create +try: + os.makedirs(WorkDir) # just like `mkdir -p ...` +except: + pass # folder exist or target is another thing + # Shadowsocks Info mbedtlsMethods = [ 'aes-128-cfb128', diff --git a/Basis/Exception.py b/Basis/Exception.py new file mode 100644 index 0000000..685b394 --- /dev/null +++ b/Basis/Exception.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class buildException(Exception): # for build error + def __init__(self, reason): + self.reason = reason diff --git a/Basis/Functions.py b/Basis/Functions.py index daefe4f..7297183 100644 --- a/Basis/Functions.py +++ b/Basis/Functions.py @@ -55,6 +55,10 @@ def hostFormat(host: str, v6Bracket: bool = False) -> str: return host +def v6AddBracket(host: str) -> str: # add bracket for ipv6 + return hostFormat(host, v6Bracket = True) + + def genFlag(length: int = 12) -> str: # generate random task flag flag = '' for i in range(0, length): diff --git a/Builder/Brook.py b/Builder/Brook.py index ab2940b..99a4776 100644 --- a/Builder/Brook.py +++ b/Builder/Brook.py @@ -1,30 +1,29 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from Basis.Functions import hostFormat - +from Basis.Functions import v6AddBracket def loadOrigin(proxyInfo: dict) -> list: # origin stream return ['client'] + [ - '--server', '%s:%i' % (hostFormat(proxyInfo['server'], v6Bracket = True), proxyInfo['port']), + '--server', '%s:%i' % (v6AddBracket(proxyInfo['server']), proxyInfo['port']), '--password', proxyInfo['passwd'], - ] + (['--udpovertcp'] if proxyInfo['stream']['uot'] else []) + ] + (['--udpovertcp'] if proxyInfo['stream']['uot'] else []) # add uot option -def loadWebsocket(proxyInfo: dict) -> list: - isTls = proxyInfo['stream']['secure'] is not None - wsAddress = (('wss' if isTls else 'ws') + '://%s:%i%s') % ( - hostFormat(proxyInfo['stream']['host'], v6Bracket = True), proxyInfo['port'], proxyInfo['stream']['path'] +def loadWebsocket(proxyInfo: dict) -> list: # websocket stream + isTls = proxyInfo['stream']['secure'] is not None # ws or wss + wsAddress = (('wss' if isTls else 'ws') + '://%s:%i%s') % ( # websocket address + v6AddBracket(proxyInfo['stream']['host']), proxyInfo['port'], proxyInfo['stream']['path'] ) brookCommand = [ 'wssclient' if isTls else 'wsclient', - '--address', '%s:%i' % (hostFormat(proxyInfo['server'], v6Bracket = True), proxyInfo['port']), + '--address', '%s:%i' % (v6AddBracket(proxyInfo['server']), proxyInfo['port']), # real address '--password', proxyInfo['passwd'], - ] + (['--withoutBrookProtocol'] if proxyInfo['stream']['raw'] else []) + ] + (['--withoutBrookProtocol'] if proxyInfo['stream']['raw'] else []) # raw transmission on ws or wss if not isTls: return brookCommand + ['--wsserver', wsAddress] return brookCommand + ['--wssserver', wsAddress] + ( - [] if proxyInfo['stream']['secure']['verify'] else ['--insecure'] + [] if proxyInfo['stream']['secure']['verify'] else ['--insecure'] # add tls options ) @@ -32,7 +31,6 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, brookCommand = ['brook', '--debug', '--listen', ':'] + { # debug module listen on random port 'origin': loadOrigin, 'ws': loadWebsocket, - }[proxyInfo['stream']['type']](proxyInfo) + [ - '--socks5', '%s:%i' % (hostFormat(socksInfo['addr'], v6Bracket = True), socksInfo['port']) - ] + }[proxyInfo['stream']['type']](proxyInfo) # choose origin or websocket stream + brookCommand += ['--socks5', '%s:%i' % (v6AddBracket(socksInfo['addr']), socksInfo['port'])] return brookCommand, 'Config file %s no need' % configFile, {} # command, fileContent, envVar diff --git a/Builder/Hysteria.py b/Builder/Hysteria.py index 4f4be18..2afdc4e 100644 --- a/Builder/Hysteria.py +++ b/Builder/Hysteria.py @@ -2,19 +2,19 @@ # -*- coding: utf-8 -*- import json -from Basis.Functions import hostFormat +from Basis.Functions import v6AddBracket def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]: hysteriaConfig = { - 'server': '%s:%i' % (hostFormat(proxyInfo['server'], v6Bracket = True), proxyInfo['port']), + 'server': '%s:%i' % (v6AddBracket(proxyInfo['server']), proxyInfo['port']), 'protocol': proxyInfo['protocol'], 'up_mbps': proxyInfo['up'], 'down_mbps': proxyInfo['down'], 'retry_interval': 2, 'retry': 3, 'socks5': { - 'listen': '%s:%i' % (hostFormat(socksInfo['addr'], v6Bracket = True), socksInfo['port']) + 'listen': '%s:%i' % (v6AddBracket(socksInfo['addr']), socksInfo['port']) }, **({} if proxyInfo['obfs'] is None else { 'obfs': proxyInfo['obfs'] diff --git a/Builder/Shadowsocks.py b/Builder/Shadowsocks.py index 5a5b627..da6fe63 100644 --- a/Builder/Shadowsocks.py +++ b/Builder/Shadowsocks.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import json +from Basis.Exception import buildException from Basis.Constant import ssMethods, ssAllMethods, mbedtlsMethods @@ -20,25 +21,25 @@ def loadConfig(proxyInfo: dict, socksInfo: dict) -> dict: # load basic config o return config -def pluginUdp(plugin: str, pluginParam: str) -> bool: # whether the plugin uses UDP +def pluginUdp(plugin: str, pluginParam: str) -> bool: # whether the plugin uses udp if plugin in ['obfs-local', 'simple-tls', 'ck-client', 'gq-client', 'mtt-client', 'rabbit-plugin']: return False # UDP is not used if plugin in ['v2ray-plugin', 'xray-plugin', 'gost-plugin']: - if 'mode=quic' not in pluginParam.split(';'): # non-quic mode does not use UDP + if 'mode=quic' not in pluginParam.split(';'): # non-quic mode does not use udp return False - return True # UDP is assumed by default + return True # udp is assumed by default def ssRust(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict, list, dict]: config = loadConfig(proxyInfo, socksInfo) - if isUdp: # proxy UDP traffic + if isUdp: # proxy udp traffic config['mode'] = 'tcp_and_udp' - return config, ['ss-rust-local', '-v'], {'RUST_BACKTRACE': 'full'} + return config, ['ss-rust-local', '-v'], {'RUST_BACKTRACE': 'full'} # enable rust trace def ssLibev(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict, list, dict]: config = loadConfig(proxyInfo, socksInfo) - if isUdp: # proxy UDP traffic + if isUdp: # proxy udp traffic config['mode'] = 'tcp_and_udp' return config, ['ss-libev-local', '-v'], {} @@ -50,7 +51,7 @@ def ssPython(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict, list, if config['method'] in ['idea-cfb', 'seed-cfb']: # only older versions of openssl are supported config['extra_opts'] = '--libopenssl=libcrypto.so.1.0.0' if not isUdp: - config['no_udp'] = True # UDP traffic is not proxied + config['no_udp'] = True # udp traffic is not proxied config['shadowsocks'] = 'ss-python-local' return config, ['ss-bootstrap-local', '--debug', '-vv'], {} @@ -58,21 +59,21 @@ def ssPython(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict, list, def ssPythonLegacy(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict, list, dict]: config = loadConfig(proxyInfo, socksInfo) if not isUdp: - config['no_udp'] = True # UDP traffic is not proxied + config['no_udp'] = True # udp traffic is not proxied config['shadowsocks'] = 'ss-python-legacy-local' return config, ['ss-bootstrap-local', '--debug', '-vv'], {} def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]: - isUdp = True if proxyInfo['plugin'] is None else ( # UDP enabled when server without plugin - not pluginUdp(proxyInfo['plugin']['type'], proxyInfo['plugin']['param']) # UDP conflict status of plugins + isUdp = True if proxyInfo['plugin'] is None else ( # udp enabled when server without plugin + not pluginUdp(proxyInfo['plugin']['type'], proxyInfo['plugin']['param']) # udp conflict status of plugins ) if proxyInfo['method'] not in ssAllMethods: # unknown shadowsocks method - raise RuntimeError('Unknown shadowsocks method') + raise buildException('Unknown shadowsocks method') for client in ssMethods: # traverse all shadowsocks client if proxyInfo['method'] not in ssMethods[client]: continue - ssConfig, ssClient, ssEnv = { + ssConfig, ssClient, ssEnv = { # found appropriate client 'ss-rust': ssRust, 'ss-libev': ssLibev, 'ss-python': ssPython, diff --git a/Builder/ShadowsocksR.py b/Builder/ShadowsocksR.py index 8155da6..70549ca 100644 --- a/Builder/ShadowsocksR.py +++ b/Builder/ShadowsocksR.py @@ -2,16 +2,17 @@ # -*- coding: utf-8 -*- import json +from Basis.Exception import buildException from Basis.Constant import ssrMethods, ssrProtocols, ssrObfuscations def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]: if proxyInfo['method'] not in ssrMethods: - raise RuntimeError('Unknown shadowsocksr method') + raise buildException('Unknown shadowsocksr method') if proxyInfo['protocol'] not in ssrProtocols: - raise RuntimeError('Unknown shadowsocksr protocol') + raise buildException('Unknown shadowsocksr protocol') if proxyInfo['obfs'] not in ssrObfuscations: - raise RuntimeError('Unknown shadowsocksr obfuscation') + raise buildException('Unknown shadowsocksr obfuscation') ssrConfig = { 'server': proxyInfo['server'], 'server_port': proxyInfo['port'], # type -> int diff --git a/Builder/Trojan.py b/Builder/Trojan.py index b6aaa5e..29b3680 100644 --- a/Builder/Trojan.py +++ b/Builder/Trojan.py @@ -13,7 +13,7 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, 'address': proxyInfo['server'], 'port': proxyInfo['port'], 'password': proxyInfo['passwd'], - **Xray.xtlsFlow(proxyInfo['stream']) + **Xray.xtlsFlow(proxyInfo['stream']) # add xtls flow option }] }, 'streamSettings': Xray.loadStream(proxyInfo['stream']) diff --git a/Builder/V2ray.py b/Builder/V2ray.py index 47bc8fb..a66709d 100644 --- a/Builder/V2ray.py +++ b/Builder/V2ray.py @@ -2,8 +2,9 @@ # -*- coding: utf-8 -*- import copy +from Basis.Exception import buildException -httpConfig = { +httpConfig = { # http obfs configure in default 'type': 'http', 'request': { 'version': '1.1', @@ -24,7 +25,7 @@ httpConfig = { } } -kcpConfig = { +kcpConfig = { # kcp options in default 'mtu': 1350, 'tti': 50, 'uplinkCapacity': 12, @@ -139,7 +140,7 @@ def loadStream(streamInfo: dict) -> dict: 'grpc': grpcStream, } if streamInfo['type'] not in streamEntry: - raise RuntimeError('Unknown stream type') + raise buildException('Unknown v2ray stream type') streamObject = streamEntry[streamInfo['type']](streamInfo) return { **streamObject, diff --git a/Builder/VLESS.py b/Builder/VLESS.py index 3180801..a9b6d8f 100644 --- a/Builder/VLESS.py +++ b/Builder/VLESS.py @@ -3,9 +3,12 @@ import json from Builder import Xray +from Basis.Exception import buildException def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]: + if proxyInfo['method'] != 'none': + raise buildException('Unknown VLESS method') outboundConfig = { 'protocol': 'vless', 'settings': { @@ -15,7 +18,7 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, 'users': [{ 'id': proxyInfo['id'], 'encryption': proxyInfo['method'], - **Xray.xtlsFlow(proxyInfo['stream']) + **Xray.xtlsFlow(proxyInfo['stream']) # add xtls flow option }] }] }, diff --git a/Builder/VMess.py b/Builder/VMess.py index 76076ad..eebf5db 100644 --- a/Builder/VMess.py +++ b/Builder/VMess.py @@ -4,11 +4,12 @@ import json from Builder import V2ray from Basis.Constant import vmessMethods +from Basis.Exception import buildException def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]: if proxyInfo['method'] not in vmessMethods: - raise RuntimeError('Unknown vmess method') + raise buildException('Unknown VMess method') outboundConfig = { 'protocol': 'vmess', 'settings': { diff --git a/Builder/Xray.py b/Builder/Xray.py index bde216c..5726ae0 100644 --- a/Builder/Xray.py +++ b/Builder/Xray.py @@ -3,6 +3,7 @@ from Builder import V2ray from Basis.Constant import xtlsFlows +from Basis.Exception import buildException loadConfig = V2ray.loadConfig @@ -11,7 +12,7 @@ def loadSecure(secureInfo: dict or None) -> dict: # TLS / XTLS encrypt config if secureInfo is None: return {'security': 'none'} # without TLS / XTLS options if secureInfo['type'] not in ['tls', 'xtls']: - raise RuntimeError('Unknown secure type') + raise buildException('Unknown xray secure type') secureObject = { 'allowInsecure': not secureInfo['verify'] # whether verify server's certificate } @@ -53,7 +54,7 @@ def loadStream(streamInfo: dict) -> dict: 'grpc': V2ray.grpcStream, } if streamInfo['type'] not in streamEntry: - raise RuntimeError('Unknown stream type') + raise buildException('Unknown xray stream type') streamObject = streamEntry[streamInfo['type']](streamInfo) return { **streamObject, @@ -67,7 +68,7 @@ def xtlsFlow(streamInfo: dict or None) -> dict: if streamInfo['secure']['type'] != 'xtls': # not XTLS secure type return {} if streamInfo['secure']['flow'] not in xtlsFlows: - raise RuntimeError('Unknown xtls flow') + raise buildException('Unknown xtls flow') return { 'flow': xtlsFlows[streamInfo['secure']['flow']] + ( # xtls-rprx-xxx '-udp443' if streamInfo['secure']['udp443'] else '' # whether block udp/443 (disable http/3) diff --git a/Builder/__init__.py b/Builder/__init__.py index dd1a60e..5bbe0dc 100644 --- a/Builder/__init__.py +++ b/Builder/__init__.py @@ -5,8 +5,10 @@ import os import copy from Basis.Logger import logging from Basis.Process import Process +from Basis.Functions import v6AddBracket +from Basis.Exception import buildException from Basis.Constant import WorkDir, PathEnv -from Basis.Functions import hostFormat, genFlag, getAvailablePort +from Basis.Functions import genFlag, getAvailablePort from Builder import Brook from Builder import VMess @@ -44,19 +46,19 @@ class Builder(object): Attributes: id, proxyType, proxyInfo, socksAddr, socksPort, output """ - output = None + output = None # output capture of proxy client (after process exit) def __loadClient(self): logging.info('[%s] Builder load %s client at %s -> %s' % ( self.id, self.proxyType, - 'socks5://%s:%i' % (hostFormat(self.socksAddr, v6Bracket = True), self.socksPort), self.proxyInfo + 'socks5://%s:%i' % (v6AddBracket(self.socksAddr), self.socksPort), self.proxyInfo )) configFile = os.path.join( # config file path WorkDir, self.id + clientEntry[self.proxyType][1] # workDir + taskId + file suffix ) logging.debug('[%s] Builder config file -> %s' % (self.id, configFile)) command, fileContent, envVar = clientEntry[self.proxyType][0](self.proxyInfo, { # load client boot info - 'addr': self.socksAddr, + 'addr': self.socksAddr, # specify socks5 info 'port': self.socksPort, }, configFile) envVar['PATH'] = PathEnv # add PATH env (some programs need it) @@ -69,7 +71,7 @@ class Builder(object): self.id = genFlag(length = 12) if taskId == '' else taskId # load task ID if proxyType not in clientEntry: logging.error('[%s] Builder receive unknown proxy type %s' % (self.id, proxyType)) - raise RuntimeError('Unknown proxy type') + raise buildException('Unknown proxy type') self.proxyType = proxyType # proxy type -> ss / ssr / vmess ... self.proxyInfo = copy.copy(proxyInfo) # connection info self.socksAddr = bindAddr