Browse Source

update: several boosts

master
Dnomd343 3 years ago
parent
commit
12b9401b72
  1. 36
      ProxyFilter/VMess.py
  2. 70
      ProxyFilter/baseFunc.py
  3. 18
      demo.py
  4. 7
      docs/ProxyObject.md

36
ProxyFilter/VMess.py

@ -29,7 +29,7 @@ quicMethodList = [
vmessFilterRules = { vmessFilterRules = {
'rootObject': { 'rootObject': {
'remark': { 'remark': {
'optional': True, 'optional': False,
'default': '', 'default': '',
'type': str, 'type': str,
'format': baseFunc.toStr 'format': baseFunc.toStr
@ -66,7 +66,6 @@ vmessFilterRules = {
'default': 0, 'default': 0,
'type': int, 'type': int,
'format': baseFunc.toInt, 'format': baseFunc.toInt,
# 'filter': 123,
'filter': lambda aid: aid in range(0, 65536), # 0 ~ 65535 'filter': lambda aid: aid in range(0, 65536), # 0 ~ 65535
'errMsg': 'Illegal alter Id' 'errMsg': 'Illegal alter Id'
}, },
@ -89,9 +88,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'tcp', 'filter': lambda streamType: streamType == 'tcp',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'obfs': { 'obfs': {
'optional': False, 'optional': False,
@ -110,9 +110,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'kcp', 'filter': lambda streamType: streamType == 'kcp',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'seed': { 'seed': {
'optional': False, 'optional': False,
@ -140,9 +141,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'ws', 'filter': lambda streamType: streamType == 'ws',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'host': { 'host': {
'optional': False, 'optional': False,
@ -158,7 +160,8 @@ vmessFilterRules = {
}, },
'ed': { 'ed': {
'optional': False, 'optional': False,
'default': 2048, 'default': None,
'allowNone': True,
'type': int, 'type': int,
'format': baseFunc.toInt, 'format': baseFunc.toInt,
'filter': lambda ed: ed > 0, 'filter': lambda ed: ed > 0,
@ -175,9 +178,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'h2', 'filter': lambda streamType: streamType == 'h2',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'host': { 'host': {
'optional': False, 'optional': False,
@ -202,9 +206,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'quic', 'filter': lambda streamType: streamType == 'quic',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'method': { 'method': {
'optional': False, 'optional': False,
@ -238,9 +243,10 @@ vmessFilterRules = {
'type': { 'type': {
'optional': True, 'optional': True,
'type': str, 'type': str,
'indexKey': True,
'format': baseFunc.toStrTidy, 'format': baseFunc.toStrTidy,
'filter': lambda streamType: streamType == 'grpc', 'filter': lambda streamType: streamType == 'grpc',
'errMsg': 'Unknown stream type' 'errMsg': 'Unexpected stream type'
}, },
'service': { 'service': {
'optional': True, 'optional': True,
@ -279,7 +285,7 @@ vmessFilterRules = {
'optional': False, 'optional': False,
'default': 'h2,http/1.1', 'default': 'h2,http/1.1',
'type': str, 'type': str,
'format': baseFunc.toStr, 'format': baseFunc.toStrTidy,
'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'], 'filter': lambda alpn: alpn in ['h2', 'http/1.1', 'h2,http/1.1'],
'errMsg': 'Illegal alpn option' 'errMsg': 'Illegal alpn option'
}, },
@ -287,7 +293,7 @@ vmessFilterRules = {
'optional': False, 'optional': False,
'default': True, 'default': True,
'type': bool, 'type': bool,
'format': lambda b: b 'format': baseFunc.toBool
} }
} }
} }
@ -308,8 +314,14 @@ def vmessFilter(rawInfo: dict, isExtra: bool) -> tuple[bool, str or dict]:
try: try:
if not isExtra: if not isExtra:
vmessFilterRules['rootObject'].pop('remark') vmessFilterRules['rootObject'].pop('remark')
return baseFunc.ruleFilter(rawInfo, vmessFilterRules, { status, result = baseFunc.ruleFilter(rawInfo, vmessFilterRules, {
'type': 'vmess' 'type': 'vmess'
}) })
if not status:
return False, result
# TODO: host -> sni
return True, result
except: except:
return False, 'Unknown error' return False, 'Unknown error'

70
ProxyFilter/baseFunc.py

@ -5,6 +5,7 @@ import re
import IPy import IPy
import copy import copy
def isHost(host: str) -> bool: def isHost(host: str) -> bool:
""" """
判断host是否合法 判断host是否合法
@ -31,6 +32,7 @@ def isHost(host: str) -> bool:
except: # 异常错误 except: # 异常错误
return False return False
def isPort(port: int) -> bool: def isPort(port: int) -> bool:
""" """
判断端口是否合法 判断端口是否合法
@ -48,6 +50,7 @@ def isPort(port: int) -> bool:
pass pass
return False return False
def toInt(raw) -> int: # change to int def toInt(raw) -> int: # change to int
if isinstance(raw, (int, float)): # int / float -> int if isinstance(raw, (int, float)): # int / float -> int
return int(raw) return int(raw)
@ -60,6 +63,7 @@ def toInt(raw) -> int: # change to int
except: except:
raise Exception('not a integer') raise Exception('not a integer')
def toStr(raw) -> str: # change to str def toStr(raw) -> str: # change to str
if raw is None: if raw is None:
return '' return ''
@ -70,42 +74,70 @@ def toStr(raw) -> str: # change to str
else: else:
raise Exception('type not allowed') raise Exception('type not allowed')
def toBool(raw) -> bool: # change to bool
if isinstance(raw, bool):
return raw
if isinstance(raw, int):
raw = str(raw)
elif isinstance(raw, bytes):
raw = str(raw, encoding='utf-8')
elif not isinstance(raw, str):
raise Exception('type not allowed')
raw = raw.strip().lower()
if raw == 'true':
return True
elif raw == 'false':
return False
else:
try:
raw = int(raw)
return raw != 0
except:
raise Exception('not a boolean')
def toStrTidy(raw) -> str: # change to str with trim and lower def toStrTidy(raw) -> str: # change to str with trim and lower
return toStr(raw).strip().lower() return toStr(raw).strip().lower()
class filterException(Exception): # 检测异常 class filterException(Exception): # 检测异常
def __init__(self, reason): def __init__(self, reason):
self.reason = reason self.reason = reason
def __dictCheck(data: dict, objectList: dict, limitRules: dict, keyPrefix: str) -> dict: # 递归检查dict def __dictCheck(data: dict, objectList: dict, limitRules: dict, keyPrefix: str) -> dict: # 递归检查dict
result = {} result = {}
for key, option in limitRules.items(): # 遍历规则 for key, option in limitRules.items(): # 遍历规则
keyName = key if keyPrefix == '' else keyPrefix + '.' + key keyName = key if keyPrefix == '' else keyPrefix + '.' + key
keyName = '`' + keyName + '`'
# 检查必选key 补全可选key # 检查必选key 补全可选key
if key not in data: if key not in data:
if option['optional']: # 必选 if option['optional']: # 必选
raise filterException('Missing ' + keyName + ' option') # 必选值缺失 raise filterException('Missing `' + keyName + '` option') # 必选值缺失
else: # 可选 else: # 可选
data[key] = option['default'] # 补全可选值 data[key] = option['default'] # 补全可选值
allowNone = False
if 'allowNone' in option and option['allowNone']: # 允许为None
allowNone = True
if not (data[key] is None and allowNone): # 忽略允许None且为None的情况
if 'format' in option: # 预处理数据 if 'format' in option: # 预处理数据
try: try:
data[key] = option['format'](data[key]) data[key] = option['format'](data[key])
except Exception as reason: except Exception as reason:
raise filterException('Illegal ' + keyName + ': ' + str(reason)) # 格式化错误 raise filterException('Illegal `' + keyName + '`: ' + str(reason)) # 格式化错误
# 检查value类型 # 检查value类型
allowNone = False
if 'allowNone' in option and option['allowNone']: # 允许为None
allowNone = True
if data[key] is None: # 值为None if data[key] is None: # 值为None
if not allowNone: # 不允许为None if not allowNone: # 不允许为None
raise filterException('Unexpected None in ' + keyName) raise filterException('Unexpected None in `' + keyName + '`')
result[key] = None result[key] = None
else: else:
dataValue = copy.deepcopy(data[key]) dataValue = copy.deepcopy(data[key])
if isinstance(option['type'], (str, list)) and not isinstance(dataValue, dict): # 子对象下必为dict
raise filterException('Illegal `' + keyName + '`: should be dictionary')
if isinstance(option['type'], str): # 单子对象 if isinstance(option['type'], str): # 单子对象
result[key] = __dictCheck(dataValue, objectList, objectList[option['type']], keyName) # 检查子对象 result[key] = __dictCheck(dataValue, objectList, objectList[option['type']], keyName) # 检查子对象
elif isinstance(option['type'], list): # 多子对象 elif isinstance(option['type'], list): # 多子对象
@ -116,26 +148,36 @@ def __dictCheck(data: dict, objectList: dict, limitRules: dict, keyPrefix: str)
subResult = __dictCheck(dataValue, objectList, objectList[valueType], keyName) # 尝试检查子对象 subResult = __dictCheck(dataValue, objectList, objectList[valueType], keyName) # 尝试检查子对象
except filterException as reason: except filterException as reason:
errMsg = str(reason) # 捕获抛出信息 errMsg = str(reason) # 捕获抛出信息
temp = None
except: except:
temp = None continue
else: # 子对象匹配成功 else: # 子对象匹配成功
break break
if subResult is None: # 无匹配子级 if subResult is None: # 无匹配子级
if errMsg is not None: # 存在子级异常信息 if errMsg is not None: # 存在子级异常信息
raise filterException(errMsg) raise filterException(errMsg)
raise filterException('Error in ' + keyName + ' option') raise filterException('Error in `' + keyName + '` option')
result[key] = subResult result[key] = subResult
elif not isinstance(data[key], option['type']): # 类型不匹配 elif not isinstance(data[key], option['type']): # 类型不匹配
raise filterException('Illegal ' + keyName + ' option') raise filterException('Illegal `' + keyName + '` option')
else: # 检查无误 else: # 检查无误
result[key] = dataValue result[key] = dataValue
if result[key] is not None: # allowNone为False if result[key] is not None: # allowNone为False
if 'filter' in option and not option['filter'](result[key]): # 格式检查 if 'filter' in option:
errFlag = False
try:
if not option['filter'](result[key]): # 格式检查
errFlag = True
except:
raise filterException('Filter error in `' + keyName + '`')
else:
if errFlag:
if 'indexKey' in option and option['indexKey']:
raise Exception('Filter index key')
raise filterException(option['errMsg']) raise filterException(option['errMsg'])
return result return result
def __ruleCheck(ruleSet: dict) -> None: # 规则集合法性检查 def __ruleCheck(ruleSet: dict) -> None: # 规则集合法性检查
if 'rootObject' not in ruleSet: # 根对象检查 if 'rootObject' not in ruleSet: # 根对象检查
raise Exception('Miss root object') raise Exception('Miss root object')
@ -195,6 +237,10 @@ def __ruleCheck(ruleSet: dict) -> None: # 规则集合法性检查
if 'errMsg' in option and not isinstance(option['errMsg'], str): # errMsg必须为str if 'errMsg' in option and not isinstance(option['errMsg'], str): # errMsg必须为str
raise Exception('Error message must be str in ' + keyName) raise Exception('Error message must be str in ' + keyName)
if 'indexKey' in option and not isinstance(option['indexKey'], bool): # indexKey必为bool
raise Exception('Illegal indexKey in ' + keyName)
def ruleFilter(rawData: dict, ruleSet: dict, header: dict) -> tuple[bool, dict or str]: def ruleFilter(rawData: dict, ruleSet: dict, header: dict) -> tuple[bool, dict or str]:
""" """
使用规则集检查原始数据 使用规则集检查原始数据

18
demo.py

@ -2,16 +2,28 @@ import ProxyFilter as Filter
info = { info = {
'type': 'vmess', 'type': 'vmess',
'remark': None, 'remark': 'ok',
'server': b'127.0.0.1 ', 'server': b'127.0.0.1 ',
'port': b"12345", 'port': b"12345",
'method': 'aes-128_gcm', 'method': 'aes-128_gcm',
'id': 'eb6273f1-a98f-59f6-ba52-945f11dee100', 'id': 'eb6273f1-a98f-59f6-ba52-945f11dee100',
'aid': '64',
'stream': { 'stream': {
'type': 'grpc', 'type': 'tcp',
'service': 'test', 'obfs': {
'host': '343.re',
'path': '/test'
},
'secure': {} 'secure': {}
} }
# 'stream': {
# 'type': 'grpc',
# 'service': 'test',
# 'secure': {
# 'sni': 'ip.343.re',
# 'verify': False
# }
# }
} }
status, data = Filter.filte(info, isExtra = True) status, data = Filter.filte(info, isExtra = True)

7
docs/ProxyObject.md

@ -227,7 +227,8 @@
+ 类型:*str* + 类型:*str*
+ 说明:VMess认证ID + 说明:VMess认证ID
+ 缺省:必选 + 缺省:必选
+ 可选值:合法的UUID + 可选值:不限
+ 建议值:合法的UUID
**aid** **aid**
@ -330,9 +331,9 @@
**ed** **ed**
+ 类型:*int* + 类型:*None* / *int*
+ 说明:`Early Data`长度阈值 + 说明:`Early Data`长度阈值
+ 缺省:2048 + 缺省:None
+ 可选值:>0 + 可选值:>0
+ 建议值:2048 + 建议值:2048

Loading…
Cancel
Save