#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import json from Tester import Xray from Builder import Trojan from Utils.Logger import logger from Utils.Tester import Settings from Utils.Process import Process from Utils.Constant import xtlsFlows from Utils.Common import md5Sum, genFlag, getAvailablePort def loadServer(configFile: str, proxyInfo: dict, streamConfig: dict, xtlsFlow: str or None) -> Process: trojanConfig = Xray.loadConfig({ 'protocol': 'trojan', 'listen': proxyInfo['server'], 'port': proxyInfo['port'], 'settings': { 'clients': [{ 'password': proxyInfo['passwd'], **({} if xtlsFlow is None else { 'flow': xtlsFlow }) }], }, 'streamSettings': streamConfig }) serverFile = os.path.join(Settings['workDir'], configFile) return Process(Settings['workDir'], cmd = ['xray', '-c', serverFile], file = { 'path': serverFile, 'content': json.dumps(trojanConfig) }, isStart = False) def loadClient(configFile: str, proxyInfo: dict, socksInfo: dict) -> Process: # load client process clientFile = os.path.join(Settings['workDir'], configFile) trojanCommand, trojanConfig, _ = Trojan.load(proxyInfo, socksInfo, clientFile) return Process(Settings['workDir'], cmd = trojanCommand, file = { 'path': clientFile, 'content': trojanConfig }, isStart = False) def loadBasicTest(tcpTlsStream: dict) -> dict: proxyInfo = { # connection info 'server': Settings['serverBind'], 'port': getAvailablePort(), 'passwd': genFlag(length = 8), # random password 'stream': tcpTlsStream['info'] } socksInfo = { # socks5 interface for test 'addr': Settings['clientBind'], 'port': getAvailablePort() } trojanConfig = { 'run_type': 'server', 'local_addr': proxyInfo['server'], 'local_port': proxyInfo['port'], 'password': [proxyInfo['passwd']], 'log_level': 0, # 0 -> ALL / 1 -> INFO / 2 -> WARN / 3 -> ERROR / 4 -> FATAL / 5 -> OFF 'ssl': { 'cert': Settings['cert'], 'key': Settings['key'] } } serverFile = os.path.join(Settings['workDir'], 'trojan_basic_server.json') trojanServer = Process(Settings['workDir'], cmd = ['trojan', '-c', serverFile], file = { 'path': serverFile, 'content': json.dumps(trojanConfig) }, isStart = False) testInfo = { # release test info 'caption': 'Trojan test: basic connection', 'client': loadClient('trojan_basic_client.json', proxyInfo, socksInfo), 'server': trojanServer, 'socks': socksInfo, # exposed socks5 address 'interface': { 'addr': proxyInfo['server'], 'port': proxyInfo['port'], } } logger.debug('New trojan test -> %s' % testInfo) return testInfo def loadTest(stream: dict) -> dict: proxyInfo = { # connection info 'server': Settings['serverBind'], 'port': getAvailablePort(), 'passwd': genFlag(length = 8), # random password 'stream': stream['info'] } socksInfo = { # socks5 interface for test 'addr': Settings['clientBind'], 'port': getAvailablePort() } xtlsFlow = None if stream['info']['secure'] is not None and stream['info']['secure']['type'] == 'xtls': # with XTLS secure xtlsFlow = xtlsFlows[stream['info']['secure']['flow']] xtlsFlow = xtlsFlow.replace('splice', 'direct') # XTLS on server should use xtls-rprx-direct flow configName = 'trojan_%s' % (md5Sum(stream['caption'])[:8]) testInfo = { # release test info 'caption': 'Trojan test: %s' % stream['caption'], 'client': loadClient(configName + '_client.json', proxyInfo, socksInfo), 'server': loadServer(configName + '_server.json', proxyInfo, stream['server'], xtlsFlow), 'socks': socksInfo, # exposed socks5 address 'interface': { 'addr': proxyInfo['server'], 'port': proxyInfo['port'], } } logger.debug('New Trojan test -> %s' % testInfo) return testInfo def load(): streams = Xray.loadStream() # load xray-core stream list yield loadBasicTest(streams[1]) # Trojan basic test -> TCP stream with TLS for stream in streams: # test all stream cases yield loadTest(stream) logger.info('Trojan test yield complete')