mirror of https://github.com/dnomd343/ProxyC
Dnomd343
3 years ago
3 changed files with 359 additions and 0 deletions
@ -0,0 +1,238 @@ |
|||||
|
#!/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': proxyInfo['port'], |
||||
|
'local_address': '127.0.0.1', |
||||
|
'local_port': socksPort, |
||||
|
'password': proxyInfo['password'], |
||||
|
'method': proxyInfo['method'], |
||||
|
} |
||||
|
if proxyInfo['plugin'] != '': |
||||
|
jsonContent['plugin'] = proxyInfo['plugin'] |
||||
|
jsonContent['plugin_opts'] = proxyInfo['pluginArg'] |
||||
|
return jsonContent |
||||
|
|
||||
|
def __pluginUdpCheck(plugin, pluginArg): # 插件是否使用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 'mode=quic' in pluginArg.split(';'): |
||||
|
return True |
||||
|
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['pluginArg']) |
||||
|
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 # 匹配不到加密方式 |
||||
|
try: |
||||
|
with open(configFile, 'w') as fileObject: |
||||
|
fileObject.write(json.dumps(jsonContent)) # 保存配置文件 |
||||
|
except: |
||||
|
return None # 配置文件写入失败 |
||||
|
return [ ssFile, '-c', configFile ] |
@ -0,0 +1,79 @@ |
|||||
|
#!/usr/bin/python |
||||
|
# -*- coding:utf-8 -*- |
||||
|
|
||||
|
import time |
||||
|
import random |
||||
|
import socket |
||||
|
import subprocess |
||||
|
from ProxyBuilder import Shadowsocks |
||||
|
|
||||
|
def __checkPortAvailable(port, host = '127.0.0.1'): |
||||
|
s = None |
||||
|
try: |
||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
|
s.settimeout(1) |
||||
|
s.connect((host, int(port))) |
||||
|
return False |
||||
|
except socket.error: |
||||
|
return True |
||||
|
finally: |
||||
|
if s: |
||||
|
s.close() |
||||
|
|
||||
|
def __genTaskFlag(length = 16): # 生成任务代号 |
||||
|
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, rangeEnd): # 获取一个空闲端口 |
||||
|
if rangeStart > rangeEnd: |
||||
|
return None |
||||
|
while True: |
||||
|
port = random.randint(rangeStart, rangeEnd) |
||||
|
if __checkPortAvailable(port): |
||||
|
return port |
||||
|
time.sleep(0.1) # 100ms |
||||
|
|
||||
|
def build(proxyInfo, configDir): # 构建代理节点连接 |
||||
|
taskFlag = __genTaskFlag() |
||||
|
socksPort = __getAvailablePort(1024, 65535) |
||||
|
if not 'type' in proxyInfo: |
||||
|
return None |
||||
|
proxyType = proxyInfo['type'] # 节点类型 |
||||
|
proxyInfo.pop('type') |
||||
|
configFile = configDir + '/' + taskFlag + '.json' # 配置文件路径 |
||||
|
if (proxyType == 'shadowsocks'): # Shadowsocks节点 |
||||
|
startCommand = Shadowsocks.load(proxyInfo, socksPort, configFile) |
||||
|
else: # 未知类型 |
||||
|
return None |
||||
|
process = subprocess.Popen(startCommand, stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) |
||||
|
return { # 返回连接参数 |
||||
|
'flag': taskFlag, |
||||
|
'port': socksPort, |
||||
|
'file': configFile, |
||||
|
'process': process, |
||||
|
'pid': process.pid, |
||||
|
} |
||||
|
|
||||
|
def check(taskInfo): # 检查客户端是否正常 |
||||
|
process = taskInfo['process'] |
||||
|
if process.poll() != None: |
||||
|
return False # 死亡 |
||||
|
else: |
||||
|
return True # 正常 |
||||
|
|
||||
|
def destroy(taskInfo): # 结束客户端并清理 |
||||
|
process = taskInfo['process'] |
||||
|
if process.poll() == None: # 未死亡 |
||||
|
process.terminate() # SIGTERM |
||||
|
while process.poll() == None: # 等待退出 |
||||
|
time.sleep(1) |
||||
|
process.terminate() |
||||
|
try: |
||||
|
os.remove(taskInfo.file) # 删除配置文件 |
||||
|
except: pass |
@ -0,0 +1,42 @@ |
|||||
|
import time |
||||
|
import socket |
||||
|
import requests |
||||
|
import ProxyBuilder |
||||
|
|
||||
|
def checkSocksPort(port): |
||||
|
try: |
||||
|
r = requests.get('http://gstatic.com/generate_204', proxies = { |
||||
|
'http': 'socks5://127.0.0.1:' + str(port), |
||||
|
'https': 'socks5://127.0.0.1:' + str(port), |
||||
|
}) |
||||
|
if r.status_code == 204: |
||||
|
return True |
||||
|
except: pass |
||||
|
return False |
||||
|
|
||||
|
testInfo = { |
||||
|
'type': 'shadowsocks', |
||||
|
'server': '127.0.0.1', |
||||
|
'port': 12345, |
||||
|
'password': 'dnomd343', |
||||
|
'method': 'aes-256-ctr', |
||||
|
'plugin': '', |
||||
|
'pluginArg': '', |
||||
|
} |
||||
|
|
||||
|
print("start") |
||||
|
print(testInfo) |
||||
|
task = ProxyBuilder.build(testInfo, '/tmp/ProxyC') |
||||
|
print(task) |
||||
|
time.sleep(1) |
||||
|
if ProxyBuilder.check(task) == False: |
||||
|
print("error exit") |
||||
|
else: |
||||
|
print("test with gstatic") |
||||
|
if checkSocksPort(task['port']): |
||||
|
print("ok") |
||||
|
else: |
||||
|
print("error") |
||||
|
ProxyBuilder.destroy(task) |
||||
|
print("stop") |
||||
|
|
Loading…
Reference in new issue