Send an ICMP6_PACKET_TOO_BIG when we try to send a message that is too big.
This change also:
1) Completely disables fallback to streams when we've negotiated messages.
2) Drops the default MTU on the bonnet to 1280.
gfe-relnote: gfe-relnote: n/a (QBONE-only change)
PiperOrigin-RevId: 278862096
Change-Id: I0ff1fae69c7f0a82d3afcd5f13f7c2626f2e583b
diff --git a/quic/qbone/qbone_session_base.cc b/quic/qbone/qbone_session_base.cc
index 62bcaa4..9c8479c 100644
--- a/quic/qbone/qbone_session_base.cc
+++ b/quic/qbone/qbone_session_base.cc
@@ -4,11 +4,15 @@
#include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
+#include <netinet/icmp6.h>
+#include <netinet/ip6.h>
+
#include <utility>
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
namespace quic {
@@ -137,12 +141,41 @@
QuicMemSlice slice(connection()->helper()->GetStreamSendBufferAllocator(),
packet.size());
memcpy(const_cast<char*>(slice.data()), packet.data(), packet.size());
- if (SendMessage(QuicMemSliceSpan(&slice)).status ==
- MESSAGE_STATUS_SUCCESS) {
- return;
+ switch (SendMessage(QuicMemSliceSpan(&slice)).status) {
+ case MESSAGE_STATUS_SUCCESS:
+ break;
+ case MESSAGE_STATUS_TOO_LARGE: {
+ if (packet.size() < sizeof(ip6_hdr)) {
+ QUIC_BUG << "Dropped malformed packet: IPv6 header too short";
+ break;
+ }
+ auto* header = reinterpret_cast<const ip6_hdr*>(packet.begin());
+ icmp6_hdr icmp_header{};
+ icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG;
+ icmp_header.icmp6_mtu =
+ connection()->GetGuaranteedLargestMessagePayload();
+
+ CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet,
+ [this](QuicStringPiece icmp_packet) {
+ writer_->WritePacketToNetwork(icmp_packet.data(),
+ icmp_packet.size());
+ });
+ break;
+ }
+ case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
+ QUIC_BUG << "MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED";
+ break;
+ case MESSAGE_STATUS_UNSUPPORTED:
+ QUIC_BUG << "MESSAGE_STATUS_UNSUPPORTED";
+ break;
+ case MESSAGE_STATUS_BLOCKED:
+ QUIC_BUG << "MESSAGE_STATUS_BLOCKED";
+ break;
+ case MESSAGE_STATUS_INTERNAL_ERROR:
+ QUIC_BUG << "MESSAGE_STATUS_INTERNAL_ERROR";
+ break;
}
- // If SendMessage() fails for any reason, fall back to ephemeral streams.
- num_fallback_to_stream_++;
+ return;
}
// Qbone streams are ephemeral.
diff --git a/quic/qbone/qbone_session_test.cc b/quic/qbone/qbone_session_test.cc
index 8a12cec..19ecd2c 100644
--- a/quic/qbone/qbone_session_test.cc
+++ b/quic/qbone/qbone_session_test.cc
@@ -12,6 +12,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
#include "net/third_party/quiche/src/quic/qbone/qbone_client_session.h"
#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
#include "net/third_party/quiche/src/quic/qbone/qbone_control_placeholder.pb.h"
@@ -353,6 +354,23 @@
runner_.Run();
}
+ void ExpectICMPTooBigResponse(const std::vector<string>& written_packets,
+ const int mtu,
+ const string& packet) {
+ auto* header = reinterpret_cast<const ip6_hdr*>(packet.data());
+ icmp6_hdr icmp_header{};
+ icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG;
+ icmp_header.icmp6_mtu = mtu;
+
+ string expected;
+ CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet,
+ [&expected](QuicStringPiece icmp_packet) {
+ expected = string(icmp_packet);
+ });
+
+ EXPECT_THAT(written_packets, Contains(expected));
+ }
+
// Test handshake establishment and sending/receiving of data for two
// directions.
void TestStreamConnection(bool use_messages) {
@@ -395,7 +413,14 @@
QUIC_LOG(INFO) << "Sending server -> client long data";
server_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data));
runner_.Run();
- EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data)));
+ if (use_messages) {
+ ExpectICMPTooBigResponse(
+ server_writer_->data(),
+ server_peer_->connection()->GetGuaranteedLargestMessagePayload(),
+ TestPacketOut(long_data));
+ } else {
+ EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data)));
+ }
EXPECT_THAT(server_writer_->data(),
Not(Contains(TestPacketOut(long_data))));
EXPECT_EQ(0u, server_peer_->GetNumActiveStreams());
@@ -404,11 +429,22 @@
QUIC_LOG(INFO) << "Sending client -> server long data";
client_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data));
runner_.Run();
- EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data)));
+ if (use_messages) {
+ ExpectICMPTooBigResponse(
+ client_writer_->data(),
+ client_peer_->connection()->GetGuaranteedLargestMessagePayload(),
+ TestPacketIn(long_data));
+ } else {
+ EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data)));
+ }
EXPECT_THAT(client_peer_->GetNumSentClientHellos(), Eq(2));
EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0));
- EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1));
- EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1));
+
+ if (!use_messages) {
+ EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1));
+ EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1));
+ }
+
if (use_messages) {
EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(0));
EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(0));