diff --git a/ProxyFilter/TrojanGo.py b/ProxyFilter/TrojanGo.py new file mode 100644 index 0000000..653e589 --- /dev/null +++ b/ProxyFilter/TrojanGo.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +from ProxyFilter import baseFunc +from ProxyFilter import Plugin + +trojanGoFilterRules = { + 'rootObject': { + 'remark': { + 'optional': False, + 'default': '', + 'type': str, + 'format': baseFunc.toStr + }, + 'server': { + 'optional': True, + 'type': str, + 'format': baseFunc.toStrTidy, + 'filter': baseFunc.isHost, + 'errMsg': 'Illegal server address' + }, + 'port': { + 'optional': True, + 'type': int, + 'format': baseFunc.toInt, + 'filter': baseFunc.isPort, + 'errMsg': 'Illegal port number' + }, + 'passwd': { + 'optional': True, + 'type': str, + 'format': baseFunc.toStr + }, + 'sni': { + 'optional': False, + 'default': '', + 'type': str, + 'format': baseFunc.toStr + }, + 'alpn': { + 'optional': False, + 'default': None, + 'allowNone': True, + 'type': str, + 'format': baseFunc.toStrTidy, + 'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'], + 'errMsg': 'Illegal alpn option' + }, + 'verify': { + 'optional': False, + 'default': True, + 'type': bool, + 'format': baseFunc.toBool + }, + 'ws': { + 'optional': False, + 'default': None, + 'allowNone': True, + 'type': 'wsObject' + }, + 'ss': { + 'optional': False, + 'default': None, + 'allowNone': True, + 'type': 'ssObject' + }, + 'plugin': { + 'optional': False, + 'default': None, + 'allowNone': True, + 'type': 'pluginObject' + } + }, + 'ssObject': { + 'method': { + 'optional': False, + 'default': 'AES-128-GCM', + 'type': str, + 'format': lambda s: baseFunc.toStrTidy(s).replace('_', '-').upper(), + 'filter': lambda method: method in ['AES-128-GCM', 'AES-256-GCM', 'CHACHA20-IETF-POLY1305'], + 'errMsg': 'Unknown Shadowsocks method' + }, + 'passwd': { + 'optional': True, + 'type': str, + 'format': baseFunc.toStr + }, + }, + 'wsObject': { + 'host': { + 'optional': False, + 'default': '', + 'type': str, + 'format': baseFunc.toStr + }, + 'path': { + 'optional': False, + 'default': '/', + 'type': str, + 'format': baseFunc.toStr + } + }, + 'pluginObject': { + 'type': { + 'optional': True, + 'type': str, + 'format': lambda pluginType: Plugin.pluginFormat(baseFunc.toStrTidy(pluginType)), + 'filter': Plugin.isPlugin, + 'errMsg': 'Unknown SIP003 plugin' + }, + 'param': { + 'optional': False, + 'default': '', + 'type': str, + 'format': baseFunc.toStr + } + } +} + +def trojanGoFilter(rawInfo: dict, isExtra: bool) -> tuple[bool, str or dict]: + """ + Trojan-Go节点合法性检查 + + 不合法: + return False, {reason} + + 合法: + return True, { + 'type': 'trojan-go', + ... + } + """ + try: + if not isExtra: # 去除非必要参数 + trojanGoFilterRules['rootObject'].pop('remark') + return baseFunc.ruleFilter(rawInfo, trojanGoFilterRules, { + 'type': 'trojan-go' + }) + except: + return False, 'Unknown error' diff --git a/ProxyFilter/filter.py b/ProxyFilter/filter.py index 1043674..366b664 100644 --- a/ProxyFilter/filter.py +++ b/ProxyFilter/filter.py @@ -6,6 +6,7 @@ from ProxyFilter import ShadowsocksR from ProxyFilter import VMess from ProxyFilter import VLESS from ProxyFilter import Trojan +from ProxyFilter import TrojanGo def filte(raw: dict, isExtra: bool = False) -> tuple[bool, str or dict]: """ @@ -34,6 +35,8 @@ def filte(raw: dict, isExtra: bool = False) -> tuple[bool, str or dict]: return VLESS.vlessFilter(raw, isExtra) elif raw['type'] == 'trojan': return Trojan.trojanFilter(raw, isExtra) + elif raw['type'] == 'trojan-go': + return TrojanGo.trojanGoFilter(raw, isExtra) else: return False, 'Unknown proxy type' except: diff --git a/demo.py b/demo.py index 1235fa3..bb5de02 100644 --- a/demo.py +++ b/demo.py @@ -2,37 +2,28 @@ import ProxyDecoder as Decoder import ProxyFilter as Filter import Check as Checker -# url = 'trojan://dnomd343@127.0.0.1:12345?security=tls&sni=local.343.re' -url = 'trojan://dnomd343@local.343.re:12345' +info = { + 'type': 'trojan-go', + 'server': '127.0.0.1', + 'port': '12345', + 'passwd': 'dnomd343', + 'sni': 'local.343.re', + 'alpn': 'h2', + 'verify': False, + 'ws': { + 'host': 'local.343.re', + 'path': '/test' + }, + 'ss': { + 'method': 'chacha20-ietf-poly1305', + 'passwd': 'dnomd343' + }, + 'plugin': { + 'type': 'obfs-local', + 'param': 'obfs=http' + } +} -ret = Decoder.decode(url) -print(ret) -# -status, ret = Filter.filte(ret, isExtra = True) +status, ret = Filter.filte(info, isExtra = True) print(status) print(ret) - -# info = { -# 'type': 'vmess', -# 'server': 'baidu.com', -# 'port': 12345, -# 'id': 'a859f794-1fcb-422e-bcad-3264dcea1f12', -# 'aid': 0, -# 'stream': { -# 'type': 'ws', -# 'host': 'host.343.re', -# 'secure': { -# # 'sni': 'sni.343.re' -# } -# } -# } - -# status, ret = Filter.filte(info, isExtra = True) -# print(status) -# print(ret) - -data = Checker.proxyTest({ - 'check': ['http'], - 'info': ret -}) -print(data) diff --git a/docs/ProxyObject/TrojanGo.md b/docs/ProxyObject/TrojanGo.md new file mode 100644 index 0000000..d26ad9c --- /dev/null +++ b/docs/ProxyObject/TrojanGo.md @@ -0,0 +1,161 @@ +## Trojan-Go + +> **remark** +> +> + 类型:*str* +> + 说明:节点备注名称 +> + 缺省:'' +> + 可选值:不限 + +``` +{ + 'type': 'trojan-go', + 'server': ..., + 'port': ..., + 'passwd': ..., + 'sni': ..., + 'alpn': ..., + 'verify': ..., + 'ws': ..., + 'ss': ..., + 'plugin': ... +} +``` + +**server** + ++ 类型:*str* ++ 说明:服务器地址 ++ 缺省:必选 ++ 可选值:合法的IP地址或域名 + +**port** + ++ 类型:*int* ++ 说明:服务器端口 ++ 缺省:必选 ++ 可选值:1 ~ 65535 + +**passwd** + ++ 类型:*str* ++ 说明:Trojan连接密码 ++ 缺省:必选 ++ 可选值:不限 + +**sni** + ++ 类型:*str* ++ 说明:TLS握手SNI字段 ++ 缺省: '' ++ 可选值:不限 ++ 建议值:合法域名 + +**alpn** + ++ 类型:*None* / *str* ++ 说明:TLS握手协商协议 ++ 缺省:None ++ 可选值:`h2`,`http/1.1`,`h2,http/1.1` ++ 建议值:'h2,http/1.1' + +**verify** + ++ 类型:*bool* ++ 说明:是否验证服务端证书 ++ 缺省:True ++ 可选值:不限 ++ 建议值:True + +**ws** + ++ 类型:*None* / *wsObject* ++ 说明:WebSocket连接配置 ++ 缺省:None ++ 可选值:不限 + +**ss** + ++ 类型:*None* / *ssObject* ++ 说明:Shadowsocks加密配置 ++ 缺省:None ++ 可选值:不限 + +**plugin** + ++ 类型:*None* / *pluginObject* ++ 说明:SIP003插件 ++ 缺省:None ++ 可选值:不限 + +### wsObject + +``` +{ + 'host': ..., + 'path': ... +} +``` + +**host** + ++ 类型:*str* ++ 说明:Websocket连接域名 ++ 缺省:'' ++ 可选值:不限 ++ 建议值:合法域名 + +**path** + ++ 类型:*str* ++ 说明:Websocket连接路径 ++ 缺省:'/' ++ 可选值:不限 ++ 建议值:以`/`开头的合法路径 + +### ssObject + +``` +{ + 'method': ..., + 'passwd': ... +} +``` + +**method** + ++ 类型:*str* ++ 说明:Shadowsocks流加密方式 ++ 缺省:'AES-128-GCM' ++ 可选值:`AES-128-GCM`,`AES-256-GCM`,`CHACHA20-IETF-POLY1305` ++ 建议值:x86平台使用AES方式,ARM平台使用CHACHA20方式 + +**passwd** + ++ 类型:*str* ++ 说明:Shadowsocks密码 ++ 缺省:'' ++ 可选值:不限 + +### pluginObject + +``` +{ + 'type': ..., + 'param': ... +} +``` + +**type** + ++ 类型:*str* ++ 说明:SIP003插件名称 ++ 缺省:必选 ++ 可选值:`obfs-local`,`simple-tls`,`v2ray-plugin`,`xray-plugin`,`kcptun-client`,`gost-plugin`,`ck-client`,`gq-client`,`mtt-client`,`rabbit-plugin`,`qtun-client`,`gun-plugin` + +**param** + ++ 类型:*str* ++ 说明:SIP003插件参数 ++ 缺省:'' ++ 可选值:不限