Browse Source

update: optimize the decoder

master
Dnomd343 3 years ago
parent
commit
185a6e0c37
  1. 5
      ProxyDecoder/Brook.py
  2. 39
      ProxyDecoder/Shadowsocks.py
  3. 28
      ProxyDecoder/ShadowsocksR.py
  4. 35
      ProxyDecoder/Trojan.py
  5. 26
      ProxyDecoder/TrojanGo.py
  6. 35
      ProxyDecoder/VLESS.py
  7. 36
      ProxyDecoder/VMess.py
  8. 11
      ProxyDecoder/baseFunc.py
  9. 16
      ProxyDecoder/decoder.py
  10. 44
      demo.py

5
ProxyDecoder/Brook.py

@ -1,7 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
@ -15,14 +14,14 @@ def __addressSplit(address: str) -> dict: # server:port
} }
def __wsSplit(wsServer: str, params: dict) -> dict: def __wsSplit(wsServer: str, params: dict) -> dict: # ws[s]://xxx:xxx/...
wsUrl = baseFunc.urlSplit(wsServer) wsUrl = baseFunc.urlSplit(wsServer)
wsInfo = { wsInfo = {
'server': wsUrl['server'], 'server': wsUrl['server'],
'port': wsUrl['port'], 'port': wsUrl['port'],
'ws': { 'ws': {
'host': wsUrl['server'], 'host': wsUrl['server'],
'path': wsUrl['path'] if wsUrl['path'] != '' else '/ws' 'path': wsUrl['path'] if wsUrl['path'] != '' else '/ws' # path as `/ws` when omitted
} }
} }
if 'address' not in params: if 'address' not in params:

39
ProxyDecoder/Shadowsocks.py

@ -4,6 +4,7 @@
import re import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __ssPlainDecode(url: str) -> dict: def __ssPlainDecode(url: str) -> dict:
""" """
Shadowsocks原始分享链接解码 Shadowsocks原始分享链接解码
@ -31,6 +32,7 @@ def __ssPlainDecode(url: str) -> dict:
'remark': remark 'remark': remark
} }
def __ssCommonDecode(url: str) -> dict: def __ssCommonDecode(url: str) -> dict:
""" """
Shadowsocks经典分享链接解码 Shadowsocks经典分享链接解码
@ -58,6 +60,7 @@ def __ssCommonDecode(url: str) -> dict:
'remark': remark 'remark': remark
} }
def __sip002Decode(url: str) -> dict: def __sip002Decode(url: str) -> dict:
""" """
Shadowsocks SIP002分享链接解码 Shadowsocks SIP002分享链接解码
@ -116,32 +119,24 @@ def __sip002Decode(url: str) -> dict:
info['plugin'] = pluginObject info['plugin'] = pluginObject
return info return info
def ssDecode(url: str, compatible: bool = False) -> dict or None:
"""
Shadowsocks分享链接解码
链接合法: def decode(url: str, compatible: bool = False) -> dict or None:
return { if url.split('://')[0] != 'ss':
'type': 'ss', raise Exception('Unexpected scheme')
...
}
链接不合法:
return None
"""
if url[0:5] != 'ss://':
return None
try: try:
result = __ssCommonDecode(url) # try shadowsocks common decode ssInfo = __ssCommonDecode(url) # try shadowsocks common decode
except: except:
try: try:
result = __sip002Decode(url) # try shadowsocks sip002 decode ssInfo = __sip002Decode(url) # try shadowsocks sip002 decode
except: except:
try: try:
result = __ssPlainDecode(url) # try shadowsocks plain decode ssInfo = __ssPlainDecode(url) # try shadowsocks plain decode
except: except:
return None raise Exception('Url could not be parsed')
if compatible and 'remark' in result: # 向后兼容部分客户端
result['remark'] = result['remark'].replace('+', ' ') if compatible and 'remark' in ssInfo: # 向后兼容部分客户端
result['type'] = 'ss' ssInfo['remark'] = ssInfo['remark'].replace('+', ' ')
return result return {
**{'type': 'ss'},
**ssInfo
}

28
ProxyDecoder/ShadowsocksR.py

@ -4,10 +4,9 @@
import re import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __ssrCommonDecode(url: str) -> dict:
"""
ShadowsocksR经典分享链接解码
def __ssrDecode(url: str) -> dict: # SSR分享链接解码
"""
FORMAT: ssr://BASE64-ENCODED-STRING-WITHOUT-PADDING FORMAT: ssr://BASE64-ENCODED-STRING-WITHOUT-PADDING
EXAMPLE: EXAMPLE:
@ -41,24 +40,11 @@ def __ssrCommonDecode(url: str) -> dict:
info['group'] = baseFunc.base64Decode(params['group']) info['group'] = baseFunc.base64Decode(params['group'])
return info return info
def ssrDecode(url: str) -> dict or None:
"""
ShadowsocksR分享链接解码
链接合法: def decode(url: str) -> dict:
if url.split('://')[0] != 'ssr':
raise Exception('Unexpected scheme')
return { return {
'type': 'ssr', **{'type': 'ssr'},
... **__ssrDecode(url)
} }
链接不合法:
return None
"""
if url[0:6] != 'ssr://':
return None
try:
result = __ssrCommonDecode(url) # try common decode
except:
return None
result['type'] = 'ssr'
return result

35
ProxyDecoder/Trojan.py

@ -4,7 +4,8 @@
import re import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __trojanCommonDecode(url: str) -> dict:
def __trojanDecode(url: str) -> dict:
""" """
Trojan标准分享链接解码 Trojan标准分享链接解码
@ -57,7 +58,7 @@ def __trojanCommonDecode(url: str) -> dict:
if 'type' not in params: if 'type' not in params:
params['type'] = 'tcp' # default -> tcp params['type'] = 'tcp' # default -> tcp
stream = { stream = {
'type': params['type'] 'type': params['type'] if params['type'] != 'http' else 'h2'
} }
if params['type'] == 'tcp': if params['type'] == 'tcp':
if 'headerType' in params and params['headerType'] == 'http': if 'headerType' in params and params['headerType'] == 'http':
@ -100,8 +101,7 @@ def __trojanCommonDecode(url: str) -> dict:
raise Exception('Unknown network type') raise Exception('Unknown network type')
if 'security' in params: if 'security' in params:
if params['security'] not in ['tls', 'xtls']: if params['security'] in ['tls', 'xtls']:
raise Exception('Unknown security type')
secure = { secure = {
'type': params['security'] 'type': params['security']
} }
@ -116,28 +116,19 @@ def __trojanCommonDecode(url: str) -> dict:
secure['flow'] = 'xtls-direct' secure['flow'] = 'xtls-direct'
elif params['flow'] in ['xtls-rprx-splice', 'xtls-rprx-splice-udp443']: elif params['flow'] in ['xtls-rprx-splice', 'xtls-rprx-splice-udp443']:
secure['flow'] = 'xtls-splice' secure['flow'] = 'xtls-splice'
elif params['security'] in ['', 'none']:
secure = None
else:
raise Exception('Unknown security type')
stream['secure'] = secure stream['secure'] = secure
info['stream'] = stream info['stream'] = stream
return info return info
def trojanDecode(url: str) -> dict or None:
"""
Trojan分享链接解码
链接合法: def decode(url: str) -> dict:
if url.split('://')[0] != 'trojan':
raise Exception('Unexpected scheme')
return { return {
'type': 'trojan', **{'type': 'trojan'},
... **__trojanDecode(url)
} }
链接不合法:
return None
"""
if url[0:9] != 'trojan://':
return None
try:
result = __trojanCommonDecode(url) # try Trojan common decode
except:
return None
result['type'] = 'trojan'
return result

26
ProxyDecoder/TrojanGo.py

@ -4,7 +4,7 @@
import re import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __trojanGoCommonDecode(url: str) -> dict: def __trojanGoDecode(url: str) -> dict:
""" """
Trojan-Go标准分享链接解码 Trojan-Go标准分享链接解码
@ -73,24 +73,10 @@ def __trojanGoCommonDecode(url: str) -> dict:
} }
return info return info
def trojanGoDecode(url: str) -> dict or None: def decode(url: str) -> dict:
""" if url.split('://')[0] != 'trojan-go':
Trojan-Go分享链接解码 raise Exception('Unexpected scheme')
链接合法:
return { return {
'type': 'trojan-go', **{'type': 'trojan-go'},
... **__trojanGoDecode(url)
} }
链接不合法:
return None
"""
if url[0:12] != 'trojan-go://':
return None
try:
result = __trojanGoCommonDecode(url) # try Trojan-Go common decode
except:
return None
result['type'] = 'trojan-go'
return result

35
ProxyDecoder/VLESS.py

@ -4,7 +4,8 @@
import re import re
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __vlessCommonDecode(url: str) -> dict:
def __vlessDecode(url: str) -> dict:
""" """
VLESS标准分享链接解码 VLESS标准分享链接解码
@ -55,7 +56,7 @@ def __vlessCommonDecode(url: str) -> dict:
} }
params = baseFunc.paramSplit(match[4]) params = baseFunc.paramSplit(match[4])
stream = { stream = {
'type': params['type'] 'type': params['type'] if params['type'] != 'http' else 'h2'
} }
if params['type'] == 'tcp': if params['type'] == 'tcp':
if 'headerType' in params and params['headerType'] == 'http': if 'headerType' in params and params['headerType'] == 'http':
@ -98,8 +99,7 @@ def __vlessCommonDecode(url: str) -> dict:
raise Exception('Unknown network type') raise Exception('Unknown network type')
if 'security' in params: if 'security' in params:
if params['security'] not in ['tls', 'xtls']: if params['security'] in ['tls', 'xtls']:
raise Exception('Unknown security type')
secure = { secure = {
'type': params['security'] 'type': params['security']
} }
@ -114,28 +114,19 @@ def __vlessCommonDecode(url: str) -> dict:
secure['flow'] = 'xtls-direct' secure['flow'] = 'xtls-direct'
elif params['flow'] in ['xtls-rprx-splice', 'xtls-rprx-splice-udp443']: elif params['flow'] in ['xtls-rprx-splice', 'xtls-rprx-splice-udp443']:
secure['flow'] = 'xtls-splice' secure['flow'] = 'xtls-splice'
elif params['security'] in ['', 'none']:
secure = None
else:
raise Exception('Unknown security type')
stream['secure'] = secure stream['secure'] = secure
info['stream'] = stream info['stream'] = stream
return info return info
def vlessDecode(url: str) -> dict or None:
"""
VLESS分享链接解码
链接合法: def decode(url: str) -> dict:
if url.split('://')[0] != 'vless':
raise Exception('Unexpected scheme')
return { return {
'type': 'vless', **{'type': 'vless'},
... **__vlessDecode(url)
} }
链接不合法:
return None
"""
if url[0:8] != 'vless://':
return None
try:
result = __vlessCommonDecode(url) # try VLESS common decode
except:
return None
result['type'] = 'vless'
return result

36
ProxyDecoder/VMess.py

@ -5,6 +5,7 @@ import re
import json import json
from ProxyDecoder import baseFunc from ProxyDecoder import baseFunc
def __vmessV2raynDecode(url: str) -> dict: def __vmessV2raynDecode(url: str) -> dict:
""" """
v2rayN / v2rayNG分享链接解码 v2rayN / v2rayNG分享链接解码
@ -27,6 +28,7 @@ def __vmessV2raynDecode(url: str) -> dict:
"sni": "...", "sni": "...",
"alpn": "..." "alpn": "..."
} }
""" """
content = json.loads( content = json.loads(
baseFunc.base64Decode( baseFunc.base64Decode(
@ -36,7 +38,7 @@ def __vmessV2raynDecode(url: str) -> dict:
if int(content['v']) != 2: # version => 2 if int(content['v']) != 2: # version => 2
raise Exception('Unknown version field') raise Exception('Unknown version field')
info = { info = {
'server': content['add'], 'server': baseFunc.formatHost(content['add']),
'port': int(content['port']), 'port': int(content['port']),
'id': content['id'], 'id': content['id'],
'aid': int(content['aid']), 'aid': int(content['aid']),
@ -102,6 +104,7 @@ def __vmessV2raynDecode(url: str) -> dict:
info['stream'] = stream info['stream'] = stream
return info return info
def __vmessCommonDecode(url: str) -> dict: def __vmessCommonDecode(url: str) -> dict:
""" """
VMess标准分享链接解码 (only VMessAEAD) VMess标准分享链接解码 (only VMessAEAD)
@ -153,7 +156,7 @@ def __vmessCommonDecode(url: str) -> dict:
if 'encryption' in params: if 'encryption' in params:
info['method'] = params['encryption'] info['method'] = params['encryption']
stream = { stream = {
'type': params['type'] 'type': params['type'] if params['type'] != 'http' else 'h2'
} }
if params['type'] == 'tcp': if params['type'] == 'tcp':
if 'headerType' in params and params['headerType'] == 'http': if 'headerType' in params and params['headerType'] == 'http':
@ -207,27 +210,18 @@ def __vmessCommonDecode(url: str) -> dict:
info['stream'] = stream info['stream'] = stream
return info return info
def vmessDecode(url: str) -> dict or None:
"""
VMess分享链接解码
链接合法:
return {
'type': 'vmess',
...
}
链接不合法: def decode(url: str) -> dict:
return None if url.split('://')[0] != 'vmess':
""" raise Exception('Unexpected scheme')
if url[0:8] != 'vmess://':
return None
try: try:
result = __vmessV2raynDecode(url) # try v2rayN decode vmessInfo = __vmessV2raynDecode(url) # try v2rayN decode
except: except:
try: try:
result = __vmessCommonDecode(url) # try VMess common decode vmessInfo = __vmessCommonDecode(url) # try VMess common decode
except: except:
return None raise Exception('Url could not be parsed')
result['type'] = 'vmess' return {
return result **{'type': 'vmess'},
**vmessInfo
}

11
ProxyDecoder/baseFunc.py

@ -5,14 +5,15 @@ import re
import base64 import base64
import urllib.parse import urllib.parse
def urlEncode(content: str) -> str or None:
def urlEncode(content: str) -> str or None: # url-encode
try: try:
return urllib.parse.urlencode(content) return urllib.parse.urlencode(content)
except: except:
return None return None
def urlDecode(content: str) -> str or None: def urlDecode(content: str) -> str or None: # url-decode
try: try:
return urllib.parse.unquote(content) return urllib.parse.unquote(content)
except: except:
@ -42,7 +43,7 @@ def base64Decode(content: str) -> str or None:
return None return None
def formatHost(host: str) -> str: def formatHost(host: str) -> str: # host -> IP / Domain
try: try:
host = host.lower().strip() host = host.lower().strip()
if host[:1] == '[' and host[-1:] == ']': # [IPv6] if host[:1] == '[' and host[-1:] == ']': # [IPv6]
@ -64,7 +65,7 @@ def paramSplit(paramStr: str) -> dict: # ?param_1=xxx&param_2=xxx&param_3=xxx
return params return params
def splitEdParam(path: str) -> tuple[int or None, str]: # 分离early-data参数 def splitEdParam(path: str) -> tuple[int or None, str]: # split early-data option
if path.find('?') == -1: if path.find('?') == -1:
return None, path return None, path
content = re.search(r'^([\s\S]*?)\?([\s\S]*)$', path) content = re.search(r'^([\s\S]*?)\?([\s\S]*)$', path)
@ -86,13 +87,11 @@ def urlSplit(url: str) -> dict: # scheme://[auth@]server[:port]/.../...?param_1=
url = urllib.parse.urlparse(url) url = urllib.parse.urlparse(url)
auth = port = None auth = port = None
netloc = url[1] netloc = url[1]
if not netloc.find(':') < 0: # server[:port] if not netloc.find(':') < 0: # server[:port]
netloc, port = netloc.rsplit(':', maxsplit = 1) netloc, port = netloc.rsplit(':', maxsplit = 1)
port = int(port) port = int(port)
if not netloc.find('@') < 0: # [auth@]server if not netloc.find('@') < 0: # [auth@]server
auth, netloc = netloc.rsplit('@', maxsplit = 1) auth, netloc = netloc.rsplit('@', maxsplit = 1)
return { return {
'scheme': url[0], 'scheme': url[0],
'auth': auth, 'auth': auth,

16
ProxyDecoder/decoder.py

@ -1,7 +1,6 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import re
from ProxyDecoder import Shadowsocks from ProxyDecoder import Shadowsocks
from ProxyDecoder import ShadowsocksR from ProxyDecoder import ShadowsocksR
from ProxyDecoder import VMess from ProxyDecoder import VMess
@ -10,6 +9,7 @@ from ProxyDecoder import Trojan
from ProxyDecoder import TrojanGo from ProxyDecoder import TrojanGo
from ProxyDecoder import Brook from ProxyDecoder import Brook
def decode(url: str) -> dict or None: def decode(url: str) -> dict or None:
""" """
代理分享链接解码 代理分享链接解码
@ -24,19 +24,19 @@ def decode(url: str) -> dict or None:
} }
""" """
try: try:
scheme = re.search(r'^([\S]+?)://([\s\S]+)$', url).group(1) scheme = url.split('://', maxsplit = 1)[0]
if scheme == 'ss': if scheme == 'ss':
return Shadowsocks.ssDecode(url, compatible = True) return Shadowsocks.decode(url, compatible = True)
elif scheme == 'ssr': elif scheme == 'ssr':
return ShadowsocksR.ssrDecode(url) return ShadowsocksR.decode(url)
elif scheme == 'vmess': elif scheme == 'vmess':
return VMess.vmessDecode(url) return VMess.decode(url)
elif scheme == 'vless': elif scheme == 'vless':
return VLESS.vlessDecode(url) return VLESS.decode(url)
elif scheme == 'trojan': elif scheme == 'trojan':
return Trojan.trojanDecode(url) return Trojan.decode(url)
elif scheme == 'trojan-go': elif scheme == 'trojan-go':
return TrojanGo.trojanGoDecode(url) return TrojanGo.decode(url)
elif scheme == 'brook': elif scheme == 'brook':
return Brook.decode(url) return Brook.decode(url)
except: except:

44
demo.py

@ -5,42 +5,16 @@ import ProxyDecoder as Decoder
import ProxyFilter as Filter import ProxyFilter as Filter
import Check as Checker import Check as Checker
# info = { # url = 'brook://server?address=&insecure=&name=&password=password&server=1.2.3.4%3A9999&username='
# 'type': 'brook', # url = 'brook://server?address=&insecure=&name=&password=password&server=%5B2001%3A4860%3A4860%3A%3A8888%5D%3A9999&username='
# 'server': '127.0.0.1', # url = 'brook://wsserver?address=&insecure=&name=&password=password&username=&wsserver=ws%3A%2F%2F1.2.3.4%3A9999'
# 'port': '12345', # url = 'brook://wsserver?address=&insecure=&name=&password=password&username=&wsserver=ws%3A%2F%2F%5B2001%3A4860%3A4860%3A%3A8888%5D%3A9999'
# 'passwd': 'dnomd343', # url = 'brook://wssserver?address=1.2.3.4%3A443&insecure=true&name=&password=password&username=&wssserver=wss%3A%2F%2Fhello.com%3A443'
# # 'ws': { # url = 'brook://wsserver?address=1.2.3.4%3A443&name=&password=password&username=&wsserver=ws%3A%2F%2Fhello.com%3A443'
# # 'host': 'local.343.re',
# # 'path': '/test',
# # 'secure': {
# # 'verify': False
# # }
# # }
# }
#
# status, ret = Filter.filte(info)
# print(status)
# print(ret)
#
# # print()
# # status, ret = Builder.build(ret, '/tmp/ProxyC')
# # print(status)
# # print(ret)
#
# data = Checker.proxyTest({
# 'check': ['http'],
# 'info': ret
# })
# print(data)
# url = 'ss://bf-cfb:test@192.168.100.1:8888#EXAMPLE'
url = 'brook://server?address=&insecure=&name=&password=password&server=1.2.3.4%3A9999&username=' # url = 'ss://YmYtY2ZiOnRlc3QvIUAjOkAxOTIuMTY4LjEwMC4xOjg4ODg#example-server'
url = 'brook://server?address=&insecure=&name=&password=password&server=%5B2001%3A4860%3A4860%3A%3A8888%5D%3A9999&username=' url = 'ss://cmM0LW1kNTpwYXNzd2Q@192.168.100.1:8888/?plugin=obfs-local%3Bobfs%3Dhttp#Example'
url = 'brook://wsserver?address=&insecure=&name=&password=password&username=&wsserver=ws%3A%2F%2F1.2.3.4%3A9999'
url = 'brook://wsserver?address=&insecure=&name=&password=password&username=&wsserver=ws%3A%2F%2F%5B2001%3A4860%3A4860%3A%3A8888%5D%3A9999'
url = 'brook://wssserver?address=1.2.3.4%3A443&insecure=true&name=&password=password&username=&wssserver=wss%3A%2F%2Fhello.com%3A443'
url = 'brook://wsserver?address=1.2.3.4%3A443&name=&password=password&username=&wsserver=ws%3A%2F%2Fhello.com%3A443'
ret = Decoder.decode(url) ret = Decoder.decode(url)
print(ret) print(ret)

Loading…
Cancel
Save