diff --git a/ProxyFilter/Plugin.py b/ProxyFilter/Plugin.py new file mode 100644 index 0000000..12e2244 --- /dev/null +++ b/ProxyFilter/Plugin.py @@ -0,0 +1,121 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +pluginList = [ # 插件列表 + 'obfs-local', + 'simple-tls', + 'v2ray-plugin', + 'xray-plugin', + 'kcptun-client', + 'gost-plugin', + 'ck-client', + 'gq-client', + 'mtt-client', + 'rabbit-plugin', + 'qtun-client', + 'gun-plugin' +] + +pluginAlias = { # 插件别名 + 'obfs-local': [ + 'obfs', + 'obfs-plugin', + 'obfs-client', + 'obfs-server', + 'simple-obfs', + ], + 'simple-tls': [ + 'tls-local', + 'tls-client', + 'tls-server', + 'tls-plugin', + 'simple-tls-local', + 'simple-tls-client', + 'simple-tls-server', + 'simple-tls-plugin', + ], + 'v2ray-plugin': [ + 'v2ray', + 'v2ray-local', + 'v2ray-client', + 'v2ray-server', + ], + 'xray-plugin': [ + 'xray', + 'xray-local', + 'xray-client', + 'xray-server', + ], + 'kcptun-client': [ + 'kcptun', + 'kcptun-local', + 'kcptun-server', + 'kcptun-plugin', + ], + 'gost-plugin': [ + 'gost', + 'gost-local', + 'gost-client', + 'gost-server', + ], + 'ck-client': [ + 'ck', + 'ck-local', + 'ck-server', + 'ck-plugin', + 'cloak', + 'cloak-local', + 'cloak-client', + 'cloak-server', + 'cloak-plugin', + ], + 'gq-client': [ + 'gq', + 'gq-local', + 'gq-server', + 'gq-plugin', + 'goquiet', + 'goquiet-local', + 'goquiet-client', + 'goquiet-server', + 'goquiet-plugin', + ], + 'mtt-client': [ + 'mtt', + 'mtt-local', + 'mtt-server', + 'mtt-plugin', + 'mos-tls-tunnel', + 'mos-tls-tunnel-local', + 'mos-tls-tunnel-client', + 'mos-tls-tunnel-server', + 'mos-tls-tunnel-plugin', + ], + 'rabbit-plugin': [ + 'rabbit', + 'rabbit-tcp', + 'rabbit-local', + 'rabbit-client', + 'rabbit-server', + ], + 'qtun-client': [ + 'qtun', + 'qtun-local', + 'qtun-server', + 'qtun-plugin', + ], + 'gun-plugin': [ + 'gun', + 'gun-local', + 'gun-client', + 'gun-server', + ] +} + +def pluginFormat(plugin): # 插件格式化 + plugin = plugin.replace('_', '-').lower().strip() + if not plugin in pluginList: # 非标插件名 + for pluginName in pluginAlias: + if plugin in pluginAlias[pluginName]: # 匹配别名列表 + return pluginName + return plugin diff --git a/ProxyFilter/Shadowsocks.py b/ProxyFilter/Shadowsocks.py new file mode 100644 index 0000000..3c36420 --- /dev/null +++ b/ProxyFilter/Shadowsocks.py @@ -0,0 +1,141 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +from ProxyFilter import baseFunc +from ProxyFilter import Plugin as sip003 + +ssMethodList = [ + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'aes-128-ocb', + 'aes-192-ocb', + 'aes-256-ocb', + 'aes-128-ofb', + 'aes-192-ofb', + 'aes-256-ofb', + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-cfb1', + 'aes-192-cfb1', + 'aes-256-cfb1', + 'aes-128-cfb8', + 'aes-192-cfb8', + 'aes-256-cfb8', + 'aes-128-cfb128', + 'aes-192-cfb128', + 'aes-256-cfb128', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'camellia-128-cfb128', + 'camellia-192-cfb128', + 'camellia-256-cfb128', + 'plain', + 'none', + 'table', + 'rc4', + 'rc4-md5', + 'rc2-cfb', + 'bf-cfb', + 'cast5-cfb', + 'des-cfb', + 'idea-cfb', + 'seed-cfb', + 'salsa20', + 'salsa20-ctr', + 'xchacha20', + 'chacha20', + 'chacha20-ietf', + 'chacha20-poly1305', + 'chacha20-ietf-poly1305', + 'xchacha20-ietf-poly1305' +] + +pluginList = [ + 'obfs-local', + 'simple-tls', + 'v2ray-plugin', + 'xray-plugin', + 'kcptun-client', + 'gost-plugin', + 'ck-client', + 'gq-client', + 'mtt-client', + 'rabbit-plugin', + 'qtun-client', + 'gun-plugin' +] + +def __ssFormat(raw): # 容错性格式化 + try: + raw['server'] = raw['server'].strip() + raw['port'] = int(raw['port']) + raw['method'] = raw['method'].replace('_', '-').lower().strip() + raw['plugin'] = sip003.pluginFormat(raw['plugin']) + except: + pass + return raw + +def ssFilter(raw): + ''' + Shadowsocks节点合法性检查 + + 不合法: + return False, {reason} + + 合法: + return True, { + 'type': 'ss', + 'server': '...', + 'port': ..., + 'password': '...', + 'method": '...', + 'plugin": '...', + 'pluginParam": '...' + } + ''' + try: + result = {} + result['type'] = 'ss' + raw = __ssFormat(raw) + + if not 'server' in raw: + return False, 'Missing `server` option' + if not 'port' in raw: + return False, 'Missing `port` option' + if not 'password' in raw: + return False, 'Missing `password` option' + if not 'method' in raw: + return False, 'Missing `method` option' + + if baseFunc.isHost(raw['server']): + result['server'] = raw['server'] + else: + return False, 'Illegal `server` option' + if baseFunc.isPort(raw['port']): + result['port'] = raw['port'] + else: + return False, 'Illegal `port` option' + result['password'] = raw['password'] + if raw['method'] in ssMethodList: + result['method'] = raw['method'] + else: + return False, 'Unknown shadowsocks method' + + if (not 'plugin' in raw) or raw['plugin'] == '': + result['plugin'] = '' + result['pluginParam'] = '' + else: + if raw['plugin'] in pluginList: + result['plugin'] = raw['plugin'] + result['pluginParam'] = raw['pluginParam'] + else: + return False, 'Unknown sip003 plugin' + except: + return False, 'Unknown error' + return True, result diff --git a/ProxyFilter/__init__.py b/ProxyFilter/__init__.py new file mode 100644 index 0000000..f7b8eb9 --- /dev/null +++ b/ProxyFilter/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +from ProxyFilter.filter import * + +__all__ = [ 'filter' ] diff --git a/ProxyFilter/baseFunc.py b/ProxyFilter/baseFunc.py new file mode 100644 index 0000000..dc397ad --- /dev/null +++ b/ProxyFilter/baseFunc.py @@ -0,0 +1,39 @@ +import re +import IPy + +def isHost(host: str) -> bool: + ''' + 判断host是否合法 + + IPv4 / IPv6 / Domain + + 合法: return True + + 不合法: return False + ''' + try: + IPy.IP(host) + if host.find('/') != -1: # filter CIDR + return False + return True + except: # not IP address + pass + return (re.search(r'^(?=^.{3,255}$)[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62})+$', host) != None) + +def isPort(port) -> bool: + ''' + 判断端口是否合法 + + 1 ~ 65535 + + 合法: return True + + 不合法: return False + ''' + try: + if isinstance(port, (int, str)): + if int(port) >= 1 and int(port) <= 65535: + return True + except: # illegal + pass + return False diff --git a/ProxyFilter/filter.py b/ProxyFilter/filter.py new file mode 100644 index 0000000..de5a443 --- /dev/null +++ b/ProxyFilter/filter.py @@ -0,0 +1,30 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +from ProxyFilter import Shadowsocks + +def filter(raw): + ''' + 代理信息过滤并格式化 + + 参数无效: + return False, {reason} + + 参数有效: + return True, { + '...': '...', + '...': '...', + ... + } + + ''' + try: + if not 'type' in raw: + return False, 'Missing `type` option' + if raw['type'] == 'ss': + return Shadowsocks.ssFilter(raw) + else: + return False, 'Unknown proxy type' + except: + pass + return False, 'Unknown error' diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..8232825 --- /dev/null +++ b/demo.py @@ -0,0 +1,16 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +import ProxyFilter as Filter + +info = { + "type": "ss", + "server": "127.0.0.1 ", + "port": 12345, + "password": "dnomd343", + "method": "aes_256-ctr", + "plugin": "obfs", + "pluginParam": "obfs=http;host=www.bing.com" +} + +print(Filter.filter(info))