diff --git a/proxy/main.py b/proxy/main.py index bfddb43..25bd3e4 100644 --- a/proxy/main.py +++ b/proxy/main.py @@ -228,9 +228,16 @@ async def handle_client( ) hs = parse_handshake(hs_bytes) except (HandshakeError, asyncio.TimeoutError, asyncio.IncompleteReadError, OSError) as exc: - log_event(client_ip, None, None, "blocked", f"handshake error: {exc}") - log.info("BLOCK %s reason=handshake_error (%s)", client_ip, exc) - client_writer.close() + # str(exc) 가 빈 문자열인 예외들(OSError(), ConnectionResetError()) + # 도 있어서 class 이름을 함께 남긴다 — 빈 reason 로 보이는 문제 회피. + 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 domain = hs.server_address.lower().strip() @@ -247,9 +254,20 @@ async def handle_client( msg = state.cfg.get("block_message") or DEFAULT_BLOCK_MESSAGE client_writer.write(build_login_disconnect(msg)) 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): pass - client_writer.close() + try: + client_writer.close() + await client_writer.wait_closed() + except Exception: # noqa: BLE001 + pass return backend_host, backend_port = target