fix(proxy): flush disconnect packet cleanly + label handshake errors
Two related diagnostics from production: 1) "Connection reset" instead of the custom block_message screen. Root cause: writer.close() returned before the kernel flushed the Login Disconnect packet, and the OS sent RST instead of FIN. Fix: write_eof() + await wait_closed() so the FIN goes out after the payload and the client has time to read the chat component. 2) Log entries showing reason "handshake error:" with an empty tail. Root cause: bare OSError() / ConnectionResetError() have empty str(), so the f-string interpolated to nothing. Fix: prepend the exception class name so the reason is always informative.
This commit is contained in:
@@ -228,9 +228,16 @@ async def handle_client(
|
|||||||
)
|
)
|
||||||
hs = parse_handshake(hs_bytes)
|
hs = parse_handshake(hs_bytes)
|
||||||
except (HandshakeError, asyncio.TimeoutError, asyncio.IncompleteReadError, OSError) as exc:
|
except (HandshakeError, asyncio.TimeoutError, asyncio.IncompleteReadError, OSError) as exc:
|
||||||
log_event(client_ip, None, None, "blocked", f"handshake error: {exc}")
|
# str(exc) 가 빈 문자열인 예외들(OSError(), ConnectionResetError())
|
||||||
log.info("BLOCK %s reason=handshake_error (%s)", client_ip, exc)
|
# 도 있어서 class 이름을 함께 남긴다 — 빈 reason 로 보이는 문제 회피.
|
||||||
client_writer.close()
|
reason = f"handshake error: {type(exc).__name__}: {exc}".rstrip(": ")
|
||||||
|
log_event(client_ip, None, None, "blocked", reason)
|
||||||
|
log.info("BLOCK %s reason=%s", client_ip, reason)
|
||||||
|
try:
|
||||||
|
client_writer.close()
|
||||||
|
await client_writer.wait_closed()
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
domain = hs.server_address.lower().strip()
|
domain = hs.server_address.lower().strip()
|
||||||
@@ -247,9 +254,20 @@ async def handle_client(
|
|||||||
msg = state.cfg.get("block_message") or DEFAULT_BLOCK_MESSAGE
|
msg = state.cfg.get("block_message") or DEFAULT_BLOCK_MESSAGE
|
||||||
client_writer.write(build_login_disconnect(msg))
|
client_writer.write(build_login_disconnect(msg))
|
||||||
await client_writer.drain()
|
await client_writer.drain()
|
||||||
|
# FIN 으로 마무리해서 클라이언트가 disconnect 패킷을 다 읽기 전에
|
||||||
|
# RST 가 가는 (그러면 "Connection reset" 으로 보인다) 일을 막는다.
|
||||||
|
try:
|
||||||
|
if client_writer.can_write_eof():
|
||||||
|
client_writer.write_eof()
|
||||||
|
except (OSError, NotImplementedError):
|
||||||
|
pass
|
||||||
except (OSError, ConnectionResetError, BrokenPipeError):
|
except (OSError, ConnectionResetError, BrokenPipeError):
|
||||||
pass
|
pass
|
||||||
client_writer.close()
|
try:
|
||||||
|
client_writer.close()
|
||||||
|
await client_writer.wait_closed()
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
backend_host, backend_port = target
|
backend_host, backend_port = target
|
||||||
|
|||||||
Reference in New Issue
Block a user