Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 1 | // Copyright (c) 2019 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 5 | #include <memory> |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 6 | #include <utility> |
| 7 | |
| 8 | #include "absl/strings/string_view.h" |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 9 | #include "quiche/quic/core/io/quic_default_event_loop.h" |
| 10 | #include "quiche/quic/core/io/quic_event_loop.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 11 | #include "quiche/quic/core/proto/crypto_server_config_proto.h" |
| 12 | #include "quiche/quic/core/quic_alarm_factory.h" |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 13 | #include "quiche/quic/core/quic_default_clock.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 14 | #include "quiche/quic/platform/api/quic_expect_bug.h" |
| 15 | #include "quiche/quic/platform/api/quic_test.h" |
| 16 | #include "quiche/quic/platform/api/quic_test_loopback.h" |
| 17 | #include "quiche/quic/qbone/platform/icmp_packet.h" |
| 18 | #include "quiche/quic/qbone/qbone_client_session.h" |
| 19 | #include "quiche/quic/qbone/qbone_constants.h" |
| 20 | #include "quiche/quic/qbone/qbone_control_placeholder.pb.h" |
| 21 | #include "quiche/quic/qbone/qbone_packet_processor_test_tools.h" |
| 22 | #include "quiche/quic/qbone/qbone_server_session.h" |
| 23 | #include "quiche/quic/test_tools/crypto_test_utils.h" |
| 24 | #include "quiche/quic/test_tools/mock_clock.h" |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 25 | #include "quiche/quic/test_tools/mock_connection_id_generator.h" |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 26 | #include "quiche/quic/test_tools/quic_connection_peer.h" |
| 27 | #include "quiche/quic/test_tools/quic_session_peer.h" |
| 28 | #include "quiche/quic/test_tools/quic_test_utils.h" |
| 29 | |
| 30 | namespace quic { |
| 31 | namespace test { |
| 32 | namespace { |
| 33 | |
| 34 | using ::testing::_; |
| 35 | using ::testing::Contains; |
| 36 | using ::testing::ElementsAre; |
| 37 | using ::testing::Eq; |
| 38 | using ::testing::Invoke; |
| 39 | using ::testing::NiceMock; |
| 40 | using ::testing::Not; |
| 41 | |
| 42 | std::string TestPacketIn(const std::string& body) { |
| 43 | return PrependIPv6HeaderForTest(body, 5); |
| 44 | } |
| 45 | |
| 46 | std::string TestPacketOut(const std::string& body) { |
| 47 | return PrependIPv6HeaderForTest(body, 4); |
| 48 | } |
| 49 | |
| 50 | ParsedQuicVersionVector GetTestParams() { |
fayang | 6a2c7aa | 2023-03-23 06:57:57 -0700 | [diff] [blame] | 51 | SetQuicReloadableFlag(quic_disable_version_q046, false); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 52 | ParsedQuicVersionVector test_versions; |
| 53 | |
| 54 | // TODO(b/113130636): Make QBONE work with TLS. |
| 55 | for (const auto& version : CurrentSupportedVersionsWithQuicCrypto()) { |
| 56 | // QBONE requires MESSAGE frames |
| 57 | if (!version.SupportsMessageFrames()) { |
| 58 | continue; |
| 59 | } |
| 60 | test_versions.push_back(version); |
| 61 | } |
| 62 | |
| 63 | return test_versions; |
| 64 | } |
| 65 | |
| 66 | // Used by QuicCryptoServerConfig to provide server credentials, passes |
| 67 | // everything through to ProofSourceForTesting if success is true, |
| 68 | // and fails otherwise. |
| 69 | class IndirectionProofSource : public ProofSource { |
| 70 | public: |
| 71 | explicit IndirectionProofSource(bool success) { |
| 72 | if (success) { |
| 73 | proof_source_ = crypto_test_utils::ProofSourceForTesting(); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // ProofSource override. |
| 78 | void GetProof(const QuicSocketAddress& server_address, |
| 79 | const QuicSocketAddress& client_address, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 80 | const std::string& hostname, const std::string& server_config, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 81 | QuicTransportVersion transport_version, |
| 82 | absl::string_view chlo_hash, |
| 83 | std::unique_ptr<Callback> callback) override { |
| 84 | if (!proof_source_) { |
| 85 | QuicCryptoProof proof; |
| 86 | quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain = |
| 87 | GetCertChain(server_address, client_address, hostname, |
| 88 | &proof.cert_matched_sni); |
| 89 | callback->Run(/*ok=*/false, chain, proof, /*details=*/nullptr); |
| 90 | return; |
| 91 | } |
| 92 | proof_source_->GetProof(server_address, client_address, hostname, |
| 93 | server_config, transport_version, chlo_hash, |
| 94 | std::move(callback)); |
| 95 | } |
| 96 | |
| 97 | quiche::QuicheReferenceCountedPointer<Chain> GetCertChain( |
| 98 | const QuicSocketAddress& server_address, |
| 99 | const QuicSocketAddress& client_address, const std::string& hostname, |
| 100 | bool* cert_matched_sni) override { |
| 101 | if (!proof_source_) { |
| 102 | return quiche::QuicheReferenceCountedPointer<Chain>(); |
| 103 | } |
| 104 | return proof_source_->GetCertChain(server_address, client_address, hostname, |
| 105 | cert_matched_sni); |
| 106 | } |
| 107 | |
| 108 | void ComputeTlsSignature( |
| 109 | const QuicSocketAddress& server_address, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 110 | const QuicSocketAddress& client_address, const std::string& hostname, |
| 111 | uint16_t signature_algorithm, absl::string_view in, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 112 | std::unique_ptr<SignatureCallback> callback) override { |
| 113 | if (!proof_source_) { |
| 114 | callback->Run(/*ok=*/true, "Signature", /*details=*/nullptr); |
| 115 | return; |
| 116 | } |
| 117 | proof_source_->ComputeTlsSignature(server_address, client_address, hostname, |
| 118 | signature_algorithm, in, |
| 119 | std::move(callback)); |
| 120 | } |
| 121 | |
| 122 | absl::InlinedVector<uint16_t, 8> SupportedTlsSignatureAlgorithms() |
| 123 | const override { |
| 124 | if (!proof_source_) { |
| 125 | return {}; |
| 126 | } |
| 127 | return proof_source_->SupportedTlsSignatureAlgorithms(); |
| 128 | } |
| 129 | |
| 130 | TicketCrypter* GetTicketCrypter() override { return nullptr; } |
| 131 | |
| 132 | private: |
| 133 | std::unique_ptr<ProofSource> proof_source_; |
| 134 | }; |
| 135 | |
| 136 | // Used by QuicCryptoClientConfig to verify server credentials, passes |
| 137 | // everything through to ProofVerifierForTesting is success is true, |
| 138 | // otherwise returns a canned response of QUIC_FAILURE. |
| 139 | class IndirectionProofVerifier : public ProofVerifier { |
| 140 | public: |
| 141 | explicit IndirectionProofVerifier(bool success) { |
| 142 | if (success) { |
| 143 | proof_verifier_ = crypto_test_utils::ProofVerifierForTesting(); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | // ProofVerifier override |
| 148 | QuicAsyncStatus VerifyProof( |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 149 | const std::string& hostname, const uint16_t port, |
| 150 | const std::string& server_config, QuicTransportVersion transport_version, |
| 151 | absl::string_view chlo_hash, const std::vector<std::string>& certs, |
| 152 | const std::string& cert_sct, const std::string& signature, |
| 153 | const ProofVerifyContext* context, std::string* error_details, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 154 | std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 155 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 156 | if (!proof_verifier_) { |
| 157 | return QUIC_FAILURE; |
| 158 | } |
| 159 | return proof_verifier_->VerifyProof( |
| 160 | hostname, port, server_config, transport_version, chlo_hash, certs, |
| 161 | cert_sct, signature, context, error_details, verify_details, |
| 162 | std::move(callback)); |
| 163 | } |
| 164 | |
| 165 | QuicAsyncStatus VerifyCertChain( |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 166 | const std::string& hostname, const uint16_t port, |
| 167 | const std::vector<std::string>& certs, const std::string& ocsp_response, |
| 168 | const std::string& cert_sct, const ProofVerifyContext* context, |
| 169 | std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 170 | uint8_t* out_alert, |
| 171 | std::unique_ptr<ProofVerifierCallback> callback) override { |
| 172 | if (!proof_verifier_) { |
| 173 | return QUIC_FAILURE; |
| 174 | } |
| 175 | return proof_verifier_->VerifyCertChain( |
| 176 | hostname, port, certs, ocsp_response, cert_sct, context, error_details, |
| 177 | details, out_alert, std::move(callback)); |
| 178 | } |
| 179 | |
| 180 | std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { |
| 181 | if (!proof_verifier_) { |
| 182 | return nullptr; |
| 183 | } |
| 184 | return proof_verifier_->CreateDefaultContext(); |
| 185 | } |
| 186 | |
| 187 | private: |
| 188 | std::unique_ptr<ProofVerifier> proof_verifier_; |
| 189 | }; |
| 190 | |
| 191 | class DataSavingQbonePacketWriter : public QbonePacketWriter { |
| 192 | public: |
| 193 | void WritePacketToNetwork(const char* packet, size_t size) override { |
| 194 | data_.push_back(std::string(packet, size)); |
| 195 | } |
| 196 | |
| 197 | const std::vector<std::string>& data() { return data_; } |
| 198 | |
| 199 | private: |
| 200 | std::vector<std::string> data_; |
| 201 | }; |
| 202 | |
| 203 | template <class T> |
| 204 | class DataSavingQboneControlHandler : public QboneControlHandler<T> { |
| 205 | public: |
| 206 | void OnControlRequest(const T& request) override { data_.push_back(request); } |
| 207 | |
| 208 | void OnControlError() override { error_ = true; } |
| 209 | |
| 210 | const std::vector<T>& data() { return data_; } |
| 211 | bool error() { return error_; } |
| 212 | |
| 213 | private: |
| 214 | std::vector<T> data_; |
| 215 | bool error_ = false; |
| 216 | }; |
| 217 | |
| 218 | // Single-threaded scheduled task runner based on a MockClock. |
| 219 | // |
| 220 | // Simulates asynchronous execution on a single thread by holding scheduled |
| 221 | // tasks until Run() is called. Performs no synchronization, assumes that |
| 222 | // Schedule() and Run() are called on the same thread. |
| 223 | class FakeTaskRunner { |
| 224 | public: |
| 225 | explicit FakeTaskRunner(MockQuicConnectionHelper* helper) |
| 226 | : tasks_([](const TaskType& l, const TaskType& r) { |
| 227 | // Items at a later time should run after items at an earlier time. |
| 228 | // Priority queue comparisons should return true if l appears after r. |
| 229 | return l->time() > r->time(); |
| 230 | }), |
| 231 | helper_(helper) {} |
| 232 | |
| 233 | // Runs all tasks in time order. Executes tasks scheduled at |
| 234 | // the same in an arbitrary order. |
| 235 | void Run() { |
| 236 | while (!tasks_.empty()) { |
| 237 | tasks_.top()->Run(); |
| 238 | tasks_.pop(); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | private: |
| 243 | class InnerTask { |
| 244 | public: |
| 245 | InnerTask(std::function<void()> task, QuicTime time) |
| 246 | : task_(std::move(task)), time_(time) {} |
| 247 | |
| 248 | void Cancel() { cancelled_ = true; } |
| 249 | |
| 250 | void Run() { |
| 251 | if (!cancelled_) { |
| 252 | task_(); |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | QuicTime time() const { return time_; } |
| 257 | |
| 258 | private: |
| 259 | bool cancelled_ = false; |
| 260 | std::function<void()> task_; |
| 261 | QuicTime time_; |
| 262 | }; |
| 263 | |
| 264 | public: |
| 265 | // Schedules a function to run immediately and advances the time. |
| 266 | void Schedule(std::function<void()> task) { |
| 267 | tasks_.push(std::shared_ptr<InnerTask>( |
| 268 | new InnerTask(std::move(task), helper_->GetClock()->Now()))); |
| 269 | helper_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
| 270 | } |
| 271 | |
| 272 | private: |
| 273 | using TaskType = std::shared_ptr<InnerTask>; |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 274 | std::priority_queue<TaskType, std::vector<TaskType>, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 275 | std::function<bool(const TaskType&, const TaskType&)>> |
| 276 | tasks_; |
| 277 | MockQuicConnectionHelper* helper_; |
| 278 | }; |
| 279 | |
| 280 | class QboneSessionTest : public QuicTestWithParam<ParsedQuicVersion> { |
| 281 | public: |
| 282 | QboneSessionTest() |
| 283 | : supported_versions_({GetParam()}), |
| 284 | runner_(&helper_), |
| 285 | compressed_certs_cache_(100) {} |
| 286 | |
| 287 | ~QboneSessionTest() override { |
| 288 | delete client_connection_; |
| 289 | delete server_connection_; |
| 290 | } |
| 291 | |
| 292 | const MockClock* GetClock() const { |
| 293 | return static_cast<const MockClock*>(helper_.GetClock()); |
| 294 | } |
| 295 | |
| 296 | // The parameters are used to control whether the handshake will success or |
| 297 | // not. |
| 298 | void CreateClientAndServerSessions(bool client_handshake_success = true, |
| 299 | bool server_handshake_success = true, |
| 300 | bool send_qbone_alpn = true) { |
| 301 | // Quic crashes if packets are sent at time 0, and the clock defaults to 0. |
| 302 | helper_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 303 | event_loop_ = GetDefaultEventLoop()->Create(QuicDefaultClock::Get()); |
| 304 | alarm_factory_ = event_loop_->CreateAlarmFactory(); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 305 | client_writer_ = std::make_unique<DataSavingQbonePacketWriter>(); |
| 306 | server_writer_ = std::make_unique<DataSavingQbonePacketWriter>(); |
| 307 | client_handler_ = |
| 308 | std::make_unique<DataSavingQboneControlHandler<QboneClientRequest>>(); |
| 309 | server_handler_ = |
| 310 | std::make_unique<DataSavingQboneControlHandler<QboneServerRequest>>(); |
| 311 | QuicSocketAddress server_address(TestLoopback(), 0); |
| 312 | QuicSocketAddress client_address; |
| 313 | if (server_address.host().address_family() == IpAddressFamily::IP_V4) { |
| 314 | client_address = QuicSocketAddress(QuicIpAddress::Any4(), 0); |
| 315 | } else { |
| 316 | client_address = QuicSocketAddress(QuicIpAddress::Any6(), 0); |
| 317 | } |
| 318 | |
| 319 | { |
| 320 | client_connection_ = new QuicConnection( |
| 321 | TestConnectionId(), client_address, server_address, &helper_, |
| 322 | alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true, |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 323 | Perspective::IS_CLIENT, supported_versions_, |
| 324 | connection_id_generator_); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 325 | client_connection_->SetSelfAddress(client_address); |
| 326 | QuicConfig config; |
| 327 | client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( |
| 328 | std::make_unique<IndirectionProofVerifier>(client_handshake_success)); |
| 329 | if (send_qbone_alpn) { |
| 330 | client_crypto_config_->set_alpn("qbone"); |
| 331 | } |
| 332 | client_peer_ = std::make_unique<QboneClientSession>( |
| 333 | client_connection_, client_crypto_config_.get(), |
| 334 | /*owner=*/nullptr, config, supported_versions_, |
| 335 | QuicServerId("test.example.com", 1234, false), client_writer_.get(), |
| 336 | client_handler_.get()); |
| 337 | } |
| 338 | |
| 339 | { |
| 340 | server_connection_ = new QuicConnection( |
| 341 | TestConnectionId(), server_address, client_address, &helper_, |
| 342 | alarm_factory_.get(), new NiceMock<MockPacketWriter>(), true, |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 343 | Perspective::IS_SERVER, supported_versions_, |
| 344 | connection_id_generator_); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 345 | server_connection_->SetSelfAddress(server_address); |
| 346 | QuicConfig config; |
| 347 | server_crypto_config_ = std::make_unique<QuicCryptoServerConfig>( |
| 348 | QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), |
| 349 | std::make_unique<IndirectionProofSource>(server_handshake_success), |
| 350 | KeyExchangeSource::Default()); |
| 351 | QuicCryptoServerConfig::ConfigOptions options; |
| 352 | QuicServerConfigProtobuf primary_config = |
| 353 | server_crypto_config_->GenerateConfig(QuicRandom::GetInstance(), |
| 354 | GetClock(), options); |
| 355 | std::unique_ptr<CryptoHandshakeMessage> message( |
| 356 | server_crypto_config_->AddConfig(primary_config, |
| 357 | GetClock()->WallNow())); |
| 358 | |
| 359 | server_peer_ = std::make_unique<QboneServerSession>( |
| 360 | supported_versions_, server_connection_, nullptr, config, |
| 361 | server_crypto_config_.get(), &compressed_certs_cache_, |
| 362 | server_writer_.get(), TestLoopback6(), TestLoopback6(), 64, |
| 363 | server_handler_.get()); |
| 364 | } |
| 365 | |
| 366 | // Hook everything up! |
| 367 | MockPacketWriter* client_writer = static_cast<MockPacketWriter*>( |
| 368 | QuicConnectionPeer::GetWriter(client_peer_->connection())); |
| 369 | ON_CALL(*client_writer, WritePacket(_, _, _, _, _)) |
| 370 | .WillByDefault(Invoke([this](const char* buffer, size_t buf_len, |
| 371 | const QuicIpAddress& self_address, |
| 372 | const QuicSocketAddress& peer_address, |
| 373 | PerPacketOptions* options) { |
| 374 | char* copy = new char[1024 * 1024]; |
| 375 | memcpy(copy, buffer, buf_len); |
| 376 | runner_.Schedule([this, copy, buf_len] { |
| 377 | QuicReceivedPacket packet(copy, buf_len, GetClock()->Now()); |
| 378 | server_peer_->ProcessUdpPacket(server_connection_->self_address(), |
| 379 | client_connection_->self_address(), |
| 380 | packet); |
| 381 | delete[] copy; |
| 382 | }); |
| 383 | return WriteResult(WRITE_STATUS_OK, buf_len); |
| 384 | })); |
| 385 | MockPacketWriter* server_writer = static_cast<MockPacketWriter*>( |
| 386 | QuicConnectionPeer::GetWriter(server_peer_->connection())); |
| 387 | ON_CALL(*server_writer, WritePacket(_, _, _, _, _)) |
| 388 | .WillByDefault(Invoke([this](const char* buffer, size_t buf_len, |
| 389 | const QuicIpAddress& self_address, |
| 390 | const QuicSocketAddress& peer_address, |
| 391 | PerPacketOptions* options) { |
| 392 | char* copy = new char[1024 * 1024]; |
| 393 | memcpy(copy, buffer, buf_len); |
| 394 | runner_.Schedule([this, copy, buf_len] { |
| 395 | QuicReceivedPacket packet(copy, buf_len, GetClock()->Now()); |
| 396 | client_peer_->ProcessUdpPacket(client_connection_->self_address(), |
| 397 | server_connection_->self_address(), |
| 398 | packet); |
| 399 | delete[] copy; |
| 400 | }); |
| 401 | return WriteResult(WRITE_STATUS_OK, buf_len); |
| 402 | })); |
| 403 | } |
| 404 | |
| 405 | void StartHandshake() { |
| 406 | server_peer_->Initialize(); |
| 407 | client_peer_->Initialize(); |
| 408 | runner_.Run(); |
| 409 | } |
| 410 | |
| 411 | void ExpectICMPTooBigResponse(const std::vector<std::string>& written_packets, |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 412 | const int mtu, const std::string& packet) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 413 | auto* header = reinterpret_cast<const ip6_hdr*>(packet.data()); |
| 414 | icmp6_hdr icmp_header{}; |
| 415 | icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG; |
| 416 | icmp_header.icmp6_mtu = mtu; |
| 417 | |
| 418 | std::string expected; |
| 419 | CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet, |
| 420 | [&expected](absl::string_view icmp_packet) { |
| 421 | expected = std::string(icmp_packet); |
| 422 | }); |
| 423 | |
| 424 | EXPECT_THAT(written_packets, Contains(expected)); |
| 425 | } |
| 426 | |
| 427 | // Test handshake establishment and sending/receiving of data for two |
| 428 | // directions. |
| 429 | void TestStreamConnection(bool use_messages) { |
| 430 | ASSERT_TRUE(server_peer_->OneRttKeysAvailable()); |
| 431 | ASSERT_TRUE(client_peer_->OneRttKeysAvailable()); |
| 432 | ASSERT_TRUE(server_peer_->IsEncryptionEstablished()); |
| 433 | ASSERT_TRUE(client_peer_->IsEncryptionEstablished()); |
| 434 | |
| 435 | // Create an outgoing stream from the client and say hello. |
| 436 | QUIC_LOG(INFO) << "Sending client -> server"; |
| 437 | client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")); |
| 438 | client_peer_->ProcessPacketFromNetwork(TestPacketIn("world")); |
| 439 | runner_.Run(); |
| 440 | // The server should see the data, the client hasn't received |
| 441 | // anything yet. |
| 442 | EXPECT_THAT(server_writer_->data(), |
| 443 | ElementsAre(TestPacketOut("hello"), TestPacketOut("world"))); |
| 444 | EXPECT_TRUE(client_writer_->data().empty()); |
| 445 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 446 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 447 | |
| 448 | // Let's pretend some service responds. |
| 449 | QUIC_LOG(INFO) << "Sending server -> client"; |
| 450 | server_peer_->ProcessPacketFromNetwork(TestPacketIn("Hello Again")); |
| 451 | server_peer_->ProcessPacketFromNetwork(TestPacketIn("Again")); |
| 452 | runner_.Run(); |
| 453 | EXPECT_THAT(server_writer_->data(), |
| 454 | ElementsAre(TestPacketOut("hello"), TestPacketOut("world"))); |
| 455 | EXPECT_THAT( |
| 456 | client_writer_->data(), |
| 457 | ElementsAre(TestPacketOut("Hello Again"), TestPacketOut("Again"))); |
| 458 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 459 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 460 | |
| 461 | // Try to send long payloads that are larger than the QUIC MTU but |
| 462 | // smaller than the QBONE max size. |
| 463 | // This should trigger the non-ephemeral stream code path. |
| 464 | std::string long_data( |
| 465 | QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1, 'A'); |
| 466 | QUIC_LOG(INFO) << "Sending server -> client long data"; |
| 467 | server_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); |
| 468 | runner_.Run(); |
| 469 | if (use_messages) { |
| 470 | ExpectICMPTooBigResponse( |
| 471 | server_writer_->data(), |
| 472 | server_peer_->connection()->GetGuaranteedLargestMessagePayload(), |
| 473 | TestPacketOut(long_data)); |
| 474 | } else { |
| 475 | EXPECT_THAT(client_writer_->data(), Contains(TestPacketOut(long_data))); |
| 476 | } |
| 477 | EXPECT_THAT(server_writer_->data(), |
| 478 | Not(Contains(TestPacketOut(long_data)))); |
| 479 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 480 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 481 | |
| 482 | QUIC_LOG(INFO) << "Sending client -> server long data"; |
| 483 | client_peer_->ProcessPacketFromNetwork(TestPacketIn(long_data)); |
| 484 | runner_.Run(); |
| 485 | if (use_messages) { |
| 486 | ExpectICMPTooBigResponse( |
| 487 | client_writer_->data(), |
| 488 | client_peer_->connection()->GetGuaranteedLargestMessagePayload(), |
| 489 | TestPacketIn(long_data)); |
| 490 | } else { |
| 491 | EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data))); |
| 492 | } |
| 493 | EXPECT_FALSE(client_peer_->EarlyDataAccepted()); |
| 494 | EXPECT_FALSE(client_peer_->ReceivedInchoateReject()); |
| 495 | EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0)); |
| 496 | |
| 497 | if (!use_messages) { |
| 498 | EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1)); |
| 499 | EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1)); |
| 500 | } |
| 501 | |
| 502 | if (use_messages) { |
| 503 | EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(0)); |
| 504 | EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(0)); |
| 505 | EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(2)); |
| 506 | EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(2)); |
| 507 | } else { |
| 508 | EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(2)); |
| 509 | EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(2)); |
| 510 | EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(0)); |
| 511 | EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(0)); |
| 512 | } |
| 513 | |
| 514 | // All streams are ephemeral and should be gone. |
| 515 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 516 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 517 | } |
| 518 | |
| 519 | // Test that client and server are not connected after handshake failure. |
| 520 | void TestDisconnectAfterFailedHandshake() { |
| 521 | EXPECT_FALSE(client_peer_->IsEncryptionEstablished()); |
| 522 | EXPECT_FALSE(client_peer_->OneRttKeysAvailable()); |
| 523 | |
| 524 | EXPECT_FALSE(server_peer_->IsEncryptionEstablished()); |
| 525 | EXPECT_FALSE(server_peer_->OneRttKeysAvailable()); |
| 526 | } |
| 527 | |
| 528 | protected: |
| 529 | const ParsedQuicVersionVector supported_versions_; |
vasilvv | 40f15e0 | 2022-09-06 06:16:43 -0700 | [diff] [blame] | 530 | std::unique_ptr<QuicEventLoop> event_loop_; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 531 | std::unique_ptr<QuicAlarmFactory> alarm_factory_; |
| 532 | FakeTaskRunner runner_; |
| 533 | MockQuicConnectionHelper helper_; |
| 534 | QuicConnection* client_connection_; |
| 535 | QuicConnection* server_connection_; |
| 536 | QuicCompressedCertsCache compressed_certs_cache_; |
| 537 | |
| 538 | std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; |
| 539 | std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_; |
| 540 | std::unique_ptr<DataSavingQbonePacketWriter> client_writer_; |
| 541 | std::unique_ptr<DataSavingQbonePacketWriter> server_writer_; |
| 542 | std::unique_ptr<DataSavingQboneControlHandler<QboneClientRequest>> |
| 543 | client_handler_; |
| 544 | std::unique_ptr<DataSavingQboneControlHandler<QboneServerRequest>> |
| 545 | server_handler_; |
| 546 | |
| 547 | std::unique_ptr<QboneServerSession> server_peer_; |
| 548 | std::unique_ptr<QboneClientSession> client_peer_; |
martinduke | 605dca2 | 2022-09-01 10:40:19 -0700 | [diff] [blame] | 549 | MockConnectionIdGenerator connection_id_generator_; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 550 | }; |
| 551 | |
bnc | 5e9007f | 2022-04-13 07:50:36 -0700 | [diff] [blame] | 552 | INSTANTIATE_TEST_SUITE_P(Tests, QboneSessionTest, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 553 | ::testing::ValuesIn(GetTestParams()), |
| 554 | ::testing::PrintToStringParamName()); |
| 555 | |
| 556 | TEST_P(QboneSessionTest, StreamConnection) { |
| 557 | CreateClientAndServerSessions(); |
| 558 | client_peer_->set_send_packets_as_messages(false); |
| 559 | server_peer_->set_send_packets_as_messages(false); |
| 560 | StartHandshake(); |
| 561 | TestStreamConnection(false); |
| 562 | } |
| 563 | |
| 564 | TEST_P(QboneSessionTest, Messages) { |
| 565 | CreateClientAndServerSessions(); |
| 566 | client_peer_->set_send_packets_as_messages(true); |
| 567 | server_peer_->set_send_packets_as_messages(true); |
| 568 | StartHandshake(); |
| 569 | TestStreamConnection(true); |
| 570 | } |
| 571 | |
| 572 | TEST_P(QboneSessionTest, ClientRejection) { |
| 573 | CreateClientAndServerSessions(false /*client_handshake_success*/, |
| 574 | true /*server_handshake_success*/, |
| 575 | true /*send_qbone_alpn*/); |
| 576 | StartHandshake(); |
| 577 | TestDisconnectAfterFailedHandshake(); |
| 578 | } |
| 579 | |
| 580 | TEST_P(QboneSessionTest, BadAlpn) { |
| 581 | CreateClientAndServerSessions(true /*client_handshake_success*/, |
| 582 | true /*server_handshake_success*/, |
| 583 | false /*send_qbone_alpn*/); |
| 584 | StartHandshake(); |
| 585 | TestDisconnectAfterFailedHandshake(); |
| 586 | } |
| 587 | |
| 588 | TEST_P(QboneSessionTest, ServerRejection) { |
| 589 | CreateClientAndServerSessions(true /*client_handshake_success*/, |
| 590 | false /*server_handshake_success*/, |
| 591 | true /*send_qbone_alpn*/); |
| 592 | StartHandshake(); |
| 593 | TestDisconnectAfterFailedHandshake(); |
| 594 | } |
| 595 | |
| 596 | // Test that data streams are not created before handshake. |
| 597 | TEST_P(QboneSessionTest, CannotCreateDataStreamBeforeHandshake) { |
| 598 | CreateClientAndServerSessions(); |
| 599 | EXPECT_QUIC_BUG(client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), |
| 600 | "Attempting to send packet before encryption established"); |
| 601 | EXPECT_QUIC_BUG(server_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), |
| 602 | "Attempting to send packet before encryption established"); |
| 603 | EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); |
| 604 | EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); |
| 605 | } |
| 606 | |
| 607 | TEST_P(QboneSessionTest, ControlRequests) { |
| 608 | CreateClientAndServerSessions(); |
| 609 | StartHandshake(); |
| 610 | EXPECT_TRUE(client_handler_->data().empty()); |
| 611 | EXPECT_FALSE(client_handler_->error()); |
| 612 | EXPECT_TRUE(server_handler_->data().empty()); |
| 613 | EXPECT_FALSE(server_handler_->error()); |
| 614 | |
| 615 | QboneClientRequest client_request; |
| 616 | client_request.SetExtension(client_placeholder, "hello from the server"); |
| 617 | EXPECT_TRUE(server_peer_->SendClientRequest(client_request)); |
| 618 | runner_.Run(); |
| 619 | ASSERT_FALSE(client_handler_->data().empty()); |
| 620 | EXPECT_THAT(client_handler_->data()[0].GetExtension(client_placeholder), |
| 621 | Eq("hello from the server")); |
| 622 | EXPECT_FALSE(client_handler_->error()); |
| 623 | |
| 624 | QboneServerRequest server_request; |
| 625 | server_request.SetExtension(server_placeholder, "hello from the client"); |
| 626 | EXPECT_TRUE(client_peer_->SendServerRequest(server_request)); |
| 627 | runner_.Run(); |
| 628 | ASSERT_FALSE(server_handler_->data().empty()); |
| 629 | EXPECT_THAT(server_handler_->data()[0].GetExtension(server_placeholder), |
| 630 | Eq("hello from the client")); |
| 631 | EXPECT_FALSE(server_handler_->error()); |
| 632 | } |
| 633 | |
| 634 | } // namespace |
| 635 | } // namespace test |
| 636 | } // namespace quic |