mirror of https://github.com/dnomd343/ProxyC
dnomd343
2 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 |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import os |
|||
import json |
|||
import time |
|||
import requests |
|||
from Builder import Shadowsocks |
|||
from Tester import Shadowsocks |
|||
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 |
|||
config = { |
|||
'server': '127.0.0.1', |
|||
'server_port': serverPort, # type -> int |
|||
'method': method, |
|||
'password': ssPassword, |
|||
} |
|||
return config |
|||
def test(testObj: dict) -> None: |
|||
logging.warning(testObj['title']) |
|||
testObj['client'].start() |
|||
testObj['server'].start() |
|||
|
|||
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 |
|||
try: |
|||
request = requests.get( |
|||
'http://baidu.com', |
|||
proxies = { |
|||
'http': 'socks5://127.0.0.1:%i' % socksPort, |
|||
'https': 'socks5://127.0.0.1:%i' % socksPort |
|||
'http': 'socks5://127.0.0.1:%i' % testObj['socks']['port'], |
|||
'https': 'socks5://127.0.0.1:%i' % testObj['socks']['port'], |
|||
}, |
|||
timeout = 10 |
|||
) |
|||
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: |
|||
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)) |
|||
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) |
|||
|
|||
|
|||
def test_2() -> None: |
|||
for ssServer in ssMethods: |
|||
for method in ssMethods[ssServer]: |
|||
for ssClient in ssMethods: |
|||
if method not in ssMethods[ssClient]: continue |
|||
timeout = 0.1 |
|||
if 'python' in ssServer or 'python' in ssClient: timeout = 0.3 |
|||
if method == 'table': timeout = 0.8 |
|||
if 'python-legacy' in ssServer or 'python-legacy' in ssClient: timeout = 1 |
|||
if method == 'salsa20-ctr': timeout = 3 |
|||
loadTest(ssServer, ssClient, method, timeout) |
|||
|
|||
|
|||
# test_1() |
|||
test_2() |
|||
# loadTest('ss-python-legacy', 'ss-python-legacy', 'salsa20-ctr', 3) |
|||
testObj['client'].quit() |
|||
testObj['server'].quit() |
|||
if errFlag: |
|||
logging.warning('client info') |
|||
logging.error('command -> ' + str(testObj['client'].cmd)) |
|||
logging.error('envVar -> ' + str(testObj['client'].env)) |
|||
logging.error('file -> ' + str(testObj['client'].file)) |
|||
logging.warning('client capture output') |
|||
logging.error('\n' + str(testObj['client'].output)) |
|||
logging.warning('server info') |
|||
logging.error('command -> ' + str(testObj['server'].cmd)) |
|||
logging.error('envVar -> ' + str(testObj['server'].env)) |
|||
logging.error('file -> ' + str(testObj['server'].file)) |
|||
logging.warning('server capture output') |
|||
logging.error('\n' + str(testObj['server'].output)) |
|||
|
|||
|
|||
testList = Shadowsocks.load(isExtra = True) |
|||
for testObject in testList: |
|||
test(testObject) |
|||
|
Loading…
Reference in new issue