diff --git a/Basis/Methods.py b/Basis/Methods.py index d488af8..8c3057f 100644 --- a/Basis/Methods.py +++ b/Basis/Methods.py @@ -127,3 +127,6 @@ udpObfuscations = ['none', 'srtp', 'utp', 'wechat-video', 'dtls', 'wireguard'] # Trojan-Go Info trojanGoMethods = ['aes-128-gcm', 'aes-256-gcm', 'chacha20-ietf-poly1305'] + +# Hysteria Info +hysteriaProtocols = ['udp', 'wechat-video', 'faketcp'] diff --git a/Builder/Hysteria.py b/Builder/Hysteria.py index a50ab2c..2840a0b 100644 --- a/Builder/Hysteria.py +++ b/Builder/Hysteria.py @@ -11,6 +11,8 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, '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']) } @@ -25,4 +27,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, }), **({} if proxyInfo['verify'] else { 'insecure': True })} - return ['hysteria', '-c', configFile, 'client'], json.dumps(hysteriaConfig), {} + return ['hysteria', '-c', configFile, 'client'], json.dumps(hysteriaConfig), {'LOGGING_LEVEL': 'trace'} diff --git a/Tester/Hysteria.py b/Tester/Hysteria.py new file mode 100644 index 0000000..914b6a1 --- /dev/null +++ b/Tester/Hysteria.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import json +import itertools +from Builder import Hysteria +from Basis.Logger import logging +from Basis.Process import Process +from Basis.Functions import genFlag +from Basis.Functions import hostFormat +from Basis.Methods import hysteriaProtocols +from Basis.Functions import getAvailablePort + +settings = { + 'serverBind': '127.0.0.1', + 'clientBind': '127.0.0.1', + # 'serverBind': '::1', + # 'clientBind': '::1', + 'workDir': '/tmp/ProxyC', + 'host': '343.re', + 'cert': '/etc/ssl/certs/343.re/fullchain.pem', + 'key': '/etc/ssl/certs/343.re/privkey.pem', +} + + +def loadServer(configFile: str, hysteriaConfig: dict) -> Process: + serverFile = os.path.join(settings['workDir'], configFile) + return Process(settings['workDir'], cmd = ['hysteria', '-c', serverFile, 'server'], file = { + 'path': serverFile, + 'content': json.dumps(hysteriaConfig) + }, isStart = False) + + +def loadClient(configFile: str, proxyInfo: dict, socksInfo: dict) -> Process: + clientFile = os.path.join(settings['workDir'], configFile) + hysteriaCommand, hysteriaConfig, _ = Hysteria.load(proxyInfo, socksInfo, clientFile) + return Process(settings['workDir'], cmd = hysteriaCommand, file = { + 'path': clientFile, + 'content': hysteriaConfig + }, isStart = False) + + +def loadTest(protocol: str, isObfs: bool, isAuth: bool) -> dict: + proxyInfo = { + 'type': 'hysteria', + 'server': settings['serverBind'], + 'port': getAvailablePort(), + 'protocol': protocol, + 'obfs': None, + 'passwd': None, + 'up': 10, + 'down': 50, + 'sni': settings['host'], + 'alpn': None, + 'verify': True, + } + socksInfo = { # socks5 interface for test + 'addr': settings['clientBind'], + 'port': getAvailablePort() + } + serverConfig = { + 'listen': '%s:%i' % (hostFormat(proxyInfo['server'], v6Bracket = True), proxyInfo['port']), + 'protocol': proxyInfo['protocol'], + 'cert': settings['cert'], + 'key': settings['key'], + } + configName = 'hysteria_' + protocol + caption = 'Hysteria protocol ' + protocol + if isObfs: + configName += '_obfs' + caption += ' (with obfs)' + proxyInfo['obfs'] = genFlag(length = 8) + serverConfig['obfs'] = proxyInfo['obfs'] + if isAuth: + configName += '_auth' + caption += ' (with auth)' + proxyInfo['passwd'] = genFlag(length = 8) + serverConfig['auth'] = { + 'mode': 'passwords', + 'config': [proxyInfo['passwd']] + } + testInfo = { + 'title': caption, + 'client': loadClient(configName + '_client.json', proxyInfo, socksInfo), + 'server': loadServer(configName + '_server.json', serverConfig), + 'socks': socksInfo, # exposed socks5 address + 'interface': { + 'addr': proxyInfo['server'], + 'port': proxyInfo['port'], + } + } + logging.debug('New hysteria test -> %s' % testInfo) + return testInfo + + +def load(): + for protocol, isObfs, isAuth in itertools.product(hysteriaProtocols, [False, True], [False, True]): + yield loadTest(protocol, isObfs, isAuth) diff --git a/test.py b/test.py index acc31d3..5942d7b 100755 --- a/test.py +++ b/test.py @@ -10,6 +10,7 @@ from Tester import VMess from Tester import VLESS from Tester import Trojan from Tester import TrojanGo +from Tester import Hysteria from Tester import Shadowsocks from Tester import ShadowsocksR @@ -28,16 +29,16 @@ def waitForStart(port: int, times: int = 100, delay: int = 100) -> bool: def test(testObj: dict) -> None: logging.warning(testObj['title']) - testObj['client'].start() testObj['server'].start() - if waitForStart(testObj['socks']['port']): - logging.debug('client start complete') + time.sleep(0.2) + testObj['client'].start() if waitForStart(testObj['interface']['port']): logging.debug('server start complete') + if waitForStart(testObj['socks']['port']): + logging.debug('client start complete') logging.debug('start test process') time.sleep(1) - errFlag = False socks5 = '%s:%i' % ( hostFormat(testObj['socks']['addr'], v6Bracket = True), @@ -103,6 +104,7 @@ vless = VLESS.load() trojan = Trojan.load() trojanGo = TrojanGo.load() brook = Brook.load() +hysteria = Hysteria.load() logging.critical('test start') # runTest(ss, 64) @@ -111,5 +113,6 @@ logging.critical('test start') # runTest(vless, 64) # runTest(trojan, 64) # runTest(trojanGo, 64) -runTest(brook, 64) +# runTest(brook, 64) +runTest(hysteria, 64) logging.critical('test complete')