fix: SOCKS5 隧道连接超时
修复子线程事件循环中 asyncio.wait_for 包装 open_connection 导致的读取取消问题。 改用 socket 层面的 timeout 设置,不再用 wait_for 包装。 同时修复 _reply 中 writer.write 不需要 await 的问题。
This commit is contained in:
+13
-10
@@ -4,6 +4,7 @@ import logging
|
||||
import struct
|
||||
import time
|
||||
import uuid
|
||||
import socket as _socket
|
||||
import ipaddress
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -127,11 +128,11 @@ class ConnectionHandler:
|
||||
methods = header[2:2 + n_methods]
|
||||
# 检查是否支持
|
||||
if METHOD_USERPASS in methods and self.config.auth_method == "userpass":
|
||||
await self.writer.write(bytes([SOCKS_VERSION, METHOD_USERPASS]))
|
||||
self.writer.write(bytes([SOCKS_VERSION, METHOD_USERPASS]))
|
||||
elif METHOD_NO_AUTH in methods:
|
||||
await self.writer.write(bytes([SOCKS_VERSION, METHOD_NO_AUTH]))
|
||||
self.writer.write(bytes([SOCKS_VERSION, METHOD_NO_AUTH]))
|
||||
else:
|
||||
await self.writer.write(bytes([SOCKS_VERSION, METHOD_NOT_ACCEPTED]))
|
||||
self.writer.write(bytes([SOCKS_VERSION, METHOD_NOT_ACCEPTED]))
|
||||
return False
|
||||
await self.writer.drain()
|
||||
return True
|
||||
@@ -177,14 +178,14 @@ class ConnectionHandler:
|
||||
log.warning("认证失败: %s (user=%s)", self.src_ip, username)
|
||||
await self.user_service.log_event("auth_fail", username,
|
||||
self.src_ip, "密码错误或账号不可用")
|
||||
await self.writer.write(bytes([1, 0x01])) # auth fail
|
||||
self.writer.write(bytes([1, 0x01])) # auth fail
|
||||
await self.writer.drain()
|
||||
return False
|
||||
|
||||
self.username = username
|
||||
log.info("[%s] 认证成功: %s (from %s)", self.conn_id, username, self.src_ip)
|
||||
await self.user_service.log_event("auth_success", username, self.src_ip)
|
||||
await self.writer.write(bytes([1, 0x00])) # auth ok
|
||||
self.writer.write(bytes([1, 0x00])) # auth ok
|
||||
await self.writer.drain()
|
||||
return True
|
||||
|
||||
@@ -273,11 +274,13 @@ class ConnectionHandler:
|
||||
|
||||
# 连接目标
|
||||
try:
|
||||
reader, writer = await asyncio.wait_for(
|
||||
asyncio.open_connection(addr, port),
|
||||
timeout=self.config.timeout
|
||||
)
|
||||
except (asyncio.TimeoutError, OSError) as e:
|
||||
# 注意:不用 asyncio.wait_for 包装 open_connection,
|
||||
# 在子线程事件循环中 wait_for 会导致连接成功后读取被取消
|
||||
sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
|
||||
sock.settimeout(self.config.timeout)
|
||||
sock.connect((addr, port))
|
||||
reader, writer = await asyncio.open_connection(sock=sock)
|
||||
except (OSError, Exception) as e:
|
||||
log.warning("[%s] 无法连接 %s:%d: %s", self.conn_id, addr, port, e)
|
||||
rep = REP_CONN_REFUSED if "refused" in str(e).lower() else REP_HOST_UNREACHABLE
|
||||
await self._reply(rep)
|
||||
|
||||
Reference in New Issue
Block a user