Extend LoadBalancerEncoder to support ConnectionIdGeneratorInterface.
PiperOrigin-RevId: 472464687
diff --git a/quiche/quic/load_balancer/load_balancer_encoder.cc b/quiche/quic/load_balancer/load_balancer_encoder.cc
index bb9608b..6cc8e0e 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder.cc
+++ b/quiche/quic/load_balancer/load_balancer_encoder.cc
@@ -167,6 +167,23 @@
return id;
}
+absl::optional<QuicConnectionId> LoadBalancerEncoder::GenerateNextConnectionId(
+ [[maybe_unused]] const QuicConnectionId &original) {
+ // Do not allow new connection IDs if linkable.
+ return (IsEncoding() && !IsEncrypted()) ? absl::optional<QuicConnectionId>()
+ : GenerateConnectionId();
+}
+
+absl::optional<QuicConnectionId> LoadBalancerEncoder::MaybeReplaceConnectionId(
+ const QuicConnectionId &original, const ParsedQuicVersion &version) {
+ // Pre-IETF versions of QUIC can respond poorly to new connection IDs issued
+ // during the handshake.
+ return (!version.HasIetfQuicFrames() &&
+ original.length() == CurrentConnectionIdLength())
+ ? absl::optional<QuicConnectionId>()
+ : GenerateConnectionId();
+}
+
QuicConnectionId LoadBalancerEncoder::MakeUnroutableConnectionId(
uint8_t first_byte) {
QuicConnectionId id;
diff --git a/quiche/quic/load_balancer/load_balancer_encoder.h b/quiche/quic/load_balancer/load_balancer_encoder.h
index b48bb19..589c347 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder.h
+++ b/quiche/quic/load_balancer/load_balancer_encoder.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_ENCODER_H_
#define QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_ENCODER_H_
+#include "quiche/quic/core/connection_id_generator.h"
#include "quiche/quic/core/crypto/quic_random.h"
#include "quiche/quic/load_balancer/load_balancer_config.h"
#include "quiche/quic/load_balancer/load_balancer_server_id.h"
@@ -50,7 +51,8 @@
// Manages QUIC-LB configurations to properly encode a given server ID in a
// QUIC Connection ID.
-class QUIC_EXPORT_PRIVATE LoadBalancerEncoder {
+class QUIC_EXPORT_PRIVATE LoadBalancerEncoder
+ : public ConnectionIdGeneratorInterface {
public:
// Returns a newly created encoder with no active config, if
// |unroutable_connection_id_length| is valid. |visitor| specifies an optional
@@ -94,6 +96,13 @@
// length Connection ID.
QuicConnectionId GenerateConnectionId();
+ // Functions from ConnectionIdGeneratorInterface
+ absl::optional<QuicConnectionId> GenerateNextConnectionId(
+ const QuicConnectionId& original) override;
+ absl::optional<QuicConnectionId> MaybeReplaceConnectionId(
+ const QuicConnectionId& original,
+ const ParsedQuicVersion& version) override;
+
private:
friend class test::LoadBalancerEncoderPeer;
@@ -108,6 +117,10 @@
QuicConnectionId MakeUnroutableConnectionId(uint8_t first_byte);
+ uint8_t CurrentConnectionIdLength() const {
+ return IsEncoding() ? config_->total_len() : unroutable_connection_id_len_;
+ }
+
QuicRandom& random_;
const bool len_self_encoded_;
LoadBalancerEncoderVisitorInterface* const visitor_;
diff --git a/quiche/quic/load_balancer/load_balancer_encoder_test.cc b/quiche/quic/load_balancer/load_balancer_encoder_test.cc
index f1df860..a331713 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder_test.cc
+++ b/quiche/quic/load_balancer/load_balancer_encoder_test.cc
@@ -130,10 +130,10 @@
TEST_F(LoadBalancerEncoderTest, BadServerIdLength) {
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
// Expects a 3 byte server ID and got 4.
auto config = LoadBalancerConfig::CreateUnencrypted(1, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
EXPECT_QUIC_BUG(
EXPECT_FALSE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 4))),
"Server ID length 4 does not match configured value of 3");
@@ -143,10 +143,9 @@
TEST_F(LoadBalancerEncoderTest, FailToUpdateConfigWithSameId) {
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true);
- EXPECT_TRUE(encoder.has_value());
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
auto config = LoadBalancerConfig::CreateUnencrypted(1, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
EXPECT_EQ(visitor.num_adds(), 1u);
EXPECT_QUIC_BUG(
@@ -199,10 +198,10 @@
};
random_.AddNextValues(0, 0x75c2699c);
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true, 8);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
auto config = LoadBalancerConfig::Create(config_id, server_id_len, nonce_len,
absl::string_view(raw_key));
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
EXPECT_TRUE(encoder->UpdateConfig(
*config, *LoadBalancerServerId::Create(raw_server_id)));
EXPECT_TRUE(encoder->IsEncoding());
@@ -248,7 +247,7 @@
};
for (const auto &test : test_vectors) {
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true, 8);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
random_.AddNextValues(kNonceHigh, kNonceLow);
EXPECT_TRUE(encoder->UpdateConfig(test.config, test.server_id));
EXPECT_EQ(encoder->GenerateConnectionId(), test.connection_id);
@@ -259,9 +258,9 @@
const uint8_t server_id_len = 3;
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true, 8);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
auto config = LoadBalancerConfig::Create(0, server_id_len, 4, kKey);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
EXPECT_TRUE(
encoder->UpdateConfig(*config, MakeServerId(kServerId, server_id_len)));
EXPECT_EQ(visitor.num_adds(), 1u);
@@ -279,7 +278,7 @@
TEST_F(LoadBalancerEncoderTest, UnroutableConnectionId) {
random_.AddNextValues(0x83, kNonceHigh);
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, false);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
EXPECT_EQ(encoder->num_nonces_left(), 0);
auto connection_id = encoder->GenerateConnectionId();
// The first byte is the config_id (0xc0) xored with (0x83 & 0x3f).
@@ -290,7 +289,7 @@
TEST_F(LoadBalancerEncoderTest, NonDefaultUnroutableConnectionIdLength) {
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true, 9);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
QuicConnectionId connection_id = encoder->GenerateConnectionId();
EXPECT_EQ(connection_id.length(), 9);
}
@@ -298,14 +297,14 @@
TEST_F(LoadBalancerEncoderTest, DeleteConfigWhenNoConfigExists) {
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true);
- EXPECT_TRUE(encoder.has_value());
+ ASSERT_TRUE(encoder.has_value());
encoder->DeleteConfig();
EXPECT_EQ(visitor.num_deletes(), 0u);
}
TEST_F(LoadBalancerEncoderTest, AddConfig) {
auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true);
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
@@ -321,12 +320,12 @@
TEST_F(LoadBalancerEncoderTest, UpdateConfig) {
auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true);
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
config = LoadBalancerConfig::Create(1, 4, 4, kKey);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 4)));
EXPECT_EQ(visitor.num_adds(), 2u);
EXPECT_EQ(visitor.num_deletes(), 1u);
@@ -336,7 +335,7 @@
TEST_F(LoadBalancerEncoderTest, DeleteConfig) {
auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true);
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
@@ -350,7 +349,7 @@
TEST_F(LoadBalancerEncoderTest, DeleteConfigNoVisitor) {
auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
- EXPECT_TRUE(config.has_value());
+ ASSERT_TRUE(config.has_value());
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true);
EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
encoder->DeleteConfig();
@@ -359,6 +358,45 @@
EXPECT_EQ(encoder->num_nonces_left(), 0);
}
+TEST_F(LoadBalancerEncoderTest, MaybeReplaceConnectionIdReturnsNoChange) {
+ auto encoder = LoadBalancerEncoder::Create(random_, nullptr, false);
+ ASSERT_TRUE(encoder.has_value());
+ EXPECT_EQ(encoder->MaybeReplaceConnectionId(TestConnectionId(1),
+ ParsedQuicVersion::Q050()),
+ absl::nullopt);
+}
+
+TEST_F(LoadBalancerEncoderTest, MaybeReplaceConnectionIdReturnsChange) {
+ random_.AddNextValues(0x83, kNonceHigh);
+ auto encoder = LoadBalancerEncoder::Create(random_, nullptr, false);
+ ASSERT_TRUE(encoder.has_value());
+ // The first byte is the config_id (0xc0) xored with (0x83 & 0x3f).
+ // The remaining bytes are random, and therefore match kNonceHigh.
+ QuicConnectionId expected({0xc3, 0x5d, 0x52, 0xde, 0x4d, 0xe3, 0xe7, 0x21});
+ EXPECT_EQ(*encoder->MaybeReplaceConnectionId(TestConnectionId(1),
+ ParsedQuicVersion::RFCv1()),
+ expected);
+}
+
+TEST_F(LoadBalancerEncoderTest, GenerateNextConnectionIdReturnsNoChange) {
+ auto config = LoadBalancerConfig::CreateUnencrypted(0, 3, 4);
+ ASSERT_TRUE(config.has_value());
+ auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true);
+ EXPECT_TRUE(encoder->UpdateConfig(*config, MakeServerId(kServerId, 3)));
+ EXPECT_EQ(encoder->GenerateNextConnectionId(TestConnectionId(1)),
+ absl::nullopt);
+}
+
+TEST_F(LoadBalancerEncoderTest, GenerateNextConnectionIdReturnsChange) {
+ random_.AddNextValues(0x83, kNonceHigh);
+ auto encoder = LoadBalancerEncoder::Create(random_, nullptr, false);
+ ASSERT_TRUE(encoder.has_value());
+ // The first byte is the config_id (0xc0) xored with (0x83 & 0x3f).
+ // The remaining bytes are random, and therefore match kNonceHigh.
+ QuicConnectionId expected({0xc3, 0x5d, 0x52, 0xde, 0x4d, 0xe3, 0xe7, 0x21});
+ EXPECT_EQ(*encoder->GenerateNextConnectionId(TestConnectionId(1)), expected);
+}
+
} // namespace
} // namespace test