From: Michał Kępień Date: Tue, 18 Mar 2025 15:28:18 +0000 (+0100) Subject: Enable receiving chunked TCP DNS messages X-Git-Tag: v9.21.7~45^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=68fe9a5df5c5298413449771c062f85e4b1b9ef3;p=thirdparty%2Fbind9.git Enable receiving chunked TCP DNS messages A TCP DNS client may send its queries in chunks, causing StreamReader.read() to return less data than previously declared by the client as the DNS message length; even the two-octet DNS message length itself may be split up into two single-octet transmissions. Sending data in chunks is valid client behavior that should not be treated as an error. Add a new helper method for reading TCP data in a loop, properly distinguishing between chunked queries and client disconnections. Use the new method for reading all TCP data from clients. --- diff --git a/bin/tests/system/isctest/asyncserver.py b/bin/tests/system/isctest/asyncserver.py index 902f436ccc4..0d8996e8e2c 100644 --- a/bin/tests/system/isctest/asyncserver.py +++ b/bin/tests/system/isctest/asyncserver.py @@ -570,8 +570,8 @@ class AsyncDnsServer(AsyncServer): ) -> Optional[int]: logging.debug("Receiving TCP message length from %s...", peer) - wire_length_bytes = await reader.read(2) - if len(wire_length_bytes) < 2: + wire_length_bytes = await self._read_tcp_octets(reader, peer, 2) + if not wire_length_bytes: return None (wire_length,) = struct.unpack("!H", wire_length_bytes) @@ -583,14 +583,38 @@ class AsyncDnsServer(AsyncServer): ) -> Optional[bytes]: logging.debug("Receiving TCP message (%d octets) from %s...", wire_length, peer) - wire = await reader.read(wire_length) - if len(wire) < wire_length: + wire = await self._read_tcp_octets(reader, peer, wire_length) + if not wire: return None logging.debug("Received complete TCP message from %s: %s", peer, wire.hex()) return wire + async def _read_tcp_octets( + self, reader: asyncio.StreamReader, peer: Peer, expected: int + ) -> Optional[bytes]: + buffer = b"" + + while len(buffer) < expected: + chunk = await reader.read(expected - len(buffer)) + if not chunk: + if buffer: + logging.debug( + "Received short TCP message (%d octets) from %s: %s", + len(buffer), + peer, + buffer.hex(), + ) + else: + logging.debug("Received disconnect from %s", peer) + return None + + logging.debug("Received %d TCP octets from %s", len(chunk), peer) + buffer += chunk + + return buffer + async def _send_tcp_response( self, writer: asyncio.StreamWriter, peer: Peer, wire: bytes ) -> None: