mirror of https://github.com/dnomd343/ProxyC
dnomd343
3 years ago
5 changed files with 219 additions and 177 deletions
@ -0,0 +1,156 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
import os |
||||
|
import json |
||||
|
import base64 |
||||
|
from Builder import Shadowsocks |
||||
|
from Basis.Logger import logging |
||||
|
from Basis.Process import Process |
||||
|
from Basis.Methods import ssMethods, ssAllMethods |
||||
|
from Basis.Functions import genFlag, getAvailablePort |
||||
|
|
||||
|
settings = { |
||||
|
'serverBind': '127.0.0.1', |
||||
|
'clientBind': '127.0.0.1', # aka socks5 address |
||||
|
'workDir': '/tmp/ProxyC' |
||||
|
} |
||||
|
|
||||
|
|
||||
|
def loadConfig(proxyInfo: dict) -> dict: # load basic config option |
||||
|
config = { |
||||
|
'server': proxyInfo['server'], |
||||
|
'server_port': proxyInfo['port'], # type -> int |
||||
|
'method': proxyInfo['method'], |
||||
|
'password': proxyInfo['passwd'], |
||||
|
} |
||||
|
if proxyInfo['plugin'] is not None: # with plugin |
||||
|
config['plugin'] = proxyInfo['plugin']['type'] |
||||
|
config['plugin_opts'] = proxyInfo['plugin']['param'] |
||||
|
return config |
||||
|
|
||||
|
|
||||
|
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 |
||||
|
return False |
||||
|
return True # UDP is assumed by default |
||||
|
|
||||
|
|
||||
|
def ssRust(proxyInfo: dict, isUdp: bool) -> tuple[dict, list]: |
||||
|
config = loadConfig(proxyInfo) |
||||
|
if isUdp: # proxy UDP traffic |
||||
|
config['mode'] = 'tcp_and_udp' |
||||
|
return config, ['ss-rust-server', '-v'] |
||||
|
|
||||
|
|
||||
|
def ssLibev(proxyInfo: dict, isUdp: bool) -> tuple[dict, list]: |
||||
|
config = loadConfig(proxyInfo) |
||||
|
if isUdp: # proxy UDP traffic |
||||
|
config['mode'] = 'tcp_and_udp' |
||||
|
return config, ['ss-libev-server', '-v'] |
||||
|
|
||||
|
|
||||
|
def ssPython(proxyInfo: dict, isUdp: bool) -> tuple[dict, list]: |
||||
|
config = loadConfig(proxyInfo) |
||||
|
mbedtlsMethods = [ |
||||
|
'aes-128-cfb128', |
||||
|
'aes-192-cfb128', |
||||
|
'aes-256-cfb128', |
||||
|
'camellia-128-cfb128', |
||||
|
'camellia-192-cfb128', |
||||
|
'camellia-256-cfb128', |
||||
|
] |
||||
|
if config['method'] in mbedtlsMethods: # mbedtls methods should use prefix `mbedtls:` |
||||
|
config['method'] = 'mbedtls:' + config['method'] |
||||
|
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['shadowsocks'] = 'ss-python-server' |
||||
|
return config, ['ss-bootstrap-server', '--debug', '-vv'] |
||||
|
|
||||
|
|
||||
|
def ssPythonLegacy(proxyInfo: dict, isUdp: bool) -> tuple[dict, list]: |
||||
|
config = loadConfig(proxyInfo) |
||||
|
if not isUdp: |
||||
|
config['no_udp'] = True # UDP traffic is not proxied |
||||
|
config['shadowsocks'] = 'ss-python-legacy-server' |
||||
|
return config, ['ss-bootstrap-server', '--debug', '-vv'] |
||||
|
|
||||
|
|
||||
|
def loadPassword(method: str) -> str: |
||||
|
b64 = lambda x: base64.b64encode(x.encode(encoding = 'utf-8')).decode(encoding = 'utf-8') |
||||
|
if not method.startswith('2022-blake3-'): |
||||
|
return genFlag(length = 8) |
||||
|
if method == '2022-blake3-aes-128-gcm': |
||||
|
return b64(genFlag(length = 16)) |
||||
|
return b64(genFlag(length = 32)) # three other 2022-blake3-* methods use 32 byte length password |
||||
|
|
||||
|
|
||||
|
def testConnection(serverType: str, clientType: str, method: str) -> dict: |
||||
|
proxyInfo = { |
||||
|
'server': settings['serverBind'], |
||||
|
'port': getAvailablePort(), |
||||
|
'method': method, |
||||
|
'passwd': loadPassword(method), |
||||
|
'plugin': None |
||||
|
} |
||||
|
socksInfo = { |
||||
|
'addr': settings['clientBind'], |
||||
|
'port': getAvailablePort() |
||||
|
} |
||||
|
|
||||
|
ssClientLoad = { |
||||
|
'ss-rust': Shadowsocks.ssRust, |
||||
|
'ss-libev': Shadowsocks.ssLibev, |
||||
|
'ss-python': Shadowsocks.ssPython, |
||||
|
'ss-python-legacy': Shadowsocks.ssPythonLegacy |
||||
|
}[clientType] |
||||
|
ssConfig, ssClient = ssClientLoad(proxyInfo, socksInfo, isUdp = False) |
||||
|
clientFile = os.path.join(settings['workDir'], '%s_%s_%s' % (serverType, clientType, method) + '_client.json') |
||||
|
client = Process(settings['workDir'], cmd = ssClient + ['-c', clientFile], file = { |
||||
|
'path': clientFile, |
||||
|
'content': json.dumps(ssConfig) |
||||
|
}, isStart = False) |
||||
|
|
||||
|
ssServerLoad = { |
||||
|
'ss-rust': ssRust, |
||||
|
'ss-libev': ssLibev, |
||||
|
'ss-python': ssPython, |
||||
|
'ss-python-legacy': ssPythonLegacy |
||||
|
}[serverType] |
||||
|
ssConfig, ssServer = ssServerLoad(proxyInfo, isUdp = False) |
||||
|
serverFile = os.path.join(settings['workDir'], '%s_%s_%s' % (serverType, clientType, method) + '_server.json') |
||||
|
server = Process(settings['workDir'], cmd = ssServer + ['-c', serverFile], file = { |
||||
|
'path': serverFile, |
||||
|
'content': json.dumps(ssConfig) |
||||
|
}, isStart = False) |
||||
|
|
||||
|
testInfo = { |
||||
|
'title': 'Shadowsocks test: {%s <- %s -> %s}' % (serverType, method, clientType), |
||||
|
'socks': socksInfo, |
||||
|
'client': client, |
||||
|
'server': server, |
||||
|
} |
||||
|
logging.debug('New shadowsocks test connection -> %s' % testInfo) |
||||
|
return testInfo |
||||
|
|
||||
|
|
||||
|
def load(isExtra: bool = False) -> list: |
||||
|
result = [] |
||||
|
if isExtra: |
||||
|
for ssServer in ssMethods: |
||||
|
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 |
||||
|
result.append(testConnection(ssType, ssType, method)) |
||||
|
break |
||||
|
return result |
@ -1,160 +1,53 @@ |
|||||
#!/usr/bin/env python3 |
#!/usr/bin/env python3 |
||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
|
|
||||
import os |
|
||||
import json |
|
||||
import time |
import time |
||||
import requests |
import requests |
||||
from Builder import Shadowsocks |
from Tester import Shadowsocks |
||||
from Basis.Logger import logging |
from Basis.Logger import logging |
||||
from Basis.Process import Process |
|
||||
from Basis.Methods import ssMethods |
|
||||
from Basis.Functions import getAvailablePort |
|
||||
|
|
||||
ssPassword = '' |
|
||||
|
|
||||
def loadConfig(serverPort: int, method: str) -> dict: # load basic config option |
def test(testObj: dict) -> None: |
||||
config = { |
logging.warning(testObj['title']) |
||||
'server': '127.0.0.1', |
testObj['client'].start() |
||||
'server_port': serverPort, # type -> int |
testObj['server'].start() |
||||
'method': method, |
|
||||
'password': ssPassword, |
|
||||
} |
|
||||
return config |
|
||||
|
|
||||
|
time.sleep(1) |
||||
|
|
||||
def ssRust(serverPort: int, method: str) -> tuple[dict, list]: |
|
||||
config = loadConfig(serverPort, method) |
|
||||
return config, ['ss-rust-server', '-v'] |
|
||||
|
|
||||
|
|
||||
def ssLibev(serverPort: int, method: str) -> tuple[dict, list]: |
|
||||
config = loadConfig(serverPort, method) |
|
||||
return config, ['ss-libev-server', '-v'] |
|
||||
|
|
||||
|
|
||||
def ssPython(serverPort: int, method: str) -> tuple[dict, list]: |
|
||||
config = loadConfig(serverPort, method) |
|
||||
mbedtlsMethods = [ |
|
||||
'aes-128-cfb128', |
|
||||
'aes-192-cfb128', |
|
||||
'aes-256-cfb128', |
|
||||
'camellia-128-cfb128', |
|
||||
'camellia-192-cfb128', |
|
||||
'camellia-256-cfb128', |
|
||||
] |
|
||||
if config['method'] in mbedtlsMethods: # mbedtls methods should use prefix `mbedtls:` |
|
||||
config['method'] = 'mbedtls:' + config['method'] |
|
||||
if config['method'] in ['idea-cfb', 'seed-cfb']: # Only older versions of openssl are supported |
|
||||
config['extra_opts'] = '--libopenssl=libcrypto.so.1.0.0' |
|
||||
config['shadowsocks'] = 'ss-python-server' |
|
||||
return config, ['ss-bootstrap-server', '--debug', '-vv'] |
|
||||
|
|
||||
|
|
||||
def ssPythonLegacy(serverPort: int, method: str) -> tuple[dict, list]: |
|
||||
config = loadConfig(serverPort, method) |
|
||||
config['shadowsocks'] = 'ss-python-legacy-server' |
|
||||
return config, ['ss-bootstrap-server', '--debug', '-vv'] |
|
||||
|
|
||||
|
|
||||
def loadTest(serverType: str, clientType: str, method: str, timeout: float) -> None: |
|
||||
logging.warning('Shadowsocks test -> server = %s | client = %s | method = %s' % (serverType, clientType, method)) |
|
||||
global ssPassword |
|
||||
if method.startswith('2022-blake3-'): |
|
||||
ssPassword = 'ZG5vbWQzNDNkbm9tZDM0M2Rub21kMzQzZG5vbWQzNDM=' # base64 encode of 'dnomd343' * 4 |
|
||||
if method == '2022-blake3-aes-128-gcm': |
|
||||
ssPassword = 'ZG5vbWQzNDNkbm9tZDM0Mw==' # base64 encode of 'dnomd343' * 2 |
|
||||
else: |
|
||||
ssPassword = 'dnomd343' |
|
||||
title = '%s_%s_%s' % (serverType, clientType, method) |
|
||||
workDir = '/tmp/ProxyC' |
|
||||
serverPort = getAvailablePort() |
|
||||
socksPort = getAvailablePort() |
|
||||
proxyInfo = { |
|
||||
'server': '127.0.0.1', |
|
||||
'port': serverPort, |
|
||||
'method': method, |
|
||||
'passwd': ssPassword, |
|
||||
'plugin': None |
|
||||
} |
|
||||
socksInfo = { |
|
||||
'addr': '127.0.0.1', |
|
||||
'port': socksPort |
|
||||
} |
|
||||
ssClientLoad = { |
|
||||
'ss-rust': Shadowsocks.ssRust, |
|
||||
'ss-libev': Shadowsocks.ssLibev, |
|
||||
'ss-python': Shadowsocks.ssPython, |
|
||||
'ss-python-legacy': Shadowsocks.ssPythonLegacy |
|
||||
}[clientType] |
|
||||
ssConfig, ssClient = ssClientLoad(proxyInfo, socksInfo, isUdp = False) |
|
||||
client = Process(workDir, cmd = ssClient + ['-c', os.path.join(workDir, title + '_client.json')], file = { |
|
||||
'path': os.path.join(workDir, title + '_client.json'), |
|
||||
'content': json.dumps(ssConfig) |
|
||||
}, isStart = False) |
|
||||
|
|
||||
ssServerLoad = { |
|
||||
'ss-rust': ssRust, |
|
||||
'ss-libev': ssLibev, |
|
||||
'ss-python': ssPython, |
|
||||
'ss-python-legacy': ssPythonLegacy |
|
||||
}[serverType] |
|
||||
ssConfig, ssServer = ssServerLoad(serverPort, method) |
|
||||
server = Process(workDir, cmd = ssServer + ['-c', os.path.join(workDir, title + '_server.json')], file = { |
|
||||
'path': os.path.join(workDir, title + '_server.json'), |
|
||||
'content': json.dumps(ssConfig) |
|
||||
}, isStart = False) |
|
||||
|
|
||||
client.start() |
|
||||
server.start() |
|
||||
time.sleep(timeout) |
|
||||
errFlag = False |
errFlag = False |
||||
try: |
try: |
||||
request = requests.get( |
request = requests.get( |
||||
'http://baidu.com', |
'http://baidu.com', |
||||
proxies = { |
proxies = { |
||||
'http': 'socks5://127.0.0.1:%i' % socksPort, |
'http': 'socks5://127.0.0.1:%i' % testObj['socks']['port'], |
||||
'https': 'socks5://127.0.0.1:%i' % socksPort |
'https': 'socks5://127.0.0.1:%i' % testObj['socks']['port'], |
||||
}, |
}, |
||||
timeout = 10 |
timeout = 10 |
||||
) |
) |
||||
request.raise_for_status() |
request.raise_for_status() |
||||
logging.info('socks5 127.0.0.1:%i -> ok' % socksPort) |
logging.info('socks5 127.0.0.1:%i -> ok' % testObj['socks']['port']) |
||||
except Exception as exp: |
except Exception as exp: |
||||
logging.error('socks5 127.0.0.1:%i -> error' % socksPort) |
logging.error('socks5 127.0.0.1:%i -> error' % testObj['socks']['port']) |
||||
logging.error('requests exception\n' + str(exp)) |
logging.error('requests exception\n' + str(exp)) |
||||
errFlag = True |
errFlag = True |
||||
client.quit() |
|
||||
server.quit() |
|
||||
if errFlag: |
|
||||
logging.error('client capture output\n' + str(client.output)) |
|
||||
logging.error('server capture output\n' + str(server.output)) |
|
||||
|
|
||||
|
|
||||
def test_1() -> None: |
|
||||
for ssType in ssMethods: |
|
||||
for method in ssMethods[ssType]: |
|
||||
timeout = 0.1 |
|
||||
if 'python' in ssType: timeout = 0.3 |
|
||||
if 'python-legacy' in ssType: |
|
||||
timeout = 0.8 |
|
||||
if method == 'table' or method == 'salsa20-ctr': timeout = 2 |
|
||||
loadTest(ssType, ssType, method, timeout) |
|
||||
|
|
||||
|
testObj['client'].quit() |
||||
def test_2() -> None: |
testObj['server'].quit() |
||||
for ssServer in ssMethods: |
if errFlag: |
||||
for method in ssMethods[ssServer]: |
logging.warning('client info') |
||||
for ssClient in ssMethods: |
logging.error('command -> ' + str(testObj['client'].cmd)) |
||||
if method not in ssMethods[ssClient]: continue |
logging.error('envVar -> ' + str(testObj['client'].env)) |
||||
timeout = 0.1 |
logging.error('file -> ' + str(testObj['client'].file)) |
||||
if 'python' in ssServer or 'python' in ssClient: timeout = 0.3 |
logging.warning('client capture output') |
||||
if method == 'table': timeout = 0.8 |
logging.error('\n' + str(testObj['client'].output)) |
||||
if 'python-legacy' in ssServer or 'python-legacy' in ssClient: timeout = 1 |
logging.warning('server info') |
||||
if method == 'salsa20-ctr': timeout = 3 |
logging.error('command -> ' + str(testObj['server'].cmd)) |
||||
loadTest(ssServer, ssClient, method, timeout) |
logging.error('envVar -> ' + str(testObj['server'].env)) |
||||
|
logging.error('file -> ' + str(testObj['server'].file)) |
||||
|
logging.warning('server capture output') |
||||
# test_1() |
logging.error('\n' + str(testObj['server'].output)) |
||||
test_2() |
|
||||
# loadTest('ss-python-legacy', 'ss-python-legacy', 'salsa20-ctr', 3) |
|
||||
|
testList = Shadowsocks.load(isExtra = True) |
||||
|
for testObject in testList: |
||||
|
test(testObject) |
||||
|
Loading…
Reference in new issue