|
@ -4,6 +4,7 @@ |
|
|
import os |
|
|
import os |
|
|
import json |
|
|
import json |
|
|
import base64 |
|
|
import base64 |
|
|
|
|
|
import itertools |
|
|
from Builder import Shadowsocks |
|
|
from Builder import Shadowsocks |
|
|
from Basis.Logger import logging |
|
|
from Basis.Logger import logging |
|
|
from Basis.Process import Process |
|
|
from Basis.Process import Process |
|
@ -82,75 +83,74 @@ def ssPythonLegacy(proxyInfo: dict, isUdp: bool) -> tuple[dict, list]: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def loadPassword(method: str) -> str: |
|
|
def loadPassword(method: str) -> str: |
|
|
b64 = lambda x: base64.b64encode(x.encode(encoding = 'utf-8')).decode(encoding = 'utf-8') |
|
|
b64 = lambda x: base64.b64encode(x.encode(encoding = 'utf-8')).decode(encoding = 'utf-8') # base64 encode |
|
|
if not method.startswith('2022-blake3-'): |
|
|
if not method.startswith('2022-blake3-'): # normal method |
|
|
return genFlag(length = 8) |
|
|
return genFlag(length = 8) |
|
|
if method == '2022-blake3-aes-128-gcm': |
|
|
if method == '2022-blake3-aes-128-gcm': # 2022-blake3-aes-128-gcm use 16 byte length password |
|
|
return b64(genFlag(length = 16)) |
|
|
return b64(genFlag(length = 16)) |
|
|
return b64(genFlag(length = 32)) # three other 2022-blake3-* methods use 32 byte length password |
|
|
return b64(genFlag(length = 32)) # three other 2022-blake3-* methods use 32 byte length password |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def testConnection(serverType: str, clientType: str, method: str) -> dict: |
|
|
def loadClient(ssType: str, configFile: str, proxyInfo: dict, socksInfo: dict) -> Process: |
|
|
proxyInfo = { |
|
|
ssConfig, ssClient = { # generate client start command and its config file |
|
|
'server': settings['serverBind'], |
|
|
|
|
|
'port': getAvailablePort(), |
|
|
|
|
|
'method': method, |
|
|
|
|
|
'passwd': loadPassword(method), |
|
|
|
|
|
'plugin': None |
|
|
|
|
|
} |
|
|
|
|
|
socksInfo = { |
|
|
|
|
|
'addr': settings['clientBind'], |
|
|
|
|
|
'port': getAvailablePort() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ssClientLoad = { |
|
|
|
|
|
'ss-rust': Shadowsocks.ssRust, |
|
|
'ss-rust': Shadowsocks.ssRust, |
|
|
'ss-libev': Shadowsocks.ssLibev, |
|
|
'ss-libev': Shadowsocks.ssLibev, |
|
|
'ss-python': Shadowsocks.ssPython, |
|
|
'ss-python': Shadowsocks.ssPython, |
|
|
'ss-python-legacy': Shadowsocks.ssPythonLegacy |
|
|
'ss-python-legacy': Shadowsocks.ssPythonLegacy |
|
|
}[clientType] |
|
|
}[ssType](proxyInfo, socksInfo, isUdp = False) |
|
|
ssConfig, ssClient = ssClientLoad(proxyInfo, socksInfo, isUdp = False) |
|
|
clientFile = os.path.join(settings['workDir'], configFile) |
|
|
clientFile = os.path.join(settings['workDir'], '%s_%s_%s' % (serverType, clientType, method) + '_client.json') |
|
|
return Process(settings['workDir'], cmd = ssClient + ['-c', clientFile], file = { # load client process |
|
|
client = Process(settings['workDir'], cmd = ssClient + ['-c', clientFile], file = { |
|
|
|
|
|
'path': clientFile, |
|
|
'path': clientFile, |
|
|
'content': json.dumps(ssConfig) |
|
|
'content': json.dumps(ssConfig) |
|
|
}, isStart = False) |
|
|
}, isStart = False) |
|
|
|
|
|
|
|
|
ssServerLoad = { |
|
|
|
|
|
|
|
|
def loadServer(ssType: str, configFile: str, proxyInfo: dict) -> Process: |
|
|
|
|
|
ssConfig, ssServer = { # generate server start command and its config file |
|
|
'ss-rust': ssRust, |
|
|
'ss-rust': ssRust, |
|
|
'ss-libev': ssLibev, |
|
|
'ss-libev': ssLibev, |
|
|
'ss-python': ssPython, |
|
|
'ss-python': ssPython, |
|
|
'ss-python-legacy': ssPythonLegacy |
|
|
'ss-python-legacy': ssPythonLegacy |
|
|
}[serverType] |
|
|
}[ssType](proxyInfo, isUdp = False) |
|
|
ssConfig, ssServer = ssServerLoad(proxyInfo, isUdp = False) |
|
|
serverFile = os.path.join(settings['workDir'], configFile) |
|
|
serverFile = os.path.join(settings['workDir'], '%s_%s_%s' % (serverType, clientType, method) + '_server.json') |
|
|
return Process(settings['workDir'], cmd = ssServer + ['-c', serverFile], file = { # load server process |
|
|
server = Process(settings['workDir'], cmd = ssServer + ['-c', serverFile], file = { |
|
|
|
|
|
'path': serverFile, |
|
|
'path': serverFile, |
|
|
'content': json.dumps(ssConfig) |
|
|
'content': json.dumps(ssConfig) |
|
|
}, isStart = False) |
|
|
}, isStart = False) |
|
|
|
|
|
|
|
|
testInfo = { |
|
|
|
|
|
|
|
|
def loadTest(serverType: str, clientType: str, method: str) -> dict: |
|
|
|
|
|
proxyInfo = { # connection info |
|
|
|
|
|
'server': settings['serverBind'], |
|
|
|
|
|
'port': getAvailablePort(), |
|
|
|
|
|
'method': method, |
|
|
|
|
|
'passwd': loadPassword(method), |
|
|
|
|
|
'plugin': None |
|
|
|
|
|
} |
|
|
|
|
|
socksInfo = { # socks5 interface for test |
|
|
|
|
|
'addr': settings['clientBind'], |
|
|
|
|
|
'port': getAvailablePort() |
|
|
|
|
|
} |
|
|
|
|
|
configName = '%s_%s_%s' % (serverType, clientType, method) # prefix of config file name |
|
|
|
|
|
testInfo = { # release test info |
|
|
'title': 'Shadowsocks test: {%s <- %s -> %s}' % (serverType, method, clientType), |
|
|
'title': 'Shadowsocks test: {%s <- %s -> %s}' % (serverType, method, clientType), |
|
|
'socks': socksInfo, |
|
|
'client': loadClient(clientType, configName + '_client.json', proxyInfo, socksInfo), |
|
|
'client': client, |
|
|
'server': loadServer(serverType, configName + '_server.json', proxyInfo), |
|
|
'server': server, |
|
|
'socks': socksInfo, # exposed socks5 interface |
|
|
} |
|
|
} |
|
|
logging.debug('New shadowsocks test connection -> %s' % testInfo) |
|
|
logging.debug('New shadowsocks test connection -> %s' % testInfo) |
|
|
return testInfo |
|
|
return testInfo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load(isExtra: bool = False) -> list: |
|
|
def load(isExtra: bool = False): |
|
|
result = [] |
|
|
if not isExtra: # just test basic connection |
|
|
if isExtra: |
|
|
for method in ssAllMethods: # test every method for once |
|
|
for ssServer in ssMethods: |
|
|
for ssType in ssMethods: # found the client which support this method |
|
|
for method in ssMethods[ssServer]: |
|
|
|
|
|
for ssClient in ssMethods: |
|
|
|
|
|
if method not in ssMethods[ssClient]: continue |
|
|
|
|
|
result.append(testConnection(ssServer, ssClient, method)) |
|
|
|
|
|
else: |
|
|
|
|
|
for method in ssAllMethods: |
|
|
|
|
|
for ssType in ssMethods: |
|
|
|
|
|
if method not in ssMethods[ssType]: continue |
|
|
if method not in ssMethods[ssType]: continue |
|
|
result.append(testConnection(ssType, ssType, method)) |
|
|
yield loadTest(ssType, ssType, method) # ssType <-- method --> ssType |
|
|
break |
|
|
break # don't need other client |
|
|
return result |
|
|
return |
|
|
|
|
|
for ssServer in ssMethods: # traverse all shadowsocks type as server |
|
|
|
|
|
for method, ssClient in itertools.product(ssMethods[ssServer], ssMethods): # supported methods and clients |
|
|
|
|
|
if method not in ssMethods[ssClient]: continue |
|
|
|
|
|
yield loadTest(ssServer, ssClient, method) # ssServer <-- method --> ssClient |
|
|