From e1816b53cbe017779749eae33c9a6314e34f54aa Mon Sep 17 00:00:00 2001 From: dnomd343 Date: Sat, 6 Aug 2022 18:06:03 +0800 Subject: [PATCH] feat: filter of ShadowsocksR --- Basis/Functions.py | 28 +++++++++++++--- Filter/Shadowsocks.py | 2 +- Filter/ShadowsocksR.py | 74 ++++++++++++++++++++++++++++++++++++++++++ demo.py | 18 ++++++++-- 4 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 Filter/ShadowsocksR.py diff --git a/Basis/Functions.py b/Basis/Functions.py index b718065..923c439 100644 --- a/Basis/Functions.py +++ b/Basis/Functions.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +import re import time import uuid import psutil @@ -10,9 +11,28 @@ from IPy import IP from Basis.Logger import logging -def isHost(raw) -> bool: - # TODO: isHost function - return True +def isIpAddr(ipAddr: str) -> bool: + try: + if '/' in ipAddr: # filter CIDR + return False + if '.' not in ipAddr and ':' not in ipAddr: # not IPv4 or IPv6 + return False + IP(ipAddr) # try to convert to IP address + return True # valid IP address + except: + return False + + +def isDomain(domain: str) -> bool: + try: + domainRegex = r'^(?=^.{3,255}$)[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62})+$' + return re.search(domainRegex, domain) is not None # regex matching + except: # unexpected error + return False + + +def isHost(host: str) -> bool: + return isIpAddr(host) or isDomain(host) # IPv4 / IPv6 / Domain def isPort(port: int) -> bool: @@ -22,7 +42,7 @@ def isPort(port: int) -> bool: def md5Sum(data: str, encode: str = 'utf-8') -> str: - return hashlib.md5(data.encode(encoding = encode)).hexdigest() + return hashlib.md5(data.encode(encoding = encode)).hexdigest() # MD5 hash def hostFormat(host: str, v6Bracket: bool = False) -> str: diff --git a/Filter/Shadowsocks.py b/Filter/Shadowsocks.py index 1053eee..7b23a54 100644 --- a/Filter/Shadowsocks.py +++ b/Filter/Shadowsocks.py @@ -10,7 +10,7 @@ from Basis.Functions import isHost, isPort ssObject = rulesFilter({ 'server': { 'type': str, - 'format': toStr, + 'format': lambda s: toStr(s).strip().lower(), 'filter': isHost, 'errMsg': 'Invalid server address' }, diff --git a/Filter/ShadowsocksR.py b/Filter/ShadowsocksR.py new file mode 100644 index 0000000..807ed26 --- /dev/null +++ b/Filter/ShadowsocksR.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from Basis.Filter import rulesFilter +from Basis.Functions import toInt, toStr +from Basis.Functions import isHost, isPort +from Basis.Constant import ssrMethods, ssrProtocols, ssrObfuscations + + +def ssrProtocolFormat(protocol: str) -> str: + protocol = toStr(protocol).strip().lower().replace('-', '_') + return 'origin' if protocol == '' else protocol # '' -> origin + + +def ssrObfsFormat(obfs: str) -> str: + obfs = toStr(obfs).strip().lower().replace('-', '_') + return 'plain' if obfs == '' else obfs # '' -> plain + + +ssrObject = rulesFilter({ + 'server': { + 'type': str, + 'format': lambda s: toStr(s).strip().lower(), + 'filter': isHost, + 'errMsg': 'Invalid server address' + }, + 'port': { + 'type': int, + 'format': toInt, + 'filter': isPort, + 'errMsg': 'Invalid port number' + }, + 'method': { + 'type': str, + 'format': lambda s: toStr(s).strip().lower().replace('_', '-'), + 'filter': lambda s: s in ssrMethods, + 'errMsg': 'Unknown ShadowsocksR method' + }, + 'passwd': { + 'type': str, + 'format': toStr, + 'errMsg': 'Invalid password content' + }, + 'protocol': { + 'optional': True, + 'default': 'origin', + 'type': str, + 'format': ssrProtocolFormat, + 'filter': lambda s: s in ssrProtocols, + 'errMsg': 'Unknown ShadowsocksR protocol' + }, + 'protocolParam': { + 'optional': True, + 'default': '', + 'type': str, + 'format': toStr, + 'errMsg': 'Invalid ShadowsocksR protocol param' + }, + 'obfs': { + 'optional': True, + 'default': 'plain', + 'type': str, + 'format': ssrObfsFormat, + 'filter': lambda s: s in ssrObfuscations, + 'errMsg': 'Unknown ShadowsocksR obfuscation' + }, + 'obfsParam': { + 'optional': True, + 'default': '', + 'type': str, + 'format': toStr, + 'errMsg': 'Invalid ShadowsocksR obfuscation param' + } +}) diff --git a/demo.py b/demo.py index ddaa726..360f70b 100755 --- a/demo.py +++ b/demo.py @@ -4,8 +4,10 @@ from pprint import pprint from Basis.Filter import Filter from Basis.Filter import filterObject from Filter.Shadowsocks import ssObject +from Filter.ShadowsocksR import ssrObject # pprint(ssObject, sort_dicts = False) +# pprint(ssrObject, sort_dicts = False) # pprint(filterObject, sort_dicts = False) ssProxy = { @@ -14,9 +16,19 @@ ssProxy = { 'method': 'none', 'passwd': 'dnomd343', 'plugin': { - 'type': 'obfs', - + 'type': 'obfs' } } -ret = Filter(ssProxy, ssObject) + +ssrProxy = { + 'server': '1.1.1.1', + 'port': 12345, + 'method': 'table', + 'passwd': 'dnomd343', + 'protocol': 'auth_chain-a', + 'obfs': 'http_post' +} + +# ret = Filter(ssProxy, ssObject) +ret = Filter(ssrProxy, ssrObject) pprint(ret, sort_dicts = False)