From d9b6d8aa354932cb6e1de750413f9f837e8cbc3a Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 26 Feb 2022 21:33:52 +0800 Subject: [PATCH] feat: test of VMess --- ProxyBuilder/V2ray.py | 5 +- ProxyBuilder/Xray.py | 5 +- ProxyBuilder/builder.py | 1 - ProxyFilter/V2ray.py | 6 +- ProxyFilter/Xray.py | 14 +-- ProxyTester/V2ray.py | 223 ++++++++++++++++++++++++++++++++++++++++ ProxyTester/VMess.py | 114 +++++++++++++++----- Test.py | 5 +- demo.py | 73 +++++++++++-- docs/ProxyObject.md | 16 +-- 10 files changed, 403 insertions(+), 59 deletions(-) create mode 100644 ProxyTester/V2ray.py diff --git a/ProxyBuilder/V2ray.py b/ProxyBuilder/V2ray.py index c874a1d..61700df 100644 --- a/ProxyBuilder/V2ray.py +++ b/ProxyBuilder/V2ray.py @@ -41,9 +41,10 @@ def __secureConfig(secureInfo: dict or None) -> dict: # TLS加密传输配置 if secureInfo is None: return {} tlsObject = { - 'allowInsecure': not secureInfo['verify'], - 'alpn': secureInfo['alpn'].split(',') + 'allowInsecure': not secureInfo['verify'] } + if secureInfo['alpn'] is not None: + tlsObject['alpn'] = secureInfo['alpn'].split(',') if secureInfo['sni'] != '': tlsObject['serverName'] = secureInfo['sni'] return { diff --git a/ProxyBuilder/Xray.py b/ProxyBuilder/Xray.py index 523dbed..b41b24e 100644 --- a/ProxyBuilder/Xray.py +++ b/ProxyBuilder/Xray.py @@ -9,9 +9,10 @@ def __secureConfig(secureInfo: dict or None) -> dict: # TLS/XTLS加密传输配 if secureInfo is None: return {} secureObject = { - 'allowInsecure': not secureInfo['verify'], - 'alpn': secureInfo['alpn'].split(',') + 'allowInsecure': not secureInfo['verify'] } + if secureInfo['alpn'] is not None: + secureObject['alpn'] = secureInfo['alpn'].split(',') if secureInfo['sni'] != '': secureObject['serverName'] = secureInfo['sni'] if secureInfo['type'] == 'tls': diff --git a/ProxyBuilder/builder.py b/ProxyBuilder/builder.py index 9a03e26..f857a20 100644 --- a/ProxyBuilder/builder.py +++ b/ProxyBuilder/builder.py @@ -119,7 +119,6 @@ def build(proxyInfo: dict, configDir: str, except: # 配置文件写入失败 raise Exception('Unable write to file ' + str(configFile)) - process = None try: # 子进程形式启动 for libcPath in libcPaths: if os.path.exists(libcPath): # 定位libc.so文件 diff --git a/ProxyFilter/V2ray.py b/ProxyFilter/V2ray.py index 189bc76..61d06e4 100644 --- a/ProxyFilter/V2ray.py +++ b/ProxyFilter/V2ray.py @@ -132,8 +132,7 @@ v2rayStreamRules = { }, 'secure': { 'optional': False, - 'default': None, - 'allowNone': True, + 'default': {}, 'type': 'secureObject' } }, @@ -218,7 +217,8 @@ v2rayStreamRules = { }, 'alpn': { 'optional': False, - 'default': 'h2,http/1.1', + 'default': None, + 'allowNone': True, 'type': str, 'format': baseFunc.toStrTidy, 'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'], diff --git a/ProxyFilter/Xray.py b/ProxyFilter/Xray.py index 900c16b..f05bbd1 100644 --- a/ProxyFilter/Xray.py +++ b/ProxyFilter/Xray.py @@ -1,6 +1,8 @@ #!/usr/bin/python # -*- coding:utf-8 -*- +import copy + from ProxyFilter import baseFunc from ProxyFilter import V2ray @@ -10,11 +12,7 @@ xrayFlowList = [ 'xtls-splice', ] -def testFunc(raw): - print(raw) - return False - -xrayStreamRules = V2ray.v2rayStreamRules +xrayStreamRules = copy.deepcopy(V2ray.v2rayStreamRules) xrayStreamRules.pop('secureObject') xrayStreamRules['tcpObject']['secure']['type'] = ['tlsObject', 'xtlsObject'] xrayStreamRules['kcpObject']['secure']['type'] = ['tlsObject', 'xtlsObject'] @@ -40,7 +38,8 @@ xrayStreamRules['tlsObject'] = { }, 'alpn': { 'optional': False, - 'default': 'h2,http/1.1', + 'default': None, + 'allowNone': True, 'type': str, 'format': baseFunc.toStrTidy, 'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'], @@ -71,7 +70,8 @@ xrayStreamRules['xtlsObject'] = { }, 'alpn': { 'optional': False, - 'default': 'h2,http/1.1', + 'default': None, + 'allowNone': True, 'type': str, 'format': baseFunc.toStrTidy, 'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'], diff --git a/ProxyTester/V2ray.py b/ProxyTester/V2ray.py new file mode 100644 index 0000000..5c27306 --- /dev/null +++ b/ProxyTester/V2ray.py @@ -0,0 +1,223 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- +import copy +import json + +httpHeader = { + 'version': '1.1', + 'status': '200', + 'reason': 'OK', + 'headers': { + 'Content-Type': [ + 'application/octet-stream', + 'video/mpeg' + ], + 'Transfer-Encoding': [ + 'chunked' + ], + 'Connection': [ + 'keep-alive' + ], + 'Pragma': 'no-cache' + } +} + +kcpSetting = { + "mtu": 1350, + "tti": 20, + "uplinkCapacity": 5, + "downlinkCapacity": 20, + "congestion": False, + "readBufferSize": 1, + "writeBufferSize": 1, +} + +udpObfsList = [ + 'none', + 'srtp', + 'utp', + 'wechat-video', + 'dtls', + 'wireguard' +] + +quicMethodList = [ + 'none', + 'aes-128-gcm', + 'chacha20-poly1305', +] + +def loadTcpStream(isObfs: bool, host: str, path: str) -> dict: + streamConfig = { + 'network': 'tcp', + 'tcpSettings': { + 'type': 'none' + } + } + if not isObfs: # 不带http混淆 + return { + 'caption': 'TCP', + 'client': { + 'type': 'tcp' + }, + 'server': streamConfig + } + + streamConfig['tcpSettings'] = { # http混淆配置 + 'header': { + 'type': 'http', + 'response': httpHeader + } + } + return { + 'caption': 'TCP with http obfs', + 'client': { + 'type': 'tcp', + 'obfs': { + 'host': host, + 'path': path + } + }, + 'server': streamConfig + } + +def loadKcpStream(seed: str, obfs: str) -> dict: + kcpSetting['header'] = { + 'type': obfs + } + kcpSetting['seed'] = seed + return { + 'caption': 'mKCP obfs ' + obfs, + 'client': { + 'type': 'kcp', + 'seed': seed, + 'obfs': obfs + }, + 'server': { + 'network': 'kcp', + 'kcpSettings': kcpSetting + } + } + +def loadWsStream(host: str, path: str, isEd: bool) -> dict: + wsSetting = { + 'path': path, + 'headers': { + 'Host': host + } + } + if not isEd: # 不带Early Data + return { + 'caption': 'WebSocket', + 'client': { + 'type': 'ws', + 'host': host, + 'path': path + }, + 'server': { + 'network': 'ws', + 'wsSettings': wsSetting + } + } + wsSetting['maxEarlyData'] = 2048 + wsSetting['earlyDataHeaderName'] = 'Sec-WebSocket-Protocol' + return { + 'caption': 'WebSocket Max-Early-Data 2048', + 'client': { + 'type': 'ws', + 'host': host, + 'path': path, + 'ed': 2048 + }, + 'server': { + 'network': 'ws', + 'wsSettings': wsSetting + } + } + +def loadH2Stream(host: str, path: str) -> dict: + return { + 'caption': 'HTTP/2', + 'client': { + 'type': 'h2', + 'host': host, + 'path': path + }, + 'server': { + 'network': 'h2', + 'httpSettings': { + 'host': [host], + 'path': path + } + } + } + +def loadQuicStream(method: str, passwd: str, obfs: str) -> dict: + return { + 'caption': 'QUIC method ' + method + ' obfs ' + obfs, + 'client': { + 'type': 'quic', + 'method': method, + 'passwd': passwd, + 'obfs': obfs + }, + 'server': { + 'network': 'quic', + 'quicSettings': { + "security": method, + "key": passwd, + "header": { + "type": obfs + } + } + } + } + +def loadGrpcStream(service: str) -> dict: + return { + 'caption': 'gRPC', + 'client': { + 'type': 'grpc', + 'service': service + }, + 'server': { + 'network': 'grpc', + 'grpcSettings': { + "serviceName": service + } + } + } + +def addSecureConfig(rawStreamInfo: dict, cert: str, key: str, sni: str) -> dict: + streamInfo = copy.deepcopy(rawStreamInfo) + streamInfo['caption'] += ' (tls)' + streamInfo['client']['secure'] = { + 'sni': sni + } + streamInfo['server']['security'] = 'tls' + streamInfo['server']['tlsSettings'] = { + 'alpn': [ + 'h2', + 'http/1.1' + ], + 'certificates': [ + { + 'certificateFile': cert, + 'keyFile': key + } + ] + } + return streamInfo + +def v2rayConfig(inboundConfig: dict) -> str: + return json.dumps({ + 'log': { + 'loglevel': 'warning' + }, + 'inbounds': [inboundConfig], + 'outbounds': [ + { + 'protocol': 'freedom' + } + ] + }) diff --git a/ProxyTester/VMess.py b/ProxyTester/VMess.py index ce22b93..2ad17ce 100644 --- a/ProxyTester/VMess.py +++ b/ProxyTester/VMess.py @@ -1,8 +1,7 @@ #!/usr/bin/python # -*- coding:utf-8 -*- -import copy -import json +from ProxyTester import V2ray config = {} @@ -14,23 +13,8 @@ vmessMethodList = [ 'zero', ] -def loadServerConfig(inboundObject: dict) -> str: - return json.dumps({ - 'log': { - 'loglevel': 'warning' - }, - 'inbounds': [inboundObject], - 'outbounds': [ - { - 'protocol': 'freedom' - } - ] - }) - -def basicConfig(method: str, alterId: int): - filePath = '/tmp/v2ray.json' - - inboundObject = { +def vmessBasicTest(method: str, alterId: int): + inboundConfig = { 'protocol': 'vmess', 'listen': '127.0.0.1', 'port': config['port'], @@ -65,20 +49,102 @@ def basicConfig(method: str, alterId: int): 'aid': alterId }, 'server': { - 'startCommand': ['v2ray', '-c', filePath], - 'fileContent': loadServerConfig(inboundObject), - 'filePath': filePath, + 'startCommand': ['v2ray', '-c', config['file']], + 'fileContent': V2ray.v2rayConfig(inboundConfig), + 'filePath': config['file'], 'envVar': envVar }, 'aider': None } +def loadVmessStream(streamInfo): + proxyInfo = { + 'type': 'vmess', + 'server': '127.0.0.1', + 'port': config['port'], + 'id': config['id'], + 'stream': streamInfo['client'] + } + inboundConfig = { + 'protocol': 'vmess', + 'listen': '127.0.0.1', + 'port': config['port'], + 'settings': { + 'clients': [ + { + 'id': config['id'] + } + ] + }, + 'streamSettings': streamInfo['server'] + } + return { + 'caption': 'VMess network ' + streamInfo['caption'], + 'proxy': proxyInfo, + 'server': { + 'startCommand': ['v2ray', '-c', config['file']], + 'fileContent': V2ray.v2rayConfig(inboundConfig), + 'filePath': config['file'], + 'envVar': {} + }, + 'aider': None + } + def vmessTest(vmessConfig: dict) -> list: result = [] for key, value in vmessConfig.items(): # vmessConfig -> config config[key] = value + + # Basic test for method in vmessMethodList: # methods and AEAD/MD5+AES test - result.append(basicConfig(method, 0)) - result.append(basicConfig(method, 64)) + result.append(vmessBasicTest(method, 0)) + result.append(vmessBasicTest(method, 64)) + + # TCP stream + streamInfo = V2ray.loadTcpStream(False, '', '') + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + streamInfo = V2ray.loadTcpStream(True, config['host'], '/') + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + # mKCP stream + for obfs in V2ray.udpObfsList: + streamInfo = V2ray.loadKcpStream(config['passwd'], obfs) + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + # WebSocket stream + streamInfo = V2ray.loadWsStream(config['host'], config['path'], False) + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + streamInfo = V2ray.loadWsStream(config['host'], config['path'], True) + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + # HTTP/2 stream + streamInfo = V2ray.loadH2Stream(config['host'], config['path']) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + # QUIC stream + for method in V2ray.quicMethodList: + for obfs in V2ray.udpObfsList: + streamInfo = V2ray.loadQuicStream(method, config['passwd'], obfs) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) + + # GRPC stream + streamInfo = V2ray.loadGrpcStream(config['service']) + result.append(loadVmessStream(streamInfo)) + streamInfo = V2ray.addSecureConfig(streamInfo, config['cert'], config['key'], config['host']) + result.append(loadVmessStream(streamInfo)) return result diff --git a/Test.py b/Test.py index b755dac..0f34397 100644 --- a/Test.py +++ b/Test.py @@ -13,6 +13,9 @@ testConfig = { 'port': 12345, 'passwd': 'dnomd343', 'host': 'dns.343.re', + 'path': '/test', + 'service': 'dnomd343', + 'file': '/tmp/proxyc-test.json', 'cert': '/etc/ssl/certs/dns.343.re/certificate.crt', 'key': '/etc/ssl/certs/dns.343.re/private.key', 'id': '1f7aa040-94d8-4b53-ae85-af6946d550bb', @@ -63,7 +66,7 @@ def testObject(option: dict) -> None: # test target object if len(sys.argv) == 1: # no param print('Unknown test type') sys.exit(1) -testList = Tester.test(sys.argv[1], testConfig) # get test list +testList = Tester.test(sys.argv[1].lower(), testConfig) # get test list if len(sys.argv) == 2: # test all for i in range(0, len(testList)): diff --git a/demo.py b/demo.py index 19ce65f..5d8fc76 100644 --- a/demo.py +++ b/demo.py @@ -3,6 +3,7 @@ import copy import time +import Check as Checker import ProxyFilter as Filter import ProxyBuilder as Builder @@ -27,23 +28,73 @@ import ProxyBuilder as Builder # # print(ret[0]) # print(ret[1]) +# +# info = { +# 'type': 'vless', +# 'server': '127.0.0.1', +# 'port': '12345', +# 'id': '58c0f2eb-5d47-45d0-8f5f-ebae5c2cfdd9', +# 'stream': { +# 'type': 'tcp', +# 'secure': { +# 'type': 'xtls', +# 'udp443': True +# } +# } +# } +# +# info = copy.deepcopy(Filter.filte(info)[1]) +# print(info) +# Builder.build(info, '/tmp/ProxyC') +# time.sleep(5) +# Builder.destroy(info) + +# info = { +# 'type': 'vmess', +# 'server': '127.0.0.1', +# 'port': 12345, +# 'id': '1f7aa040-94d8-4b53-ae85-af6946d550bb', +# 'stream': { +# 'type': 'h2', +# # 'host': 'dns.343.re', +# # 'path': '/test', +# # 'secure': {} +# # 'secure': { +# # 'sni': 'dns.343.re' +# # } +# } +# } +# +# ret = Filter.filte(info) +# +# print(ret[0]) +# print(ret[1]) info = { - 'type': 'vless', + 'type': 'vmess', 'server': '127.0.0.1', - 'port': '12345', - 'id': '58c0f2eb-5d47-45d0-8f5f-ebae5c2cfdd9', + 'port': '3345', + 'id': '657b26d0-d25e-5b75-a018-40cb679c83a3', 'stream': { - 'type': 'tcp', + 'type': 'ws', + 'host': None, + 'path': '/test', + 'ed': 2048, 'secure': { - 'type': 'xtls', - 'udp443': True + 'sni': 'dns.343.re', + 'alpn': 'h2,http/1.1' } } } -info = copy.deepcopy(Filter.filte(info)[1]) -print(info) -Builder.build(info, '/tmp/ProxyC') -time.sleep(5) -Builder.destroy(info) +ret = Filter.filte(info) + +print(ret[0]) +print(ret[1]) + +data = Checker.proxyTest({ + 'check': ['http'], + 'info': ret[1] +}) + +print(data) diff --git a/docs/ProxyObject.md b/docs/ProxyObject.md index 6b8af68..aba1119 100644 --- a/docs/ProxyObject.md +++ b/docs/ProxyObject.md @@ -373,7 +373,7 @@ **secure** -+ 类型:*None* / *secureObject* ++ 类型:*secureObject* + 说明:TLS加密 + 缺省:None + 可选值:不限 @@ -488,9 +488,9 @@ **alpn** -+ 类型:*str* ++ 类型:*None* / *str* + 说明:TLS握手协商协议 -+ 缺省:'h2,http/1.1' ++ 缺省:None + 可选值:`h2`,`http/1.1`,`h2,http/1.1` + 建议值:'h2,http/1.1' @@ -687,7 +687,7 @@ **secure** -+ 类型:*None* / *tlsObject* ++ 类型:*tlsObject* + 说明:TLS加密 + 缺省:None + 可选值:不限 @@ -803,9 +803,9 @@ **alpn** -+ 类型:*str* ++ 类型:*None* / *str* + 说明:TLS握手协商协议 -+ 缺省:'h2,http/1.1' ++ 缺省:None + 可选值:`h2`,`http/1.1`,`h2,http/1.1` + 建议值:'h2,http/1.1' @@ -840,9 +840,9 @@ **alpn** -+ 类型:*str* ++ 类型:*None* / *str* + 说明:TLS握手协商协议 -+ 缺省:'h2,http/1.1' ++ 缺省:None + 可选值:`h2`,`http/1.1`,`h2,http/1.1` + 建议值:'h2,http/1.1'