Support IETF RETRY from client This CL parses the retry token, and updates our connection ID and crypters. Server-side support will come in a subsequent CL which will also add end to end tests. gfe-relnote: Support IETF Retry packets from client in v99, protected by disabled v99 flag PiperOrigin-RevId: 246911895 Change-Id: Icd5ecd22190fd18ad42882a66c3aa470640ce223
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc index 5c46910..602940c 100644 --- a/quic/core/chlo_extractor.cc +++ b/quic/core/chlo_extractor.cc
@@ -35,6 +35,9 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {}
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index ac5101e..23f386b 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -16,6 +16,7 @@ #include <utility> #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h" @@ -348,6 +349,7 @@ fix_termination_packets_( GetQuicReloadableFlag(quic_fix_termination_packets)), send_ack_when_on_can_write_(false), + retry_has_been_parsed_(false), validate_packet_number_post_decryption_( GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)), use_uber_received_packet_manager_( @@ -746,6 +748,39 @@ RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); } +// Handles retry for client connection. +void QuicConnection::OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) { + if (original_connection_id != connection_id_) { + QUIC_DLOG(ERROR) << "Ignoring RETRY with original connection ID " + << original_connection_id << " not matching expected " + << connection_id_ << " token " + << QuicTextUtils::HexEncode(retry_token); + return; + } + if (retry_has_been_parsed_) { + QUIC_DLOG(ERROR) << "Ignoring non-first RETRY with token " + << QuicTextUtils::HexEncode(retry_token); + return; + } + retry_has_been_parsed_ = true; + QUIC_DLOG(INFO) << "Received RETRY, replacing connection ID " + << connection_id_ << " with " << new_connection_id + << ", received token " + << QuicTextUtils::HexEncode(retry_token); + connection_id_ = new_connection_id; + packet_generator_.SetConnectionId(connection_id_); + packet_generator_.SetRetryToken(retry_token); + + // Reinstall initial crypters because the connection ID changed. + CrypterPair crypters; + CryptoUtils::CreateTlsInitialCrypters( + Perspective::IS_CLIENT, transport_version(), connection_id_, &crypters); + SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); + InstallDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); +} + bool QuicConnection::HasIncomingConnectionId(QuicConnectionId connection_id) { for (QuicConnectionId const& incoming_connection_id : incoming_connection_ids_) {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index b28ece5..ea12d71 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -481,6 +481,9 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override; bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override; @@ -1508,6 +1511,9 @@ // needs to be sent. bool send_ack_when_on_can_write_; + // Indicates whether a RETRY packet has been parsed. + bool retry_has_been_parsed_; + // Latched value of quic_validate_packet_number_post_decryption. const bool validate_packet_number_post_decryption_;
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index a254585..094fc7b 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -869,6 +869,12 @@ DCHECK(false); } +void QuicDispatcher::OnRetryPacket(QuicConnectionId /*original_connection_id*/, + QuicConnectionId /*new_connection_id*/, + QuicStringPiece /*retry_token*/) { + DCHECK(false); +} + void QuicDispatcher::OnDecryptedPacket(EncryptionLevel level) { DCHECK(false); } @@ -1066,7 +1072,7 @@ bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection( QuicConnectionId connection_id, bool ietf_quic) { - VLOG(1) << "Received packet from new connection " << connection_id; + QUIC_VLOG(1) << "Received packet from new connection " << connection_id; return true; }
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h index 4503fc0..c4fe223 100644 --- a/quic/core/quic_dispatcher.h +++ b/quic/core/quic_dispatcher.h
@@ -149,6 +149,9 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; void OnCoalescedPacket(const QuicEncryptedPacket& packet) override;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index 303dca2..55208e9 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -1510,6 +1510,8 @@ if (IsVersionNegotiation(header, packet_has_ietf_packet_header)) { QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet"; rv = ProcessVersionNegotiationPacket(&reader, header); + } else if (header.long_packet_type == RETRY) { + rv = ProcessRetryPacket(&reader, header); } else if (header.reset_flag) { rv = ProcessPublicResetPacket(&reader, header); } else if (packet.length() <= kMaxIncomingPacketSize) { @@ -1563,6 +1565,29 @@ return true; } +bool QuicFramer::ProcessRetryPacket(QuicDataReader* reader, + const QuicPacketHeader& header) { + DCHECK_EQ(Perspective::IS_CLIENT, perspective_); + + // Parse Original Destination Connection ID Length. + uint8_t odcil = header.type_byte & 0xf; + if (odcil != 0) { + odcil += kConnectionIdLengthAdjustment; + } + + // Parse Original Destination Connection ID. + QuicConnectionId original_destination_connection_id; + if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } + + QuicStringPiece retry_token = reader->ReadRemainingPayload(); + visitor_->OnRetryPacket(original_destination_connection_id, + header.source_connection_id, retry_token); + return true; +} + bool QuicFramer::MaybeProcessIetfInitialRetryToken( QuicDataReader* encrypted_reader, QuicPacketHeader* header) { @@ -2430,6 +2455,7 @@ set_detailed_error("Unable to read type."); return false; } + header->type_byte = type; // Determine whether this is a long or short header. header->form = type & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET : IETF_QUIC_SHORT_HEADER_PACKET; @@ -2469,14 +2495,19 @@ set_detailed_error("Illegal long header type value."); return false; } - if (header->long_packet_type == RETRY && - (version().KnowsWhichDecrypterToUse() || - supports_multiple_packet_number_spaces_)) { - set_detailed_error("Not yet supported IETF RETRY packet received."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); + if (header->long_packet_type == RETRY) { + if (!version().SupportsRetry()) { + set_detailed_error("RETRY not supported in this version."); + return false; + } + if (perspective_ == Perspective::IS_SERVER) { + set_detailed_error("Client-initiated RETRY is invalid."); + return false; + } + } else { + header->packet_number_length = GetLongHeaderPacketNumberLength( + header->version.transport_version, type); } - header->packet_number_length = GetLongHeaderPacketNumberLength( - header->version.transport_version, type); } } if (header->long_packet_type != VERSION_NEGOTIATION) {
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h index b20ac92..decb456 100644 --- a/quic/core/quic_framer.h +++ b/quic/core/quic_framer.h
@@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -92,6 +93,12 @@ virtual void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) = 0; + // Called only when |perspective_| is IS_CLIENT and a retry packet has been + // parsed. + virtual void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) = 0; + // Called when all fields except packet number has been parsed, but has not // been authenticated. If it returns false, framing for this packet will // cease. @@ -263,7 +270,7 @@ } // Pass a UDP packet into the framer for parsing. - // Return true if the packet was processed succesfully. |packet| must be a + // Return true if the packet was processed successfully. |packet| must be a // single, complete UDP packet (not a frame of a packet). This packet // might be null padded past the end of the payload, which will be correctly // ignored. @@ -602,6 +609,9 @@ bool ProcessVersionNegotiationPacket(QuicDataReader* reader, const QuicPacketHeader& header); + bool ProcessRetryPacket(QuicDataReader* reader, + const QuicPacketHeader& header); + bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader, QuicPacketHeader* header);
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index 5edb288..56665df 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -198,6 +198,16 @@ QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override { + retry_original_connection_id_ = + QuicMakeUnique<QuicConnectionId>(original_connection_id); + retry_new_connection_id_ = + QuicMakeUnique<QuicConnectionId>(new_connection_id); + retry_token_ = QuicMakeUnique<std::string>(std::string(retry_token)); + } + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, PacketHeaderFormat /*form*/) override { QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " @@ -394,6 +404,9 @@ std::unique_ptr<QuicPublicResetPacket> public_reset_packet_; std::unique_ptr<QuicIetfStatelessResetPacket> stateless_reset_packet_; std::unique_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; + std::unique_ptr<QuicConnectionId> retry_original_connection_id_; + std::unique_ptr<QuicConnectionId> retry_new_connection_id_; + std::unique_ptr<std::string> retry_token_; std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; std::vector<std::unique_ptr<QuicAckFrame>> ack_frames_; @@ -5479,6 +5492,78 @@ CheckFramingBoundaries(packet, QUIC_INVALID_VERSION_NEGOTIATION_PACKET); } +TEST_P(QuicFramerTest, ParseIetfRetryPacket) { + if (!framer_.version().SupportsRetry()) { + return; + } + // IETF RETRY is only sent from client to server. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type RETRY and ODCIL=8) + 0xF5, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x05, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_TRUE(visitor_.retry_original_connection_id_.get()); + ASSERT_TRUE(visitor_.retry_new_connection_id_.get()); + ASSERT_TRUE(visitor_.retry_token_.get()); + + EXPECT_EQ(FramerTestConnectionId(), + *visitor_.retry_original_connection_id_.get()); + EXPECT_EQ(FramerTestConnectionIdPlusOne(), + *visitor_.retry_new_connection_id_.get()); + EXPECT_EQ("Hello this is RETRY!", *visitor_.retry_token_.get()); +} + +TEST_P(QuicFramerTest, RejectIetfRetryPacketAsServer) { + if (!framer_.version().SupportsRetry()) { + return; + } + // IETF RETRY is only sent from client to server. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + // clang-format off + unsigned char packet[] = { + // public flags (long header with packet type RETRY and ODCIL=8) + 0xF5, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x05, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error()); + EXPECT_EQ("Client-initiated RETRY is invalid.", framer_.detailed_error()); +} + TEST_P(QuicFramerTest, BuildPaddingFramePacket) { QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); @@ -13085,7 +13170,8 @@ } TEST_P(QuicFramerTest, IetfRetryPacketRejected) { - if (!framer_.version().KnowsWhichDecrypterToUse()) { + if (!framer_.version().KnowsWhichDecrypterToUse() || + framer_.version().SupportsRetry()) { return; } @@ -13112,7 +13198,7 @@ {"Unable to read protocol version.", {QUIC_VERSION_BYTES}}, // connection_id length - {"Not yet supported IETF RETRY packet received.", + {"RETRY not supported in this version.", {0x00}}, }; // clang-format on @@ -13128,7 +13214,8 @@ } TEST_P(QuicFramerTest, RetryPacketRejectedWithMultiplePacketNumberSpaces) { - if (framer_.transport_version() < QUIC_VERSION_46) { + if (framer_.transport_version() < QUIC_VERSION_46 || + framer_.version().SupportsRetry()) { return; } framer_.EnableMultiplePacketNumberSpacesSupport(); @@ -13142,7 +13229,7 @@ {"Unable to read protocol version.", {QUIC_VERSION_BYTES}}, // connection_id length - {"Not yet supported IETF RETRY packet received.", + {"RETRY not supported in this version.", {0x00}}, }; // clang-format on
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc index fa3aca4..f30fc99 100644 --- a/quic/core/quic_ietf_framer_test.cc +++ b/quic/core/quic_ietf_framer_test.cc
@@ -96,6 +96,10 @@ void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} + bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, PacketHeaderFormat form) override { return true;
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index 99e8cc3..7ec8739 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -255,7 +255,7 @@ // Sets transmission type of next constructed packets. void SetTransmissionType(TransmissionType type); - // Sets the retry token to be sent over the wire in v99 IETF Initial packets. + // Sets the retry token to be sent over the wire in IETF Initial packets. void SetRetryToken(QuicStringPiece retry_token); // Returns the largest payload that will fit into a single MESSAGE frame.
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index 7e98274..b90880e 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -485,6 +485,10 @@ } } +void QuicPacketGenerator::SetRetryToken(QuicStringPiece retry_token) { + packet_creator_.SetRetryToken(retry_token); +} + void QuicPacketGenerator::SetCanSetTransmissionType( bool can_set_transmission_type) { packet_creator_.set_can_set_transmission_type(can_set_transmission_type);
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h index 047295d..417fda6 100644 --- a/quic/core/quic_packet_generator.h +++ b/quic/core/quic_packet_generator.h
@@ -217,6 +217,9 @@ // Set transmission type of next constructed packets. void SetTransmissionType(TransmissionType type); + // Sets the retry token to be sent over the wire in IETF Initial packets. + void SetRetryToken(QuicStringPiece retry_token); + // Allow/Disallow setting transmission type of next constructed packets. void SetCanSetTransmissionType(bool can_set_transmission_type);
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h index e745e07..3ced31f 100644 --- a/quic/core/quic_packets.h +++ b/quic/core/quic_packets.h
@@ -102,6 +102,7 @@ // parsed from the packet buffer. IETF QUIC only, always false for GQUIC. bool has_possible_stateless_reset_token; QuicPacketNumberLength packet_number_length; + uint8_t type_byte; ParsedQuicVersion version; // nonce contains an optional, 32-byte nonce value. If not included in the // packet, |nonce| will be empty.
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 3fb817b..99f90fe 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -60,6 +60,10 @@ return false; } +bool ParsedQuicVersion::SupportsRetry() const { + return transport_version == QUIC_VERSION_99; +} + std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { os << ParsedQuicVersionToString(version); return os;
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 00bbb32..7264810 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -154,6 +154,9 @@ // Returns whether header protection is used in this version of QUIC. bool HasHeaderProtection() const; + + // Returns whether this version supports IETF RETRY packets. + bool SupportsRetry() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion();
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 0f1ccc3..643291e 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -250,6 +250,10 @@ MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket& packet)); + MOCK_METHOD3(OnRetryPacket, + void(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token)); // The constructor sets this up to return true by default. MOCK_METHOD1(OnUnauthenticatedHeader, bool(const QuicPacketHeader& header)); // The constructor sets this up to return true by default. @@ -302,6 +306,9 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} bool OnProtocolVersionMismatch(ParsedQuicVersion version, PacketHeaderFormat form) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; @@ -1011,6 +1018,9 @@ MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket&)); + + MOCK_METHOD3(OnRetryPacket, + void(QuicConnectionId, QuicConnectionId, QuicStringPiece)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager {
diff --git a/quic/test_tools/simple_quic_framer.cc b/quic/test_tools/simple_quic_framer.cc index 028e2cd..06a6718 100644 --- a/quic/test_tools/simple_quic_framer.cc +++ b/quic/test_tools/simple_quic_framer.cc
@@ -39,6 +39,10 @@ QuicMakeUnique<QuicVersionNegotiationPacket>((packet)); } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override {} + bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { return true; }
diff --git a/quic/tools/quic_packet_printer_bin.cc b/quic/tools/quic_packet_printer_bin.cc index 207b357..80ffd4e 100644 --- a/quic/tools/quic_packet_printer_bin.cc +++ b/quic/tools/quic_packet_printer_bin.cc
@@ -63,6 +63,11 @@ const QuicVersionNegotiationPacket& packet) override { std::cerr << "OnVersionNegotiationPacket\n"; } + void OnRetryPacket(QuicConnectionId original_connection_id, + QuicConnectionId new_connection_id, + QuicStringPiece retry_token) override { + std::cerr << "OnRetryPacket\n"; + } bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { std::cerr << "OnUnauthenticatedPublicHeader\n"; return true;