mirror of https://github.com/dnomd343/ProxyC
dnomd343
2 years ago
12 changed files with 0 additions and 1008 deletions
@ -1,60 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import copy |
|||
|
|||
def __originConfig(proxyInfo: dict) -> list: |
|||
return [ |
|||
'client', |
|||
'--server', proxyInfo['server'] + ':' + str(proxyInfo['port']), |
|||
'--password', proxyInfo['passwd'] |
|||
] |
|||
|
|||
def __wsConfig(proxyInfo: dict) -> list: |
|||
return [ |
|||
'wsclient', |
|||
'--wsserver', 'ws://' + proxyInfo['ws']['host'] + ':' + str(proxyInfo['port']) + proxyInfo['ws']['path'], |
|||
'--address', proxyInfo['server'] + ':' + str(proxyInfo['port']), |
|||
'--password', proxyInfo['passwd'] |
|||
] |
|||
|
|||
def __wssConfig(proxyInfo: dict) -> list: |
|||
wssConfig = [ |
|||
'wssclient', |
|||
'--wssserver', 'wss://' + proxyInfo['ws']['host'] + ':' + str(proxyInfo['port']) + proxyInfo['ws']['path'], |
|||
'--address', proxyInfo['server'] + ':' + str(proxyInfo['port']), |
|||
'--password', proxyInfo['passwd'] |
|||
] |
|||
if not proxyInfo['ws']['secure']['verify']: |
|||
wssConfig += ['--insecure'] |
|||
return wssConfig |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str or None, dict]: |
|||
""" |
|||
Brook配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
proxyInfo = copy.deepcopy(proxyInfo) |
|||
if proxyInfo['server'].find(':') >= 0: |
|||
proxyInfo['server'] = '[' + proxyInfo['server'] + ']' # IPv6 |
|||
if proxyInfo['ws'] is not None and proxyInfo['ws']['host'].find(':') >= 0: |
|||
proxyInfo['ws']['host'] = '[' + proxyInfo['ws']['host'] + ']' # IPv6 |
|||
|
|||
command = [ |
|||
'brook', |
|||
'--debug', '--listen', 'skip success', # debug on |
|||
] |
|||
if proxyInfo['ws'] is None: |
|||
command += __originConfig(proxyInfo) # original mode |
|||
elif proxyInfo['ws']['secure'] is None: |
|||
command += __wsConfig(proxyInfo) # ws mode |
|||
else: |
|||
command += __wssConfig(proxyInfo) # wss mode |
|||
command += [ |
|||
'--socks5', '127.0.0.1:' + str(socksPort) |
|||
] |
|||
return command, None, {} |
@ -1,44 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import copy |
|||
import json |
|||
|
|||
defaultUpSpeed = 10000 |
|||
defaultDownSpeed = 10000 |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str or None, dict]: |
|||
""" |
|||
Hysteria配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
proxyInfo = copy.deepcopy(proxyInfo) |
|||
if proxyInfo['server'].find(':') >= 0: |
|||
proxyInfo['server'] = '[' + proxyInfo['server'] + ']' # IPv6 |
|||
|
|||
config = { |
|||
'server': proxyInfo['server'] + ':' + str(proxyInfo['port']), |
|||
'protocol': proxyInfo['protocol'], |
|||
'up_mbps': defaultUpSpeed, |
|||
'down_mbps': defaultDownSpeed, |
|||
'socks5': { |
|||
'listen': '127.0.0.1:' + str(socksPort) |
|||
} |
|||
} |
|||
|
|||
if proxyInfo['obfs'] is not None: |
|||
config['obfs'] = proxyInfo['obfs'] |
|||
if proxyInfo['auth'] is not None: |
|||
config['auth_str'] = proxyInfo['auth'] |
|||
if proxyInfo['sni'] != '': |
|||
config['server_name'] = proxyInfo['sni'] |
|||
if proxyInfo['alpn'] is not None: |
|||
config['alpn'] = proxyInfo['alpn'] |
|||
if not proxyInfo['verify']: |
|||
config['insecure'] = True |
|||
|
|||
return ['hysteria', '-c', configFile, 'client'], json.dumps(config), {} |
@ -1,225 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
|
|||
ssMethodList = { # Shadowsocks各版本加密方式支持 |
|||
'ss-python': [ |
|||
'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', |
|||
'table', |
|||
'rc4', |
|||
'rc4-md5', |
|||
'rc2-cfb', |
|||
'bf-cfb', |
|||
'cast5-cfb', |
|||
'des-cfb', |
|||
'idea-cfb', |
|||
'seed-cfb', |
|||
'salsa20', |
|||
'xchacha20', |
|||
'chacha20', |
|||
'chacha20-ietf', |
|||
'chacha20-poly1305', |
|||
'chacha20-ietf-poly1305', |
|||
'xchacha20-ietf-poly1305', |
|||
], |
|||
'ss-python-legacy': [ |
|||
'aes-128-ctr', |
|||
'aes-192-ctr', |
|||
'aes-256-ctr', |
|||
'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', |
|||
'camellia-128-cfb', |
|||
'camellia-192-cfb', |
|||
'camellia-256-cfb', |
|||
'table', |
|||
'rc4', |
|||
'rc4-md5', |
|||
'rc2-cfb', |
|||
'bf-cfb', |
|||
'cast5-cfb', |
|||
'des-cfb', |
|||
'idea-cfb', |
|||
'seed-cfb', |
|||
'salsa20', |
|||
'salsa20-ctr', |
|||
'chacha20', |
|||
], |
|||
'ss-libev': [ |
|||
'aes-128-gcm', |
|||
'aes-192-gcm', |
|||
'aes-256-gcm', |
|||
'aes-128-ctr', |
|||
'aes-192-ctr', |
|||
'aes-256-ctr', |
|||
'aes-128-cfb', |
|||
'aes-192-cfb', |
|||
'aes-256-cfb', |
|||
'camellia-128-cfb', |
|||
'camellia-192-cfb', |
|||
'camellia-256-cfb', |
|||
'rc4', |
|||
'rc4-md5', |
|||
'bf-cfb', |
|||
'salsa20', |
|||
'chacha20', |
|||
'chacha20-ietf', |
|||
'chacha20-ietf-poly1305', |
|||
'xchacha20-ietf-poly1305', |
|||
], |
|||
'ss-libev-legacy': [ |
|||
'aes-128-ctr', |
|||
'aes-192-ctr', |
|||
'aes-256-ctr', |
|||
'aes-128-cfb', |
|||
'aes-192-cfb', |
|||
'aes-256-cfb', |
|||
'camellia-128-cfb', |
|||
'camellia-192-cfb', |
|||
'camellia-256-cfb', |
|||
'table', |
|||
'rc4', |
|||
'rc4-md5', |
|||
'rc2-cfb', |
|||
'bf-cfb', |
|||
'cast5-cfb', |
|||
'des-cfb', |
|||
'idea-cfb', |
|||
'seed-cfb', |
|||
'salsa20', |
|||
'chacha20', |
|||
'chacha20-ietf', |
|||
], |
|||
'ss-rust': [ |
|||
'aes-128-gcm', |
|||
'aes-256-gcm', |
|||
'plain', |
|||
'none', |
|||
'chacha20-ietf-poly1305', |
|||
] |
|||
} |
|||
|
|||
def __baseConfig(proxyInfo: dict, socksPort: int) -> dict: # 生成基本配置 |
|||
config = { |
|||
'server': proxyInfo['server'], |
|||
'server_port': proxyInfo['port'], |
|||
'local_address': '127.0.0.1', |
|||
'local_port': socksPort, |
|||
'method': proxyInfo['method'], |
|||
'password': proxyInfo['passwd'], |
|||
} |
|||
if proxyInfo['plugin'] is not None: # 带插件 |
|||
config['plugin'] = proxyInfo['plugin']['type'] |
|||
config['plugin_opts'] = proxyInfo['plugin']['param'] |
|||
return config |
|||
|
|||
def __pluginWithUdp(plugin: str, pluginParam: str) -> bool: # 插件是否使用UDP通讯 |
|||
if plugin in ['obfs-local', 'simple-tls', 'ck-client', |
|||
'gq-client', 'mtt-client', 'rabbit-plugin']: # 不使用UDP通讯的插件 |
|||
return False |
|||
if plugin in ['v2ray-plugin', 'xray-plugin', 'gost-plugin']: |
|||
if 'mode=quic' not in pluginParam.split(';'): # 非quic模式不使用UDP通讯 |
|||
return False |
|||
return True # 默认假定占用UDP |
|||
|
|||
def __ssPython(proxyInfo: dict, socksPort: int, |
|||
isUdp: bool, isLegacy: bool = False) -> tuple[dict, str]: # ss-python配置生成 |
|||
config = __baseConfig(proxyInfo, socksPort) |
|||
mbedtlsMethods = [ |
|||
'aes-128-cfb128', |
|||
'aes-192-cfb128', |
|||
'aes-256-cfb128', |
|||
'camellia-128-cfb128', |
|||
'camellia-192-cfb128', |
|||
'camellia-256-cfb128', |
|||
] |
|||
if not isLegacy: # 新版本特性 |
|||
if config['method'] in mbedtlsMethods: # mbedtls库流加密 |
|||
config['method'] = 'mbedtls:' + config['method'] |
|||
if config['method'] in ['idea-cfb', 'seed-cfb']: # 仅openssl旧版本支持 |
|||
config['extra_opts'] = '--libopenssl=libcrypto.so.1.0.0' |
|||
if not isUdp: |
|||
config['no_udp'] = True # 关闭UDP代理 |
|||
config['shadowsocks'] = 'ss-python-legacy-local' if isLegacy else 'ss-python-local' |
|||
return config, 'ss-bootstrap-local' |
|||
|
|||
def __ssLibev(proxyInfo: dict, socksPort: int, |
|||
isUdp: bool, isLegacy: bool = False) -> tuple[dict, str]: # ss-libev配置生成 |
|||
config = __baseConfig(proxyInfo, socksPort) |
|||
if isUdp: |
|||
config['mode'] = 'tcp_and_udp' |
|||
return config, 'ss-libev-legacy-local' if isLegacy else 'ss-libev-local' |
|||
|
|||
def __ssRust(proxyInfo: dict, socksPort: int, isUdp: bool) -> tuple[dict, str]: # ss-rust配置生成 |
|||
config = __baseConfig(proxyInfo, socksPort) |
|||
if isUdp: |
|||
config['mode'] = 'tcp_and_udp' |
|||
return config, 'ss-rust-local' |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list or None, str or None, dict or None]: |
|||
""" |
|||
Shadowsocks配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
if proxyInfo['plugin'] is None: # 无插件时启用UDP |
|||
isUdp = True |
|||
else: |
|||
isUdp = not __pluginWithUdp( # 获取插件UDP冲突状态 |
|||
proxyInfo['plugin']['type'], proxyInfo['plugin']['param'] |
|||
) |
|||
if proxyInfo['method'] in ssMethodList['ss-libev']: # 按序匹配客户端 |
|||
config, ssFile = __ssLibev(proxyInfo, socksPort, isUdp) |
|||
elif proxyInfo['method'] in ssMethodList['ss-libev-legacy']: |
|||
config, ssFile = __ssLibev(proxyInfo, socksPort, isUdp, isLegacy = True) |
|||
elif proxyInfo['method'] in ssMethodList['ss-python']: |
|||
config, ssFile = __ssPython(proxyInfo, socksPort, isUdp) |
|||
elif proxyInfo['method'] in ssMethodList['ss-python-legacy']: |
|||
config, ssFile = __ssPython(proxyInfo, socksPort, isUdp, isLegacy = True) |
|||
elif proxyInfo['method'] in ssMethodList['ss-rust']: |
|||
config, ssFile = __ssRust(proxyInfo, socksPort, isUdp) |
|||
else: |
|||
raise Exception('Unknown Shadowsocks method') # 无匹配加密方式 |
|||
return [ssFile, '-c', configFile], json.dumps(config), {} |
@ -1,27 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list or None, str or None, dict or None]: |
|||
""" |
|||
ShadowsocksR配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
config = { |
|||
'server': proxyInfo['server'], |
|||
'server_port': proxyInfo['port'], |
|||
'local_address': '127.0.0.1', |
|||
'local_port': socksPort, |
|||
'password': proxyInfo['passwd'], |
|||
'method': proxyInfo['method'], |
|||
'protocol': proxyInfo['protocol'], |
|||
'protocol_param': proxyInfo['protocolParam'], |
|||
'obfs': proxyInfo['obfs'], |
|||
'obfs_param': proxyInfo['obfsParam'] |
|||
} |
|||
return ['ssr-local', '-c', configFile], json.dumps(config), {} |
@ -1,45 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
from ProxyBuilder import Xray |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str, dict]: |
|||
""" |
|||
Trojan配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
flowType = None |
|||
if proxyInfo['stream']['secure'] is not None and proxyInfo['stream']['secure']['type'] == 'xtls': |
|||
flowType = proxyInfo['stream']['secure']['flow'] |
|||
if flowType == 'xtls-origin': |
|||
flowType = 'xtls-rprx-origin' |
|||
elif flowType == 'xtls-direct': |
|||
flowType = 'xtls-rprx-direct' |
|||
elif flowType == 'xtls-splice': |
|||
flowType = 'xtls-rprx-splice' |
|||
else: |
|||
raise Exception('Unknown XTLS flow') |
|||
if proxyInfo['stream']['secure']['udp443']: |
|||
flowType += '-udp443' |
|||
outboundConfig = { |
|||
'protocol': 'trojan', |
|||
'settings': { |
|||
'servers': [ |
|||
{ |
|||
'address': proxyInfo['server'], |
|||
'port': proxyInfo['port'], |
|||
'password': proxyInfo['passwd'], |
|||
} |
|||
] |
|||
}, |
|||
'streamSettings': Xray.xrayStreamConfig(proxyInfo['stream']) |
|||
} |
|||
if flowType is not None: # 添加XTLS流控类型 |
|||
outboundConfig['settings']['servers'][0]['flow'] = flowType |
|||
config = Xray.baseConfig(socksPort, outboundConfig) # Trojan节点配置 |
|||
return ['xray', '-c', configFile], json.dumps(config), {} |
@ -1,76 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
|
|||
def __tlsConfig(proxyInfo: dict) -> dict: |
|||
tlsConfig = { |
|||
'verify': proxyInfo['verify'] |
|||
} |
|||
if proxyInfo['sni'] != '': |
|||
tlsConfig['sni'] = proxyInfo['sni'] |
|||
if proxyInfo['alpn'] is not None: |
|||
tlsConfig['alpn'] = proxyInfo['alpn'].split(',') |
|||
return tlsConfig |
|||
|
|||
def __wsConfig(proxyInfo: dict) -> dict: |
|||
if proxyInfo['ws'] is None: |
|||
return { |
|||
'enabled': False |
|||
} |
|||
wsConfig = { |
|||
'enabled': True, |
|||
'path': proxyInfo['ws']['path'] |
|||
} |
|||
if proxyInfo['ws']['host'] != '': |
|||
wsConfig['host'] = proxyInfo['ws']['host'] |
|||
return wsConfig |
|||
|
|||
def __ssConfig(proxyInfo: dict) -> dict: |
|||
if proxyInfo['ss'] is None: |
|||
return { |
|||
'enabled': False |
|||
} |
|||
return { |
|||
'enabled': True, |
|||
'method': proxyInfo['ss']['method'], |
|||
'password': proxyInfo['ss']['passwd'] |
|||
} |
|||
|
|||
def __pluginConfig(proxyInfo: dict) -> dict: |
|||
if proxyInfo['plugin'] is None: |
|||
return { |
|||
'enabled': False |
|||
} |
|||
return { |
|||
'enabled': True, |
|||
'type': 'shadowsocks', |
|||
'command': proxyInfo['plugin']['type'], |
|||
'option': proxyInfo['plugin']['param'] |
|||
} |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str, dict]: |
|||
""" |
|||
Trojan-Go配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
config = { |
|||
'run_type': 'client', |
|||
'local_addr': '127.0.0.1', |
|||
'local_port': socksPort, |
|||
'remote_addr': proxyInfo['server'], |
|||
'remote_port': proxyInfo['port'], |
|||
'password': [ |
|||
proxyInfo['passwd'] |
|||
], |
|||
'log_level': 0, |
|||
'ssl': __tlsConfig(proxyInfo), |
|||
'websocket': __wsConfig(proxyInfo), |
|||
'shadowsocks': __ssConfig(proxyInfo), |
|||
'transport_plugin': __pluginConfig(proxyInfo) |
|||
} |
|||
return ['trojan-go', '-config', configFile], json.dumps(config), {'PATH': '/usr/bin'} |
@ -1,161 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
logLevel = 'warning' |
|||
|
|||
httpHeader = { |
|||
'type': 'http', |
|||
'request': { |
|||
'version': '1.1', |
|||
'method': 'GET', |
|||
'path': [], |
|||
'headers': { |
|||
'Host': [], |
|||
'User-Agent': [ |
|||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36', |
|||
'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46' |
|||
], |
|||
'Accept-Encoding': [ |
|||
'gzip, deflate' |
|||
], |
|||
'Connection': [ |
|||
'keep-alive' |
|||
], |
|||
'Pragma': 'no-cache' |
|||
} |
|||
} |
|||
} |
|||
|
|||
kcpSettings = { |
|||
'mtu': 1350, |
|||
'tti': 50, |
|||
'uplinkCapacity': 12, |
|||
'downlinkCapacity': 100, |
|||
'congestion': False, |
|||
'readBufferSize': 2, |
|||
'writeBufferSize': 2, |
|||
'header': {} |
|||
} |
|||
|
|||
def __secureConfig(secureInfo: dict or None) -> dict: # TLS加密传输配置 |
|||
if secureInfo is None: |
|||
return {} |
|||
tlsObject = { |
|||
'allowInsecure': not secureInfo['verify'] |
|||
} |
|||
if secureInfo['alpn'] is not None: |
|||
tlsObject['alpn'] = secureInfo['alpn'].split(',') |
|||
if secureInfo['sni'] != '': |
|||
tlsObject['serverName'] = secureInfo['sni'] |
|||
return { |
|||
'security': 'tls', |
|||
'tlsSettings': tlsObject |
|||
} |
|||
|
|||
def tcpConfig(streamInfo: dict, secureFunc) -> dict: # TCP传输方式配置 |
|||
tcpObject = {} |
|||
if streamInfo['obfs'] is not None: |
|||
httpHeader['request']['path'].append(streamInfo['obfs']['path']) |
|||
httpHeader['request']['headers']['Host'] = streamInfo['obfs']['host'].split(',') |
|||
tcpObject['header'] = httpHeader |
|||
return {**{ |
|||
'network': 'tcp', |
|||
'tcpSettings': tcpObject |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def kcpConfig(streamInfo: dict, secureFunc) -> dict: # mKCP传输方式配置 |
|||
kcpObject = kcpSettings |
|||
kcpObject['header']['type'] = streamInfo['obfs'] |
|||
if streamInfo['seed'] is not None: |
|||
kcpObject['seed'] = streamInfo['seed'] |
|||
return {**{ |
|||
'network': 'kcp', |
|||
'kcpSettings': kcpObject |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def wsConfig(streamInfo: dict, secureFunc) -> dict: # WebSocket传输方式配置 |
|||
wsObject = { |
|||
'path': streamInfo['path'] |
|||
} |
|||
if streamInfo['host'] != '': |
|||
wsObject['headers'] = {} |
|||
wsObject['headers']['Host'] = streamInfo['host'] |
|||
if streamInfo['ed'] is not None: |
|||
wsObject['maxEarlyData'] = streamInfo['ed'] |
|||
wsObject['earlyDataHeaderName'] = 'Sec-WebSocket-Protocol' |
|||
return {**{ |
|||
'network': 'ws', |
|||
'wsSettings': wsObject |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def h2Config(streamInfo: dict, secureFunc) -> dict: # HTTP/2传输方式配置 |
|||
h2Object = { |
|||
'path': streamInfo['path'] |
|||
} |
|||
if streamInfo['host'] != '': |
|||
h2Object['host'] = streamInfo['host'].split(',') |
|||
return {**{ |
|||
'network': 'http', |
|||
'httpSettings': h2Object |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def quicConfig(streamInfo: dict, secureFunc) -> dict: # QUIC传输方式配置 |
|||
return {**{ |
|||
'network': 'quic', |
|||
'quicSettings': { |
|||
'security': streamInfo['method'], |
|||
'key': streamInfo['passwd'], |
|||
'header': { |
|||
'type': streamInfo['obfs'] |
|||
} |
|||
} |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def grpcConfig(streamInfo: dict, secureFunc) -> dict: # gRPC传输方式配置 |
|||
grpcObject = { |
|||
'serviceName': streamInfo['service'] |
|||
} |
|||
if streamInfo['mode'] == 'multi': # gRPC multi-mode not work in v2fly-core |
|||
grpcObject['multiMode'] = True |
|||
return {**{ |
|||
'network': 'grpc', |
|||
'grpcSettings': grpcObject |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def v2rayStreamConfig(streamInfo: dict) -> dict: # 生成v2ray传输方式配置 |
|||
streamType = streamInfo['type'] |
|||
if streamType == 'tcp': |
|||
return tcpConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'kcp': |
|||
return kcpConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'ws': |
|||
return wsConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'h2': |
|||
return h2Config(streamInfo, __secureConfig) |
|||
elif streamType == 'quic': |
|||
return quicConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'grpc': |
|||
return grpcConfig(streamInfo, __secureConfig) |
|||
else: |
|||
raise Exception('Unknown stream type') |
|||
|
|||
def baseConfig(socksPort: int, outboundObject: dict) -> dict: # 基础配置生成 |
|||
return { |
|||
'log': { |
|||
'loglevel': logLevel |
|||
}, |
|||
'inbounds': [ |
|||
{ |
|||
'port': socksPort, |
|||
'listen': '127.0.0.1', |
|||
'protocol': 'socks', |
|||
'settings': { |
|||
'udp': True, |
|||
'auth': 'noauth' |
|||
} |
|||
} |
|||
], |
|||
'outbounds': [ |
|||
outboundObject |
|||
] |
|||
} |
@ -1,46 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
from ProxyBuilder import Xray |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str, dict]: |
|||
""" |
|||
VLESS配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
user = { |
|||
'id': proxyInfo['id'], |
|||
'encryption': proxyInfo['method'] |
|||
} |
|||
if proxyInfo['stream']['secure'] is not None and proxyInfo['stream']['secure']['type'] == 'xtls': |
|||
flowType = proxyInfo['stream']['secure']['flow'] |
|||
if flowType == 'xtls-origin': |
|||
user['flow'] = 'xtls-rprx-origin' |
|||
elif flowType == 'xtls-direct': |
|||
user['flow'] = 'xtls-rprx-direct' |
|||
elif flowType == 'xtls-splice': |
|||
user['flow'] = 'xtls-rprx-splice' |
|||
else: |
|||
raise Exception('Unknown XTLS flow') |
|||
if proxyInfo['stream']['secure']['udp443']: |
|||
user['flow'] += '-udp443' |
|||
outboundConfig = { |
|||
'protocol': 'vless', |
|||
'settings': { |
|||
'vnext': [ |
|||
{ |
|||
'address': proxyInfo['server'], |
|||
'port': proxyInfo['port'], |
|||
'users': [user] |
|||
} |
|||
] |
|||
}, |
|||
'streamSettings': Xray.xrayStreamConfig(proxyInfo['stream']) |
|||
} |
|||
config = Xray.baseConfig(socksPort, outboundConfig) # VLESS节点配置 |
|||
return ['xray', '-c', configFile], json.dumps(config), {} |
@ -1,36 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import json |
|||
from ProxyBuilder import V2ray |
|||
|
|||
def load(proxyInfo: dict, socksPort: int, configFile: str) -> tuple[list, str, dict]: |
|||
""" |
|||
VMess配置载入 |
|||
proxyInfo: 节点信息 |
|||
socksPort: 本地通讯端口 |
|||
configFile: 配置文件路径 |
|||
|
|||
return startCommand, fileContent, envVar |
|||
""" |
|||
outboundConfig = { |
|||
'protocol': 'vmess', |
|||
'settings': { |
|||
'vnext': [ |
|||
{ |
|||
'address': proxyInfo['server'], |
|||
'port': proxyInfo['port'], |
|||
'users': [ |
|||
{ |
|||
'id': proxyInfo['id'], |
|||
'alterId': proxyInfo['aid'], |
|||
'security': proxyInfo['method'] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}, |
|||
'streamSettings': V2ray.v2rayStreamConfig(proxyInfo['stream']) |
|||
} |
|||
config = V2ray.baseConfig(socksPort, outboundConfig) # VMess节点配置 |
|||
return ['v2ray', '-c', configFile], json.dumps(config), {} |
@ -1,63 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
from ProxyBuilder import V2ray |
|||
|
|||
baseConfig = V2ray.baseConfig |
|||
|
|||
def __secureConfig(secureInfo: dict or None) -> dict: # TLS/XTLS加密传输配置 |
|||
if secureInfo is None: |
|||
return {} |
|||
secureObject = { |
|||
'allowInsecure': not secureInfo['verify'] |
|||
} |
|||
if secureInfo['alpn'] is not None: |
|||
secureObject['alpn'] = secureInfo['alpn'].split(',') |
|||
if secureInfo['sni'] != '': |
|||
secureObject['serverName'] = secureInfo['sni'] |
|||
if secureInfo['type'] == 'tls': |
|||
return { |
|||
'security': 'tls', |
|||
'tlsSettings': secureObject |
|||
} |
|||
elif secureInfo['type'] == 'xtls': |
|||
return { |
|||
'security': 'xtls', |
|||
'xtlsSettings': secureObject |
|||
} |
|||
else: |
|||
raise Exception('Unknown secure type') |
|||
|
|||
def wsConfig(streamInfo: dict, secureFunc) -> dict: # WebSocket传输方式配置 |
|||
wsObject = { |
|||
'path': streamInfo['path'] |
|||
} |
|||
if streamInfo['host'] != '': |
|||
wsObject['headers'] = {} |
|||
wsObject['headers']['Host'] = streamInfo['host'] |
|||
if streamInfo['ed'] is not None: # ed参数写入路径 -> /...?ed=xxx |
|||
if wsObject['path'].find('?') == -1: # 原路径不带参数 |
|||
wsObject['path'] += '?ed=' + str(streamInfo['ed']) |
|||
else: |
|||
wsObject['path'] += '&ed=' + str(streamInfo['ed']) |
|||
return {**{ |
|||
'network': 'ws', |
|||
'wsSettings': wsObject |
|||
}, **secureFunc(streamInfo['secure'])} |
|||
|
|||
def xrayStreamConfig(streamInfo: dict) -> dict: # 生成xray传输方式配置 |
|||
streamType = streamInfo['type'] |
|||
if streamType == 'tcp': |
|||
return V2ray.tcpConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'kcp': |
|||
return V2ray.kcpConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'ws': |
|||
return wsConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'h2': |
|||
return V2ray.h2Config(streamInfo, __secureConfig) |
|||
elif streamType == 'quic': |
|||
return V2ray.quicConfig(streamInfo, __secureConfig) |
|||
elif streamType == 'grpc': |
|||
return V2ray.grpcConfig(streamInfo, __secureConfig) |
|||
else: |
|||
raise Exception('Unknown stream type') |
@ -1,6 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
from ProxyBuilder.builder import * |
|||
|
|||
__all__ = ['build', 'check', 'destroy'] |
@ -1,219 +0,0 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding:utf-8 -*- |
|||
|
|||
import os |
|||
import time |
|||
import ctypes |
|||
import random |
|||
import socket |
|||
import signal |
|||
import subprocess |
|||
|
|||
from ProxyBuilder import Shadowsocks |
|||
from ProxyBuilder import ShadowsocksR |
|||
from ProxyBuilder import VMess |
|||
from ProxyBuilder import VLESS |
|||
from ProxyBuilder import Trojan |
|||
from ProxyBuilder import TrojanGo |
|||
from ProxyBuilder import Brook |
|||
from ProxyBuilder import Hysteria |
|||
|
|||
libcPaths = [ |
|||
'/usr/lib/libc.so.6', # CentOS |
|||
'/usr/lib64/libc.so.6', |
|||
'/lib/libc.musl-i386.so.1', # Alpine |
|||
'/lib/libc.musl-x86_64.so.1', |
|||
'/lib/libc.musl-aarch64.so.1', |
|||
'/lib/i386-linux-gnu/libc.so.6', # Debian / Ubuntu |
|||
'/lib/x86_64-linux-gnu/libc.so.6', |
|||
'/lib/aarch64-linux-gnu/libc.so.6', |
|||
] |
|||
|
|||
def __preExec(libcPath) -> None: |
|||
ctypes.CDLL(libcPath).prctl(1, signal.SIGTERM) # 子进程跟随退出 |
|||
os.setpgrp() # 新进程组 |
|||
|
|||
|
|||
def __checkPortAvailable(port: int) -> bool: # 检测端口可用性 |
|||
ipv4_tcp = None |
|||
ipv4_udp = None |
|||
ipv6_tcp = None |
|||
ipv6_udp = None |
|||
try: |
|||
ipv4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|||
ipv4_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
|||
ipv4_tcp.bind(('0.0.0.0', port)) |
|||
ipv4_udp.bind(('0.0.0.0', port)) |
|||
ipv4_tcp.close() |
|||
ipv4_udp.close() |
|||
ipv6_tcp = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) |
|||
ipv6_udp = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) |
|||
ipv6_tcp.bind(('::', port)) |
|||
ipv6_udp.bind(('::', port)) |
|||
ipv6_tcp.close() |
|||
ipv6_udp.close() |
|||
return True # IPv4 TCP / IPv4 UDP / IPv6 TCP / IPv6 UDP 均无占用 |
|||
except: |
|||
return False |
|||
finally: # 关闭socket |
|||
try: |
|||
ipv4_tcp.close() |
|||
except: pass |
|||
try: |
|||
ipv4_udp.close() |
|||
except: pass |
|||
try: |
|||
ipv6_tcp.close() |
|||
except: pass |
|||
try: |
|||
ipv6_udp.close() |
|||
except: pass |
|||
|
|||
|
|||
def __genTaskFlag(length: int = 16) -> str: # 生成任务标志 |
|||
flag = '' |
|||
for i in range(0, length): |
|||
tmp = random.randint(0, 15) |
|||
if tmp >= 10: |
|||
flag += chr(tmp + 87) # a ~ f |
|||
else: |
|||
flag += str(tmp) # 0 ~ 9 |
|||
return flag |
|||
|
|||
|
|||
def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or None: # 获取一个空闲端口 |
|||
if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535: |
|||
return None |
|||
while True: |
|||
port = random.randint(rangeStart, rangeEnd) # 随机选取 |
|||
if __checkPortAvailable(port): |
|||
return port |
|||
time.sleep(0.1) # wait for 100ms |
|||
|
|||
|
|||
def build(proxyInfo: dict, configDir: str, |
|||
portRangeStart: int = 1024, portRangeEnd: int = 65535) -> tuple[bool, str or dict]: |
|||
""" |
|||
创建代理节点客户端 |
|||
|
|||
代理节点无效: |
|||
return False, {reason} |
|||
|
|||
代理工作正常: |
|||
return True, { |
|||
'flag': taskFlag, |
|||
'port': socksPort, |
|||
'file': configFile, |
|||
'process': process |
|||
} |
|||
""" |
|||
taskFlag = __genTaskFlag() # 生成测试标志 |
|||
socksPort = __getAvailablePort(portRangeStart, portRangeEnd) # 获取Socks5测试端口 |
|||
|
|||
if 'type' not in proxyInfo: # 未指定节点类型 |
|||
return False, 'Proxy type not specified' |
|||
if proxyInfo['type'] == 'ss': # Shadowsocks节点 |
|||
clientObj = Shadowsocks |
|||
elif proxyInfo['type'] == 'ssr': # ShadowsocksR节点 |
|||
clientObj = ShadowsocksR |
|||
elif proxyInfo['type'] == 'vmess': # VMess节点 |
|||
clientObj = VMess |
|||
elif proxyInfo['type'] == 'vless': # VLESS节点 |
|||
clientObj = VLESS |
|||
elif proxyInfo['type'] == 'trojan': # Trojan节点 |
|||
clientObj = Trojan |
|||
elif proxyInfo['type'] == 'trojan-go': # Trojan-Go节点 |
|||
clientObj = TrojanGo |
|||
elif proxyInfo['type'] == 'brook': # Brook节点 |
|||
clientObj = Brook |
|||
elif proxyInfo['type'] == 'hysteria': # Hysteria节点 |
|||
clientObj = Hysteria |
|||
else: # 未知类型 |
|||
return False, 'Unknown proxy type' |
|||
|
|||
configFile = configDir + '/' + taskFlag + '.json' # 配置文件路径 |
|||
try: |
|||
startCommand, fileContent, envVar = clientObj.load(proxyInfo, socksPort, configFile) # 载入配置 |
|||
except: # 格式出错 |
|||
return False, 'Format error with ' + str(proxyInfo['type']) |
|||
|
|||
try: |
|||
if fileContent is not None: |
|||
with open(configFile, 'w') as fileObject: # 保存配置文件 |
|||
fileObject.write(fileContent) |
|||
except: # 配置文件写入失败 |
|||
raise Exception('Unable write to file ' + str(configFile)) |
|||
|
|||
try: # 子进程形式启动 |
|||
for libcPath in libcPaths: |
|||
if os.path.exists(libcPath): # 定位libc.so文件 |
|||
break |
|||
process = subprocess.Popen( # 启动子进程 |
|||
startCommand, |
|||
env = envVar, |
|||
stdout = subprocess.DEVNULL, |
|||
stderr = subprocess.DEVNULL, |
|||
preexec_fn = lambda: __preExec(libcPath) |
|||
) |
|||
except: |
|||
process = subprocess.Popen( # prctl失败 回退正常启动 |
|||
startCommand, |
|||
env = envVar, |
|||
stdout = subprocess.DEVNULL, |
|||
stderr = subprocess.DEVNULL |
|||
) |
|||
if process is None: # 启动失败 |
|||
raise Exception('Subprocess start failed by `' + ' '.join(startCommand) + '`') |
|||
|
|||
return True, { # 返回连接参数 |
|||
'flag': taskFlag, |
|||
'port': socksPort, |
|||
'file': configFile if fileContent is not None else None, |
|||
'process': process |
|||
} |
|||
|
|||
|
|||
def check(client: dict) -> bool or None: |
|||
""" |
|||
检查客户端是否正常运行 |
|||
|
|||
工作异常: return False |
|||
|
|||
工作正常: return True |
|||
""" |
|||
return client['process'].poll() is None |
|||
|
|||
|
|||
def destroy(client: dict) -> bool: |
|||
""" |
|||
结束客户端并清理 |
|||
|
|||
销毁异常: return False |
|||
|
|||
销毁成功: return True |
|||
""" |
|||
try: |
|||
maxTermTime = 100 # SIGTERM -> SIGKILL |
|||
process = client['process'] |
|||
os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 杀死子进程组 |
|||
time.sleep(0.2) |
|||
while process.poll() is None: # 等待退出 |
|||
maxTermTime -= 1 |
|||
if maxTermTime < 0: |
|||
process.kill() # SIGKILL -> force kill |
|||
else: |
|||
process.terminate() # SIGTERM -> soft kill |
|||
time.sleep(0.2) |
|||
except: |
|||
return False |
|||
|
|||
try: |
|||
file = client['file'] |
|||
if file is None: # 无配置文件 |
|||
return True |
|||
if os.path.exists(file) and os.path.isfile(file): |
|||
os.remove(file) # 删除配置文件 |
|||
return True # 销毁成功 |
|||
except: |
|||
pass |
|||
return False |
Loading…
Reference in new issue