|
|
|
#!/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 __baseJSON(proxyInfo, socksPort): # 生成JSON基本结构
|
|
|
|
jsonContent = {
|
|
|
|
'server': proxyInfo['server'],
|
|
|
|
'server_port': int(proxyInfo['port']),
|
|
|
|
'local_address': '127.0.0.1',
|
|
|
|
'local_port': int(socksPort),
|
|
|
|
'password': proxyInfo['password'],
|
|
|
|
'method': proxyInfo['method'],
|
|
|
|
}
|
|
|
|
if proxyInfo['plugin'] != '':
|
|
|
|
jsonContent['plugin'] = proxyInfo['plugin']
|
|
|
|
jsonContent['plugin_opts'] = proxyInfo['pluginParam']
|
|
|
|
return jsonContent
|
|
|
|
|
|
|
|
def __pluginUdpCheck(plugin, pluginParam): # 插件是否使用UDP通讯
|
|
|
|
if plugin == '': # 无插件
|
|
|
|
return False
|
|
|
|
noUdpPlugin = [ # 不使用UDP通讯的插件
|
|
|
|
'obfs-local',
|
|
|
|
'simple-tls',
|
|
|
|
'ck-client',
|
|
|
|
'gq-client',
|
|
|
|
'mtt-client',
|
|
|
|
'rabbit-plugin',
|
|
|
|
'gun-plugin',
|
|
|
|
]
|
|
|
|
onlyUdpPlugin = [ # 仅使用UDP通讯的插件
|
|
|
|
'kcptun-client',
|
|
|
|
'qtun-client',
|
|
|
|
]
|
|
|
|
if plugin in noUdpPlugin:
|
|
|
|
return False
|
|
|
|
if plugin in onlyUdpPlugin:
|
|
|
|
return True
|
|
|
|
if plugin == 'v2ray-plugin' or plugin == 'xray-plugin' or plugin == 'gost-plugin':
|
|
|
|
if not 'mode=quic' in pluginParam.split(';'):
|
|
|
|
return False
|
|
|
|
return True # 默认假定占用UDP
|
|
|
|
|
|
|
|
def __ssPython(proxyInfo, socksPort, isLegacy = False): # ss-python配置文件生成
|
|
|
|
jsonContent = __baseJSON(proxyInfo, socksPort)
|
|
|
|
specialMethods = [
|
|
|
|
'aes-128-cfb128',
|
|
|
|
'aes-192-cfb128',
|
|
|
|
'aes-256-cfb128',
|
|
|
|
'camellia-128-cfb128',
|
|
|
|
'camellia-192-cfb128',
|
|
|
|
'camellia-256-cfb128',
|
|
|
|
]
|
|
|
|
if isLegacy == False: # 仅新版本支持
|
|
|
|
if jsonContent['method'] in specialMethods:
|
|
|
|
jsonContent['method'] = 'mbedtls:' + jsonContent['method']
|
|
|
|
if jsonContent['method'] == 'idea-cfb' or jsonContent['method'] == 'seed-cfb':
|
|
|
|
jsonContent['extra_opts'] = '--libopenssl=libcrypto.so.1.0.0'
|
|
|
|
if proxyInfo['udp'] != True:
|
|
|
|
jsonContent['no_udp'] = True
|
|
|
|
if isLegacy == True:
|
|
|
|
jsonContent['shadowsocks'] = 'ss-python-legacy-local'
|
|
|
|
else:
|
|
|
|
jsonContent['shadowsocks'] = 'ss-python-local'
|
|
|
|
return jsonContent, 'ss-bootstrap-local'
|
|
|
|
|
|
|
|
def __ssLibev(proxyInfo, socksPort, isLegacy = False): # ss-libev配置文件生成
|
|
|
|
jsonContent = __baseJSON(proxyInfo, socksPort)
|
|
|
|
if proxyInfo['udp'] == True:
|
|
|
|
jsonContent['mode'] = 'tcp_and_udp'
|
|
|
|
if isLegacy == True:
|
|
|
|
return jsonContent, 'ss-libev-legacy-local'
|
|
|
|
else:
|
|
|
|
return jsonContent, 'ss-libev-local'
|
|
|
|
|
|
|
|
def __ssRust(proxyInfo, socksPort): # ss-rust配置文件生成
|
|
|
|
jsonContent = __baseJSON(proxyInfo, socksPort)
|
|
|
|
if proxyInfo['udp'] == True:
|
|
|
|
jsonContent['mode'] = 'tcp_and_udp'
|
|
|
|
return jsonContent, 'ss-rust-local'
|
|
|
|
|
|
|
|
def load(proxyInfo, socksPort, configFile): # Shadowsocks配置载入
|
|
|
|
proxyInfo['udp'] = not __pluginUdpCheck(proxyInfo['plugin'], proxyInfo['pluginParam'])
|
|
|
|
if proxyInfo['method'] in ssMethodList['ss-libev']:
|
|
|
|
jsonContent, ssFile = __ssLibev(proxyInfo, socksPort)
|
|
|
|
elif proxyInfo['method'] in ssMethodList['ss-libev-legacy']:
|
|
|
|
jsonContent, ssFile = __ssLibev(proxyInfo, socksPort, isLegacy = True)
|
|
|
|
elif proxyInfo['method'] in ssMethodList['ss-python']:
|
|
|
|
jsonContent, ssFile = __ssPython(proxyInfo, socksPort)
|
|
|
|
elif proxyInfo['method'] in ssMethodList['ss-python-legacy']:
|
|
|
|
jsonContent, ssFile = __ssPython(proxyInfo, socksPort, isLegacy = True)
|
|
|
|
elif proxyInfo['method'] in ssMethodList['ss-rust']:
|
|
|
|
jsonContent, ssFile = __ssRust(proxyInfo, socksPort)
|
|
|
|
else:
|
|
|
|
return None, None # 匹配不到加密方式
|
|
|
|
return [ ssFile, '-c', configFile ], json.dumps(jsonContent)
|