From 11c2e590290c3f5283f78b5f02ba83bc45882984 Mon Sep 17 00:00:00 2001 From: Sanket Meghale Date: Sat, 9 May 2026 07:27:54 +0530 Subject: [PATCH 1/2] Handle malformed identify varint prefixes --- libp2p/identity/identify/identify.py | 29 ++++++++++++------- tests/core/identity/identify/test_identify.py | 25 ++++++++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/libp2p/identity/identify/identify.py b/libp2p/identity/identify/identify.py index d7137702f..e4d5eb012 100644 --- a/libp2p/identity/identify/identify.py +++ b/libp2p/identity/identify/identify.py @@ -12,6 +12,9 @@ StreamHandlerFn, TProtocol, ) +from libp2p.exceptions import ( + ParseError, +) from libp2p.network.stream.exceptions import ( StreamClosed, ) @@ -87,17 +90,21 @@ def parse_identify_response(response: bytes) -> Identify: """ # Try new format first: length-prefixed protobuf if len(response) >= 1: - length, varint_size = decode_varint_with_size(response) - if varint_size > 0 and length > 0 and varint_size + length <= len(response): - protobuf_data = response[varint_size : varint_size + length] - try: - identify_response = Identify() - identify_response.ParseFromString(protobuf_data) - # Sanity check: must have agent_version (protocol_version is optional) - if identify_response.agent_version: - return identify_response - except Exception: - pass # Fall through to old format + try: + length, varint_size = decode_varint_with_size(response) + except ParseError: + pass # Fall through to old format + else: + if varint_size > 0 and length > 0 and varint_size + length <= len(response): + protobuf_data = response[varint_size : varint_size + length] + try: + identify_response = Identify() + identify_response.ParseFromString(protobuf_data) + # Sanity check: must have agent_version. + if identify_response.agent_version: + return identify_response + except Exception: + pass # Fall through to old format # Fall back to old format: raw protobuf try: diff --git a/tests/core/identity/identify/test_identify.py b/tests/core/identity/identify/test_identify.py index ae7b4ab18..356faa5b0 100644 --- a/tests/core/identity/identify/test_identify.py +++ b/tests/core/identity/identify/test_identify.py @@ -5,6 +5,10 @@ Multiaddr, ) +from libp2p.exceptions import ( + ParseError, +) +from libp2p.identity.identify import identify as identify_module from libp2p.identity.identify.identify import ( AGENT_VERSION, ID, @@ -22,6 +26,27 @@ logger = logging.getLogger("libp2p.identity.identify-test") +def test_parse_identify_response_falls_back_after_prefix_parse_error(monkeypatch): + raw_response = identify_module.Identify( + agent_version=AGENT_VERSION, + protocol_version=PROTOCOL_VERSION, + ).SerializeToString() + + def raise_parse_error(data: bytes) -> tuple[int, int]: + raise ParseError("Unexpected end of data while decoding varint") + + monkeypatch.setattr( + identify_module, + "decode_varint_with_size", + raise_parse_error, + ) + + identify_response = parse_identify_response(raw_response) + + assert identify_response.agent_version == AGENT_VERSION + assert identify_response.protocol_version == PROTOCOL_VERSION + + @pytest.mark.trio async def test_identify_protocol(security_protocol): async with host_pair_factory(security_protocol=security_protocol) as ( From 4fa9b0d55eaaba32a591d4eb119a8bf8739ec1d1 Mon Sep 17 00:00:00 2001 From: Sanket Meghale Date: Sat, 9 May 2026 07:29:25 +0530 Subject: [PATCH 2/2] Add identify parser newsfragment --- newsfragments/1328.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/1328.bugfix.rst diff --git a/newsfragments/1328.bugfix.rst b/newsfragments/1328.bugfix.rst new file mode 100644 index 000000000..fc9eeae4c --- /dev/null +++ b/newsfragments/1328.bugfix.rst @@ -0,0 +1 @@ +Allowed identify response parsing to fall back to raw protobuf messages when the length-prefix probe raises ``ParseError``.