feat: SOCKS5 代理管理系统 v1.0

Flask + SQLite + Bootstrap5 暗色主题
- 仪表盘: 在线/离线统计 + 最近代理 + 操作日志
- 代理 CRUD: 增删改 + 启用/禁用 + 单/批量健康检测(SOCKS5)
- 分组管理: 创建/删除/筛选
- 操作日志: 分页查询
- RESTful API + Web 界面
- 管理员登录认证 (SM_ADMIN_PASSWORD 环境变量)
This commit is contained in:
Your Name
2026-07-16 16:40:20 +08:00
commit aa8af6c2e0
20 changed files with 950 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import time
import logging
from datetime import datetime, timezone
from models import Proxy, db
from extensions import db as _db_ext
log = logging.getLogger("socks.health")
TEST_URL = "http://httpbin.org/get"
def check_proxy(proxy):
"""检查单个 SOCKS5 代理是否可用。返回 {status, latency_ms, error}"""
import socks
import socket
host, port = proxy.host, proxy.port
timeout = 10
status = "unknown"
latency = None
error = None
orig_getaddrinfo = socket.getaddrinfo
orig_socket = socket.socket
try:
# 使用 PySocks 创建 SOCKS5 隧道
s = socks.socksocket()
s.settimeout(timeout)
s.set_proxy(socks.SOCKS5, host, port,
username=proxy.username or None,
password=proxy.password or None)
t0 = time.time()
# 尝试连接到测试 URLhttpbin.org
s.connect(("httpbin.org", 80))
elapsed = time.time() - t0
latency = round(elapsed * 1000, 1)
# 发送一个简单 HTTP HEAD 请求验证隧道通畅
s.sendall(b"HEAD /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n")
resp = s.recv(1024)
s.close()
if resp and (b"200" in resp[:4] or b"301" in resp[:4] or b"302" in resp[:4]):
status = "online"
else:
status = "online" # 连接成功即算在线(某些代理只允许特定目标)
except Exception as e:
status = "offline"
error = str(e)[:200]
log.warning("Proxy %s:%d check failed: %s", host, port, e)
finally:
socket.getaddrinfo = orig_getaddrinfo
socket.socket = orig_socket
return {"status": status, "latency_ms": latency, "error": error}
def run_health_checks():
"""对所有 enabled 的代理运行健康检测,更新数据库,返回结果摘要。"""
proxies = Proxy.query.filter_by(enabled=True).all()
results = []
online_count = 0
for p in proxies:
r = check_proxy(p)
p.status = r["status"]
p.latency_ms = r["latency_ms"]
p.last_check = datetime.now(timezone.utc)
if r["status"] == "online":
online_count += 1
results.append({
"id": p.id, "name": p.name, "host": p.host, "port": p.port,
**r,
})
_db_ext.session.commit()
return {
"checked": len(results),
"online": online_count,
"offline": len(results) - online_count,
"details": results,
}