From db27f754e17758a758ccdb3464c50dc081df3095 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Mon, 14 Feb 2022 21:34:50 +0800 Subject: [PATCH] feat: url decode of shadowsocksr --- ProxyDecoder/Shadowsocks.py | 26 +++++++++---- ProxyDecoder/ShadowsocksR.py | 71 ++++++++++++++++++++++++++++++++++++ ProxyDecoder/decoder.py | 3 ++ decode.py | 4 +- 4 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 ProxyDecoder/ShadowsocksR.py diff --git a/ProxyDecoder/Shadowsocks.py b/ProxyDecoder/Shadowsocks.py index de3cc3b..02e2a18 100644 --- a/ProxyDecoder/Shadowsocks.py +++ b/ProxyDecoder/Shadowsocks.py @@ -99,7 +99,7 @@ def __sip002Decode(url: str): for field in content.group(1).split('&'): # /?plugin=...&other1=...&other2=... if field.find('=') == -1: # 缺失xxx=... continue - field = re.search(r'^([\S]*)=([\S]*)$', field) # xxx=... + field = re.search(r'^([\S]*?)=([\S]*)$', field) # xxx=... if field.group(1) == 'plugin': plugin = baseFunc.urlDecode(field.group(2)) # plugin参数 break @@ -119,18 +119,28 @@ def __sip002Decode(url: str): return None def ssDecode(url: str): + ''' + Shadowsocks 分享链接解码 + + 链接合法: + return {...} + + 链接不合法: + return None + ''' try: if url[0:5] != 'ss://': return None result = __ssCommonDecode(url) # try shadowsocks common decode - if result != None: - return result - result = __sip002Decode(url) # try shadowsocks sip002 decode - if result != None: - return result - result = __ssPlainDecode(url) # try shadowsocks plain decode - if result != None: + if result == None: + result = __sip002Decode(url) # try shadowsocks sip002 decode + if result == None: + result = __ssPlainDecode(url) # try shadowsocks plain decode + if result != None: # 解析成功 + result['type'] = 'ss' return result + else: # 解析失败 + return None except: pass return None diff --git a/ProxyDecoder/ShadowsocksR.py b/ProxyDecoder/ShadowsocksR.py new file mode 100644 index 0000000..5102aaf --- /dev/null +++ b/ProxyDecoder/ShadowsocksR.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +import re +from ProxyDecoder import baseFunc + +def __ssrCommonDecode(url: str): + ''' + ShadowsocksR经典分享链接解码 + + FORMAT: ssr://BASE64-ENCODED-STRING-WITHOUT-PADDING + + EXAMPLE: + ssr://{base64} + -> server:port:protocol:method:obfs:base64(passwd)/?... + -> obfsparam=...&protoparam=...&remarks=...&group=... + ''' + try: + content = re.search(r'^ssr://([\S]+)$', url).group(1) # ssr://{base64} + content = re.search( + r'^([a-zA-Z0-9.:_-]*):([0-9]*):' # server:p/r + r'([0-9a-zA-Z_.-]*):([0-9a-zA-Z_.-]*):([0-9a-zA-Z_.-]*):' # protocol:method:obfs: + r'([0-9a-zA-Z_=+\\-]*)(/\?)?([\S]*)?$' # base(passwd)/?... + , baseFunc.base64Decode(content) + ) + info = { + 'server': content.group(1), + 'port': int(content.group(2)), + 'password': baseFunc.base64Decode(content.group(6)), + 'method': content.group(4), + 'protocol': content.group(3), + 'obfs': content.group(5), + } + for field in content.group(8).split('&'): # /?obfsparam=...&protoparam=...&remarks=...&group=... + if field.find('=') == -1: # 缺失xxx=... + continue + field = re.search(r'^([\S]*?)=([\S]*)$', field) # xxx=... + if field.group(1) == 'protoparam': + info['protocolParam'] = baseFunc.base64Decode(field.group(2)) + elif field.group(1) == 'obfsparam': + info['obfsParam'] = baseFunc.base64Decode(field.group(2)) + elif field.group(1) == 'remarks': + info['remark'] = baseFunc.base64Decode(field.group(2)) + elif field.group(1) == 'group': + info['group'] = baseFunc.base64Decode(field.group(2)) + return info + except: + return None + +def ssrDecode(url: str): + ''' + ShadowsocksR 分享链接解码 + + 链接合法: + return {...} + + 链接不合法: + return None + ''' + try: + if url[0:6] != 'ssr://': + return None + result = __ssrCommonDecode(url) # try common decode + if result != None: # 解析成功 + result['type'] = 'ssr' + return result + else: # 解析失败 + return None + except: + pass + return None diff --git a/ProxyDecoder/decoder.py b/ProxyDecoder/decoder.py index 5f94590..f9cc865 100644 --- a/ProxyDecoder/decoder.py +++ b/ProxyDecoder/decoder.py @@ -3,6 +3,7 @@ import re from ProxyDecoder import Shadowsocks +from ProxyDecoder import ShadowsocksR def decode(url): ''' @@ -23,6 +24,8 @@ def decode(url): scheme = re.search(r'^([\S]+?)://([\s\S]+)$', url).group(1) if scheme == 'ss': return Shadowsocks.ssDecode(url) + elif scheme == 'ssr': + return ShadowsocksR.ssrDecode(url) except: pass return None diff --git a/decode.py b/decode.py index 57ef6c2..0367b42 100644 --- a/decode.py +++ b/decode.py @@ -7,4 +7,6 @@ ssPlainUrl = 'ss://bf-cfb:test@192.168.100.1:8888' ssCommonUrl = 'ss://YmYtY2ZiOnRlc3RAMTkyLjE2OC4xMDAuMTo4ODg4#example-server' ssSip002Url = 'ss://cmM0LW1kNTpwYXNzd2Q@192.168.100.1:8888/?plugin=obfs-local%3Bobfs%3Dhttp#Example' -print(Decoder.decode(ssPlainUrl)) +ssrCommonUrl = 'ssr://ZmU4MDo6MTo2MDA0OmF1dGhfYWVzMTI4X21kNTphZXMtMjU2LWNmYjp0bHMxLjJfdGlja2V0X2F1dGg6Y0dGemMzZGsvP29iZnNwYXJhbT1ZMlUzTUdVeE5EY3dOekF1ZFhCa1lYUmxMbTFwWTNKdmMyOW1kQzVqYjIwJnByb3RvcGFyYW09TVRRM01EY3dPa0pGTTIxck9RJnJlbWFya3M9UlZoQlRWQk1SUSZncm91cD1kR1Z6ZEE' + +print(Decoder.decode(ssrCommonUrl))