Browse Source

feat: filter of VMess

master
dnomd343 2 years ago
parent
commit
e28832f450
  1. 10
      Basis/Filter.py
  2. 12
      Basis/Functions.py
  3. 6
      Filter/Plugin.py
  4. 6
      Filter/Shadowsocks.py
  5. 6
      Filter/ShadowsocksR.py
  6. 239
      Filter/V2ray.py
  7. 62
      Filter/VMess.py
  8. 22
      demo.py
  9. 18
      docs/ProxyObject/VMess.md

10
Basis/Filter.py

@ -80,14 +80,14 @@ def Filter(raw: dict, rules: dict) -> dict:
else: # key exist
data[key] = raw[key]
# format process (data --[format]--> data)
try:
data[key] = rule['format'](data[key]) # run format
except:
raise RuntimeError(rule['errMsg']) # format error
if data[key] is None: # key content is None
if not rule['allowNone']: # key is not allow None
raise RuntimeError('Field `%s` shouldn\'t be None' % key)
continue # skip following process
try:
data[key] = rule['format'](data[key]) # run format
except:
raise RuntimeError(rule['errMsg']) # format error
# filter process (data --[type check (& filter check)]--> pass / non-pass)
if type(rule['type']) == type: # str / int / bool / ...
rule['type'] = [rule['type']] # str -> [str] / int -> [int] / ...
@ -104,7 +104,7 @@ def Filter(raw: dict, rules: dict) -> dict:
else: # multi subObject
if rule['indexKey'] not in data[key]: # confirm index key exist
raise RuntimeError('Index key not found in `%s`' % key)
subType = data[key][rule['indexKey']]
subType = data[key][rule['indexKey']].lower()
if subType not in rule['type']: # confirm subObject rule exist
raise RuntimeError('Unknown index `%s` in key `%s`' % (subType, key))
subRules = rule['type'][subType]

12
Basis/Functions.py

@ -38,7 +38,7 @@ def isHost(host: str) -> bool:
def isPort(port: int) -> bool:
if type(port) != int:
return False
return 1 <= port <= 65535 # 1 ~ 65535
return port in range(1, 65536) # 1 ~ 65535
def md5Sum(data: str, encode: str = 'utf-8') -> str:
@ -80,9 +80,9 @@ def toInt(raw) -> int:
raise RuntimeError('Unable convert to int')
def toStr(raw, acceptNone: bool = True) -> str:
if raw is None and acceptNone: # None -> ''
return ''
def toStr(raw) -> str:
if raw is None:
raise RuntimeError('None could not convert to str')
if isinstance(raw, bytes): # bytes -> str
return str(raw, encoding = 'utf-8')
try:
@ -91,6 +91,10 @@ def toStr(raw, acceptNone: bool = True) -> str:
raise RuntimeError('Unable convert to str')
def toStrTidy(raw) -> str:
return toStr(raw).strip().lower() # with trim and lower
def toBool(raw) -> bool:
if isinstance(raw, (bool, int, float)):
return bool(raw)

6
Filter/Plugin.py

@ -2,9 +2,9 @@
# -*- coding: utf-8 -*-
import copy
from Basis.Functions import toStr
from Basis.Filter import rulesFilter
from Basis.Constant import pluginClients
from Basis.Functions import toStr, toStrTidy
pluginAlias = {
'obfs-local': {'obfs', 'simple-obfs'},
@ -24,7 +24,7 @@ pluginAlias = {
pluginObject = rulesFilter({
'type': {
'type': str,
'format': lambda s: pluginFormat(toStr(s)),
'format': lambda s: pluginFormat(toStrTidy(s)),
'filter': lambda s: s in pluginClients,
'errMsg': 'Unknown SIP003 plugin'
},
@ -48,7 +48,7 @@ def loadAlias() -> None:
def pluginFormat(pluginName: str) -> str:
pluginName = pluginName.strip().lower().replace('_', '-')
pluginName = pluginName.replace('_', '-')
for plugin, alias in pluginAlias.items():
if pluginName in alias:
return plugin

6
Filter/Shadowsocks.py

@ -4,13 +4,13 @@
from Basis.Filter import rulesFilter
from Filter.Plugin import pluginObject
from Basis.Constant import ssAllMethods
from Basis.Functions import toInt, toStr
from Basis.Functions import isHost, isPort
from Basis.Functions import toInt, toStr, toStrTidy
ssObject = rulesFilter({
'server': {
'type': str,
'format': lambda s: toStr(s).strip().lower(),
'format': toStrTidy,
'filter': isHost,
'errMsg': 'Invalid server address'
},
@ -22,7 +22,7 @@ ssObject = rulesFilter({
},
'method': {
'type': str,
'format': lambda s: toStr(s).strip().lower().replace('_', '-'),
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in ssAllMethods,
'errMsg': 'Unknown Shadowsocks method'
},

6
Filter/ShadowsocksR.py

@ -2,8 +2,8 @@
# -*- coding: utf-8 -*-
from Basis.Filter import rulesFilter
from Basis.Functions import toInt, toStr
from Basis.Functions import isHost, isPort
from Basis.Functions import toInt, toStr, toStrTidy
from Basis.Constant import ssrMethods, ssrProtocols, ssrObfuscations
@ -20,7 +20,7 @@ def ssrObfsFormat(obfs: str) -> str:
ssrObject = rulesFilter({
'server': {
'type': str,
'format': lambda s: toStr(s).strip().lower(),
'format': toStrTidy,
'filter': isHost,
'errMsg': 'Invalid server address'
},
@ -32,7 +32,7 @@ ssrObject = rulesFilter({
},
'method': {
'type': str,
'format': lambda s: toStr(s).strip().lower().replace('_', '-'),
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in ssrMethods,
'errMsg': 'Unknown ShadowsocksR method'
},

239
Filter/V2ray.py

@ -0,0 +1,239 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Basis.Filter import rulesFilter
from Basis.Constant import quicMethods, udpObfuscations
from Basis.Functions import toInt, toStr, toStrTidy, toBool
tlsObject = rulesFilter({
'sni': {
'optional': True,
'default': '',
'type': str,
'format': toStrTidy,
'errMsg': 'Invalid SNI content'
},
'alpn': {
'optional': True,
'default': None,
'allowNone': True,
'type': str,
'format': lambda s: toStrTidy(s).replace(' ', ''), # remove space
'filter': lambda s: s in ['h2', 'http/1.1', 'h2,http/1.1'],
'errMsg': 'Invalid alpn option'
},
'verify': {
'optional': True,
'default': True,
'type': bool,
'format': toBool,
'errMsg': 'Invalid verify option'
}
})
obfsObject = rulesFilter({
'host': {
'optional': True,
'default': '',
'type': str,
'format': toStrTidy,
'errMsg': 'Invalid obfs host'
},
'path': {
'optional': True,
'default': '/',
'type': str,
'format': lambda s: toStr(s).strip(),
'errMsg': 'Invalid obfs path'
}
})
tcpObject = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'tcp',
'errMsg': 'Invalid TCP stream type'
},
'obfs': {
'optional': True,
'default': None,
'allowNone': True,
'type': obfsObject,
'errMsg': 'Invalid obfsObject'
},
'secure': {
'optional': True,
'default': None,
'allowNone': True,
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})
kcpObject = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'kcp',
'errMsg': 'Invalid mKCP stream type'
},
'seed': {
'optional': True,
'default': None,
'allowNone': True,
'type': str,
'format': toStr,
'errMsg': 'Invalid mKCP seed'
},
'obfs': {
'optional': True,
'default': 'none',
'type': str,
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in udpObfuscations,
'errMsg': 'Unknown mKCP obfs method'
},
'secure': {
'optional': True,
'default': None,
'allowNone': True,
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})
wsObject = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'ws',
'errMsg': 'Invalid WebSocket stream type'
},
'host': {
'optional': True,
'default': '',
'type': str,
'format': toStrTidy,
'errMsg': 'Invalid WebSocket host'
},
'path': {
'optional': True,
'default': '/',
'type': str,
'format': lambda s: toStr(s).strip(),
'errMsg': 'Invalid WebSocket path'
},
'ed': {
'optional': True,
'default': None,
'allowNone': True,
'type': int,
'format': toInt,
'filter': lambda i: i > 0,
'errMsg': 'Illegal Max-Early-Data length'
},
'secure': {
'optional': True,
'default': None,
'allowNone': True,
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})
h2Object = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'h2',
'errMsg': 'Invalid HTTP/2 stream type'
},
'host': {
'optional': True,
'default': '',
'type': str,
'format': toStrTidy,
'errMsg': 'Invalid HTTP/2 host'
},
'path': {
'optional': True,
'default': '/',
'type': str,
'format': lambda s: toStr(s).strip(),
'errMsg': 'Invalid HTTP/2 path'
},
'secure': {
'optional': True,
'default': {},
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})
quicObject = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'quic',
'errMsg': 'Invalid QUIC stream type'
},
'method': {
'optional': True,
'default': 'none',
'type': str,
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in quicMethods,
'errMsg': 'Unknown QUIC method'
},
'passwd': {
'optional': True,
'default': '',
'type': str,
'format': toStr,
'errMsg': 'Invalid QUIC password'
},
'obfs': {
'optional': True,
'default': 'none',
'type': str,
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in udpObfuscations,
'errMsg': 'Unknown QUIC obfs method'
},
'secure': {
'optional': True,
'default': {},
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})
grpcObject = rulesFilter({
'type': {
'type': str,
'format': toStrTidy,
'filter': lambda s: s == 'grpc',
'errMsg': 'Invalid gRPC stream type'
},
'service': {
'type': str,
'format': lambda s: toStr(s).strip(),
'errMsg': 'Invalid service content'
},
'mode': {
'optional': True,
'default': 'gun',
'type': str,
'format': toStrTidy,
'filter': lambda s: s in ['gun', 'multi'],
'errMsg': 'Unknown gRPC mode'
},
'secure': {
'optional': True,
'default': None,
'allowNone': True,
'type': tlsObject,
'errMsg': 'Invalid tlsObject'
}
})

62
Filter/VMess.py

@ -0,0 +1,62 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Filter import V2ray
from Basis.Filter import rulesFilter
from Basis.Constant import vmessMethods
from Basis.Functions import isHost, isPort
from Basis.Functions import toInt, toStrTidy
vmessObject = rulesFilter({
'server': {
'type': str,
'format': toStrTidy,
'filter': isHost,
'errMsg': 'Invalid server address'
},
'port': {
'type': int,
'format': toInt,
'filter': isPort,
'errMsg': 'Invalid port number'
},
'method': {
'optional': True,
'default': 'auto',
'type': str,
'format': lambda s: toStrTidy(s).replace('_', '-'),
'filter': lambda s: s in vmessMethods,
'errMsg': 'Unknown VMess method'
},
'id': {
'type': str,
'format': toStrTidy,
'errMsg': 'Unknown VMess ID'
},
'aid': {
'optional': True,
'default': 0,
'type': int,
'format': toInt,
'filter': lambda i: i in range(0, 65536), # 0 ~ 65535
'errMsg': 'Invalid VMess alter ID'
},
'stream': {
'optional': True,
'default': {
'type': 'tcp'
},
'multiSub': True,
'type': {
'tcp': V2ray.tcpObject,
'kcp': V2ray.kcpObject,
'ws': V2ray.wsObject,
'h2': V2ray.h2Object,
'quic': V2ray.quicObject,
'grpc': V2ray.grpcObject,
},
'errMsg': 'Invalid VMess stream'
}
})
# TODO: add SNI / ws host / h2 host

22
demo.py

@ -5,9 +5,11 @@ from Basis.Filter import Filter
from Basis.Filter import filterObject
from Filter.Shadowsocks import ssObject
from Filter.ShadowsocksR import ssrObject
from Filter.VMess import vmessObject
# pprint(ssObject, sort_dicts = False)
# pprint(ssrObject, sort_dicts = False)
# pprint(vmessObject, sort_dicts = False)
# pprint(filterObject, sort_dicts = False)
ssProxy = {
@ -29,6 +31,24 @@ ssrProxy = {
'obfs': 'http_post'
}
vmessProxy = {
'server': '1.1.1.1',
'port': b'12345',
'id': 'c8783403-64d5-4b6d-8cf4-bd3988d01b6c',
'aid': '64',
'stream': {
'type': 'GRPC',
'service': 'no-gfw',
'mode': ' multi ',
'secure': {
'sni': ' DNOMD343.top',
'alpn': 'h2, http/1.1',
'verify': 'False '
}
}
}
# ret = Filter(ssProxy, ssObject)
ret = Filter(ssrProxy, ssrObject)
# ret = Filter(ssrProxy, ssrObject)
ret = Filter(vmessProxy, vmessObject)
pprint(ret, sort_dicts = False)

18
docs/ProxyObject/VMess.md

@ -72,7 +72,7 @@
### secure
+ 类型:*None* / [*secureObject*](#secureobject)
+ 类型:*None* / [*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`None`
+ 限制:无
@ -104,7 +104,7 @@
### secure
+ 类型:*None* / [*secureObject*](#secureobject)
+ 类型:*None* / [*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`None`
+ 限制:无
@ -144,7 +144,7 @@
### secure
+ 类型:*None* / [*secureObject*](#secureobject)
+ 类型:*None* / [*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`None`
+ 限制:无
@ -176,9 +176,9 @@
### secure
+ 类型:[*secureObject*](#secureobject)
+ 类型:[*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`None`
+ 缺省:`tlsObject`
+ 限制:无
## quicObject
@ -216,9 +216,9 @@
### secure
+ 类型:[*secureObject*](#secureobject)
+ 类型:[*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`secureObject`
+ 缺省:`tlsObject`
+ 限制:无
## grpcObject
@ -248,7 +248,7 @@
### secure
+ 类型:*None* / [*secureObject*](#secureobject)
+ 类型:*None* / [*tlsObject*](#tlsobject)
+ 说明:TLS加密选项
+ 缺省:`None`
+ 限制:无
@ -276,7 +276,7 @@
+ 缺省:`/`
+ 限制:无
## secureObject
## tlsObject
```
{

Loading…
Cancel
Save