blob: 4d7b70e53d827d16cff743a578076893dfcc26d8 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2012 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
5#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h"
6
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include <utility>
9
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "net/third_party/quiche/src/quic/core/chlo_extractor.h"
11#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
12#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
fayangccbab732019-05-13 10:11:25 -070013#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
15#include "net/third_party/quiche/src/quic/core/quic_types.h"
16#include "net/third_party/quiche/src/quic/core/quic_utils.h"
dschinazi76992e72019-07-17 20:40:40 -070017#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050018#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
22#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
23#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050024#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
dschinazi965ce092019-05-23 06:29:01 -070025#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050026
27namespace quic {
28
29typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket;
30typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList;
31typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult;
32
33namespace {
34
35// An alarm that informs the QuicDispatcher to delete old sessions.
36class DeleteSessionsAlarm : public QuicAlarm::Delegate {
37 public:
38 explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
39 : dispatcher_(dispatcher) {}
40 DeleteSessionsAlarm(const DeleteSessionsAlarm&) = delete;
41 DeleteSessionsAlarm& operator=(const DeleteSessionsAlarm&) = delete;
42
43 void OnAlarm() override { dispatcher_->DeleteSessions(); }
44
45 private:
46 // Not owned.
47 QuicDispatcher* dispatcher_;
48};
49
50// Collects packets serialized by a QuicPacketCreator in order
51// to be handed off to the time wait list manager.
52class PacketCollector : public QuicPacketCreator::DelegateInterface,
53 public QuicStreamFrameDataProducer {
54 public:
55 explicit PacketCollector(QuicBufferAllocator* allocator)
56 : send_buffer_(allocator) {}
57 ~PacketCollector() override = default;
58
59 // QuicPacketCreator::DelegateInterface methods:
60 void OnSerializedPacket(SerializedPacket* serialized_packet) override {
61 // Make a copy of the serialized packet to send later.
62 packets_.emplace_back(
63 new QuicEncryptedPacket(CopyBuffer(*serialized_packet),
64 serialized_packet->encrypted_length, true));
65 serialized_packet->encrypted_buffer = nullptr;
66 DeleteFrames(&(serialized_packet->retransmittable_frames));
67 serialized_packet->retransmittable_frames.clear();
68 }
69
70 char* GetPacketBuffer() override {
71 // Let QuicPacketCreator to serialize packets on stack buffer.
72 return nullptr;
73 }
74
dschinazi17d42422019-06-18 16:35:07 -070075 void OnUnrecoverableError(QuicErrorCode /*error*/,
76 const std::string& /*error_details*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050077
QUICHE teama6ef0a62019-03-07 20:34:33 -050078 // QuicStreamFrameDataProducer
dschinazi17d42422019-06-18 16:35:07 -070079 WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -050080 QuicStreamOffset offset,
81 QuicByteCount data_length,
82 QuicDataWriter* writer) override {
83 if (send_buffer_.WriteStreamData(offset, data_length, writer)) {
84 return WRITE_SUCCESS;
85 }
86 return WRITE_FAILED;
87 }
dschinazi17d42422019-06-18 16:35:07 -070088 bool WriteCryptoData(EncryptionLevel /*level*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -050089 QuicStreamOffset offset,
90 QuicByteCount data_length,
91 QuicDataWriter* writer) override {
92 return send_buffer_.WriteStreamData(offset, data_length, writer);
93 }
94
95 std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() {
96 return &packets_;
97 }
98
99 private:
100 std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_;
101 // This is only needed until the packets are encrypted. Once packets are
102 // encrypted, the stream data is no longer required.
103 QuicStreamSendBuffer send_buffer_;
104};
105
106// Helper for statelessly closing connections by generating the
107// correct termination packets and adding the connection to the time wait
108// list manager.
109class StatelessConnectionTerminator {
110 public:
dschinazi7b9278c2019-05-20 07:36:21 -0700111 StatelessConnectionTerminator(QuicConnectionId server_connection_id,
fayangf7c569c2019-05-07 11:56:51 -0700112 const ParsedQuicVersion version,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 QuicConnectionHelperInterface* helper,
114 QuicTimeWaitListManager* time_wait_list_manager)
dschinazi7b9278c2019-05-20 07:36:21 -0700115 : server_connection_id_(server_connection_id),
fayangf7c569c2019-05-07 11:56:51 -0700116 framer_(ParsedQuicVersionVector{version},
117 /*unused*/ QuicTime::Zero(),
118 Perspective::IS_SERVER,
119 /*unused*/ kQuicDefaultConnectionIdLength),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 collector_(helper->GetStreamSendBufferAllocator()),
dschinazi7b9278c2019-05-20 07:36:21 -0700121 creator_(server_connection_id, &framer_, &collector_),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 time_wait_list_manager_(time_wait_list_manager) {
fayangf7c569c2019-05-07 11:56:51 -0700123 framer_.set_data_producer(&collector_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500124 }
125
126 ~StatelessConnectionTerminator() {
127 // Clear framer's producer.
fayangf7c569c2019-05-07 11:56:51 -0700128 framer_.set_data_producer(nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500129 }
130
131 // Generates a packet containing a CONNECTION_CLOSE frame specifying
132 // |error_code| and |error_details| and add the connection to time wait.
133 void CloseConnection(QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700134 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500135 bool ietf_quic) {
fkastenholze9d71a82019-04-09 05:12:13 -0700136 QuicConnectionCloseFrame* frame =
137 new QuicConnectionCloseFrame(error_code, error_details);
fkastenholz305e1732019-06-18 05:01:22 -0700138 if (VersionHasIetfQuicFrames(framer_.transport_version())) {
fkastenholz72f509b2019-04-10 09:17:49 -0700139 frame->close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
140 }
141
QUICHE teama6ef0a62019-03-07 20:34:33 -0500142 if (!creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)) {
143 QUIC_BUG << "Unable to add frame to an empty packet";
144 delete frame;
145 return;
146 }
147 creator_.Flush();
148 DCHECK_EQ(1u, collector_.packets()->size());
149 time_wait_list_manager_->AddConnectionIdToTimeWait(
dschinazi7b9278c2019-05-20 07:36:21 -0700150 server_connection_id_, ietf_quic,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500151 QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
QUICHE team6987b4a2019-03-15 16:23:04 -0700152 quic::ENCRYPTION_INITIAL, collector_.packets());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500153 }
154
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155 private:
dschinazi7b9278c2019-05-20 07:36:21 -0700156 QuicConnectionId server_connection_id_;
fayangf7c569c2019-05-07 11:56:51 -0700157 QuicFramer framer_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500158 // Set as the visitor of |creator_| to collect any generated packets.
159 PacketCollector collector_;
160 QuicPacketCreator creator_;
161 QuicTimeWaitListManager* time_wait_list_manager_;
162};
163
164// Class which extracts the ALPN from a CHLO packet.
165class ChloAlpnExtractor : public ChloExtractor::Delegate {
166 public:
dschinazi17d42422019-06-18 16:35:07 -0700167 void OnChlo(QuicTransportVersion /*version*/,
168 QuicConnectionId /*server_connection_id*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500169 const CryptoHandshakeMessage& chlo) override {
170 QuicStringPiece alpn_value;
171 if (chlo.GetStringPiece(kALPN, &alpn_value)) {
vasilvvc48c8712019-03-11 13:38:16 -0700172 alpn_ = std::string(alpn_value);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 }
174 }
175
vasilvvc48c8712019-03-11 13:38:16 -0700176 std::string&& ConsumeAlpn() { return std::move(alpn_); }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500177
178 private:
vasilvvc48c8712019-03-11 13:38:16 -0700179 std::string alpn_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500180};
181
QUICHE teama6ef0a62019-03-07 20:34:33 -0500182} // namespace
183
184QuicDispatcher::QuicDispatcher(
185 const QuicConfig* config,
186 const QuicCryptoServerConfig* crypto_config,
187 QuicVersionManager* version_manager,
188 std::unique_ptr<QuicConnectionHelperInterface> helper,
189 std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
190 std::unique_ptr<QuicAlarmFactory> alarm_factory,
dschinazi8ff74822019-05-28 16:37:20 -0700191 uint8_t expected_server_connection_id_length)
QUICHE teama6ef0a62019-03-07 20:34:33 -0500192 : config_(config),
193 crypto_config_(crypto_config),
194 compressed_certs_cache_(
195 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
196 helper_(std::move(helper)),
197 session_helper_(std::move(session_helper)),
198 alarm_factory_(std::move(alarm_factory)),
199 delete_sessions_alarm_(
200 alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))),
201 buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202 version_manager_(version_manager),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500203 last_error_(QUIC_NO_ERROR),
204 new_sessions_allowed_per_event_loop_(0u),
QUICHE team963d57e2019-03-21 10:58:47 -0700205 accept_new_connections_(true),
dschinazi7b9278c2019-05-20 07:36:21 -0700206 allow_short_initial_server_connection_ids_(false),
dschinazi8ff74822019-05-28 16:37:20 -0700207 expected_server_connection_id_length_(
208 expected_server_connection_id_length),
fayang91475c42019-06-19 08:04:26 -0700209 should_update_expected_server_connection_id_length_(false) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500210
211QuicDispatcher::~QuicDispatcher() {
212 session_map_.clear();
213 closed_session_list_.clear();
214}
215
216void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
217 DCHECK(writer_ == nullptr);
218 writer_.reset(writer);
219 time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
220}
221
222void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address,
223 const QuicSocketAddress& peer_address,
224 const QuicReceivedPacket& packet) {
dschinazi965ce092019-05-23 06:29:01 -0700225 QUIC_DVLOG(2) << "Dispatcher received encrypted " << packet.length()
226 << " bytes:" << std::endl
227 << QuicTextUtils::HexDump(
228 QuicStringPiece(packet.data(), packet.length()));
fayang1ed1f762019-06-24 11:40:04 -0700229 ReceivedPacketInfo packet_info(self_address, peer_address, packet);
fayang1f123502019-05-14 08:05:16 -0700230 std::string detailed_error;
dschinazi48ac9192019-07-31 00:07:26 -0700231 QuicErrorCode error;
232 if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
233 error = QuicFramer::ProcessPacketDispatcher(
234 packet, expected_server_connection_id_length_, &packet_info.form,
235 &packet_info.version_flag, &packet_info.version_label,
236 &packet_info.destination_connection_id,
237 &packet_info.source_connection_id, &detailed_error);
238 } else {
239 QUIC_RELOADABLE_FLAG_COUNT(quic_use_parse_public_header);
240 bool retry_token_present;
241 QuicStringPiece retry_token;
242 error = QuicFramer::ParsePublicHeaderDispatcher(
243 packet, expected_server_connection_id_length_, &packet_info.form,
244 &packet_info.version_flag, &packet_info.use_length_prefix,
245 &packet_info.version_label, &packet_info.version,
246 &packet_info.destination_connection_id,
247 &packet_info.source_connection_id, &retry_token_present, &retry_token,
248 &detailed_error);
249 }
fayangccbab732019-05-13 10:11:25 -0700250 if (error != QUIC_NO_ERROR) {
251 // Packet has framing error.
252 SetLastError(error);
253 QUIC_DLOG(ERROR) << detailed_error;
254 return;
255 }
dschinazi243eabc2019-08-05 16:15:29 -0700256 if (!GetQuicReloadableFlag(quic_use_parse_public_header)) {
257 packet_info.version = ParseQuicVersionLabel(packet_info.version_label);
258 }
fayang1ed1f762019-06-24 11:40:04 -0700259 if (packet_info.destination_connection_id.length() !=
dschinazi8ff74822019-05-28 16:37:20 -0700260 expected_server_connection_id_length_ &&
261 !should_update_expected_server_connection_id_length_ &&
fayangccbab732019-05-13 10:11:25 -0700262 !QuicUtils::VariableLengthConnectionIdAllowedForVersion(
fayang1ed1f762019-06-24 11:40:04 -0700263 packet_info.version.transport_version)) {
fayangccbab732019-05-13 10:11:25 -0700264 SetLastError(QUIC_INVALID_PACKET_HEADER);
265 QUIC_DLOG(ERROR) << "Invalid Connection Id Length";
266 return;
267 }
dschinazib953d022019-08-01 18:05:58 -0700268
269 if (packet_info.version_flag && IsSupportedVersion(packet_info.version)) {
270 if (!QuicUtils::IsConnectionIdValidForVersion(
271 packet_info.destination_connection_id,
272 packet_info.version.transport_version)) {
273 SetLastError(QUIC_INVALID_PACKET_HEADER);
274 QUIC_DLOG(ERROR)
275 << "Invalid destination connection ID length for version";
276 return;
277 }
278 if (packet_info.version.SupportsClientConnectionIds() &&
279 !QuicUtils::IsConnectionIdValidForVersion(
280 packet_info.source_connection_id,
281 packet_info.version.transport_version)) {
282 SetLastError(QUIC_INVALID_PACKET_HEADER);
283 QUIC_DLOG(ERROR) << "Invalid source connection ID length for version";
284 return;
285 }
286 }
287
dschinazi8ff74822019-05-28 16:37:20 -0700288 if (should_update_expected_server_connection_id_length_) {
fayang1ed1f762019-06-24 11:40:04 -0700289 expected_server_connection_id_length_ =
290 packet_info.destination_connection_id.length();
fayangccbab732019-05-13 10:11:25 -0700291 }
fayang91475c42019-06-19 08:04:26 -0700292
fayang1ed1f762019-06-24 11:40:04 -0700293 if (MaybeDispatchPacket(packet_info)) {
fayang91475c42019-06-19 08:04:26 -0700294 // Packet has been dropped or successfully dispatched, stop processing.
fayangccbab732019-05-13 10:11:25 -0700295 return;
296 }
fayang1ed1f762019-06-24 11:40:04 -0700297 ProcessHeader(&packet_info);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298}
299
dschinazi7b9278c2019-05-20 07:36:21 -0700300QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId(
301 QuicConnectionId server_connection_id,
QUICHE teamc65d1d12019-03-19 20:58:04 -0700302 ParsedQuicVersion version) {
fayang91475c42019-06-19 08:04:26 -0700303 if (server_connection_id.length() == expected_server_connection_id_length_) {
dschinazi7b9278c2019-05-20 07:36:21 -0700304 return server_connection_id;
QUICHE teamc65d1d12019-03-19 20:58:04 -0700305 }
306 DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
307 version.transport_version));
dschinaziadc75072019-08-19 10:54:45 -0700308
QUICHE teamc65d1d12019-03-19 20:58:04 -0700309 QuicConnectionId new_connection_id =
wub662a3d62019-08-16 14:10:50 -0700310 GenerateNewServerConnectionId(version, server_connection_id);
fayang91475c42019-06-19 08:04:26 -0700311 DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length());
dschinazi28c1bf32019-08-19 11:54:46 -0700312
313 // Verify that GenerateNewServerConnectionId is deterministic.
314 DCHECK_EQ(new_connection_id,
315 GenerateNewServerConnectionId(version, server_connection_id));
316
dschinazi7b9278c2019-05-20 07:36:21 -0700317 QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id
QUICHE teamc65d1d12019-03-19 20:58:04 -0700318 << " with " << new_connection_id;
319 return new_connection_id;
320}
321
wub662a3d62019-08-16 14:10:50 -0700322QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId(
323 ParsedQuicVersion /*version*/,
dschinaziadc75072019-08-19 10:54:45 -0700324 QuicConnectionId connection_id) const {
dschinaziadc75072019-08-19 10:54:45 -0700325 return QuicUtils::CreateReplacementConnectionId(connection_id);
wub662a3d62019-08-16 14:10:50 -0700326}
327
fayang91475c42019-06-19 08:04:26 -0700328bool QuicDispatcher::MaybeDispatchPacket(
fayang1ed1f762019-06-24 11:40:04 -0700329 const ReceivedPacketInfo& packet_info) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500330 // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC.
331 // Given that we can't even send a reply rejecting the packet, just drop the
332 // packet.
fayang1ed1f762019-06-24 11:40:04 -0700333 if (packet_info.peer_address.port() == 0) {
fayang91475c42019-06-19 08:04:26 -0700334 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 }
336
fayang1ed1f762019-06-24 11:40:04 -0700337 QuicConnectionId server_connection_id = packet_info.destination_connection_id;
QUICHE team8e2e4532019-03-14 14:37:56 -0700338
QUICHE team963d57e2019-03-21 10:58:47 -0700339 // The IETF spec requires the client to generate an initial server
340 // connection ID that is at least 64 bits long. After that initial
341 // connection ID, the dispatcher picks a new one of its expected length.
342 // Therefore we should never receive a connection ID that is smaller
343 // than 64 bits and smaller than what we expect.
dschinazi7b9278c2019-05-20 07:36:21 -0700344 if (server_connection_id.length() < kQuicMinimumInitialConnectionIdLength &&
fayang91475c42019-06-19 08:04:26 -0700345 server_connection_id.length() < expected_server_connection_id_length_ &&
dschinazi7b9278c2019-05-20 07:36:21 -0700346 !allow_short_initial_server_connection_ids_) {
fayang1ed1f762019-06-24 11:40:04 -0700347 DCHECK(packet_info.version_flag);
QUICHE team963d57e2019-03-21 10:58:47 -0700348 DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
fayang1ed1f762019-06-24 11:40:04 -0700349 packet_info.version.transport_version));
QUICHE team963d57e2019-03-21 10:58:47 -0700350 QUIC_DLOG(INFO) << "Packet with short destination connection ID "
dschinazi7b9278c2019-05-20 07:36:21 -0700351 << server_connection_id << " expected "
fayang91475c42019-06-19 08:04:26 -0700352 << static_cast<int>(expected_server_connection_id_length_);
dschinaziee07e472019-06-19 09:56:56 -0700353 if (!GetQuicReloadableFlag(quic_drop_invalid_small_initial_connection_id)) {
fayang17230ac2019-06-21 06:28:28 -0700354 // Add this connection_id to the time-wait state, to safely reject
355 // future packets.
356 QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
357 << " to time-wait list.";
358 StatelesslyTerminateConnection(
fayang1ed1f762019-06-24 11:40:04 -0700359 server_connection_id, packet_info.form, packet_info.version_flag,
dschinazi48ac9192019-07-31 00:07:26 -0700360 packet_info.use_length_prefix, packet_info.version,
361 QUIC_HANDSHAKE_FAILED, "Reject connection",
fayang17230ac2019-06-21 06:28:28 -0700362 quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
363
364 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
365 server_connection_id));
366 time_wait_list_manager_->ProcessPacket(
fayang1ed1f762019-06-24 11:40:04 -0700367 packet_info.self_address, packet_info.peer_address,
368 server_connection_id, packet_info.form, GetPerPacketContext());
fayang17230ac2019-06-21 06:28:28 -0700369
370 buffered_packets_.DiscardPackets(server_connection_id);
dschinaziee07e472019-06-19 09:56:56 -0700371 } else {
372 QUIC_RELOADABLE_FLAG_COUNT(quic_drop_invalid_small_initial_connection_id);
fayang17230ac2019-06-21 06:28:28 -0700373 // Drop the packet silently.
dschinaziee07e472019-06-19 09:56:56 -0700374 }
fayang91475c42019-06-19 08:04:26 -0700375 return true;
QUICHE team963d57e2019-03-21 10:58:47 -0700376 }
377
QUICHE teama6ef0a62019-03-07 20:34:33 -0500378 // Packets with connection IDs for active connections are processed
379 // immediately.
dschinazi7b9278c2019-05-20 07:36:21 -0700380 auto it = session_map_.find(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500381 if (it != session_map_.end()) {
dschinazi7b9278c2019-05-20 07:36:21 -0700382 DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id));
fayang1ed1f762019-06-24 11:40:04 -0700383 it->second->ProcessUdpPacket(packet_info.self_address,
384 packet_info.peer_address, packet_info.packet);
fayang91475c42019-06-19 08:04:26 -0700385 return true;
dschinazi5c030852019-07-11 15:45:53 -0700386 } else {
387 // We did not find the connection ID, check if we've replaced it.
388 QuicConnectionId replaced_connection_id = MaybeReplaceServerConnectionId(
389 server_connection_id, packet_info.version);
390 if (replaced_connection_id != server_connection_id) {
391 // Search for the replacement.
392 auto it2 = session_map_.find(replaced_connection_id);
393 if (it2 != session_map_.end()) {
394 DCHECK(!buffered_packets_.HasBufferedPackets(replaced_connection_id));
395 it2->second->ProcessUdpPacket(packet_info.self_address,
396 packet_info.peer_address,
397 packet_info.packet);
398 return true;
399 }
400 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 }
402
dschinazi7b9278c2019-05-20 07:36:21 -0700403 if (buffered_packets_.HasChloForConnection(server_connection_id)) {
fayang1ed1f762019-06-24 11:40:04 -0700404 BufferEarlyPacket(packet_info);
fayang91475c42019-06-19 08:04:26 -0700405 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500406 }
407
fayang1ed1f762019-06-24 11:40:04 -0700408 if (OnFailedToDispatchPacket(packet_info)) {
fayang91475c42019-06-19 08:04:26 -0700409 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500410 }
411
dschinazi7b9278c2019-05-20 07:36:21 -0700412 if (time_wait_list_manager_->IsConnectionIdInTimeWait(server_connection_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500413 // This connection ID is already in time-wait state.
414 time_wait_list_manager_->ProcessPacket(
fayang1ed1f762019-06-24 11:40:04 -0700415 packet_info.self_address, packet_info.peer_address,
416 packet_info.destination_connection_id, packet_info.form,
417 GetPerPacketContext());
fayang91475c42019-06-19 08:04:26 -0700418 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500419 }
420
421 // The packet has an unknown connection ID.
422
423 // Unless the packet provides a version, assume that we can continue
424 // processing using our preferred version.
fayang1ed1f762019-06-24 11:40:04 -0700425 if (packet_info.version_flag) {
426 if (!IsSupportedVersion(packet_info.version)) {
427 if (ShouldCreateSessionForUnknownVersion(packet_info.version_label)) {
fayang91475c42019-06-19 08:04:26 -0700428 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500429 }
430 if (!crypto_config()->validate_chlo_size() ||
fayang1ed1f762019-06-24 11:40:04 -0700431 packet_info.packet.length() >= kMinPacketSizeForVersionNegotiation) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500432 // Since the version is not supported, send a version negotiation
433 // packet and stop processing the current packet.
fayang1ed1f762019-06-24 11:40:04 -0700434 QuicConnectionId client_connection_id =
435 packet_info.source_connection_id;
dschinazi30ab6db2019-08-13 14:43:32 -0700436 bool use_length_prefix = packet_info.use_length_prefix;
437 if (!GetQuicReloadableFlag(quic_use_length_prefix_from_packet_info)) {
438 use_length_prefix = packet_info.form != GOOGLE_QUIC_PACKET &&
439 !QuicVersionLabelUses4BitConnectionIdLength(
440 packet_info.version_label);
441 } else {
442 QUIC_RELOADABLE_FLAG_COUNT(quic_use_length_prefix_from_packet_info);
443 // TODO(dschinazi) remove the client-side workaround in
444 // QuicFramer::ParseServerVersionNegotiationProbeResponse
445 // when quic_use_length_prefix_from_packet_info is deprecated.
446 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500447 time_wait_list_manager()->SendVersionNegotiationPacket(
dschinazi346b7ce2019-06-05 01:38:18 -0700448 server_connection_id, client_connection_id,
dschinazi30ab6db2019-08-13 14:43:32 -0700449 packet_info.form != GOOGLE_QUIC_PACKET, use_length_prefix,
dschinazi48ac9192019-07-31 00:07:26 -0700450 GetSupportedVersions(), packet_info.self_address,
451 packet_info.peer_address, GetPerPacketContext());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500452 }
fayang91475c42019-06-19 08:04:26 -0700453 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500454 }
fayangccbab732019-05-13 10:11:25 -0700455 }
nharper55fa6132019-05-07 19:37:21 -0700456
nharper55fa6132019-05-07 19:37:21 -0700457 return false;
458}
459
fayang1ed1f762019-06-24 11:40:04 -0700460void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) {
461 QuicConnectionId server_connection_id =
462 packet_info->destination_connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500463 // Packet's connection ID is unknown. Apply the validity checks.
wub2a5670f2019-06-13 13:39:16 -0700464 // TODO(wub): Determine the fate completely in ValidityChecks, then call
465 // ProcessUnauthenticatedHeaderFate in one place.
fayang1ed1f762019-06-24 11:40:04 -0700466 QuicPacketFate fate = ValidityChecks(*packet_info);
fayang17230ac2019-06-21 06:28:28 -0700467 ChloAlpnExtractor alpn_extractor;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500468 switch (fate) {
dschinazi76992e72019-07-17 20:40:40 -0700469 case kFateProcess: {
fayang1ed1f762019-06-24 11:40:04 -0700470 if (packet_info->version.handshake_protocol == PROTOCOL_TLS1_3) {
fayang17230ac2019-06-21 06:28:28 -0700471 // TODO(nharper): Support buffering non-ClientHello packets when using
472 // TLS.
fayang1ed1f762019-06-24 11:40:04 -0700473 ProcessChlo(/*alpn=*/"", packet_info);
fayang17230ac2019-06-21 06:28:28 -0700474 break;
475 }
dschinazi76992e72019-07-17 20:40:40 -0700476 ParsedQuicVersionVector chlo_extractor_versions;
477 if (!GetQuicRestartFlag(
478 quic_dispatcher_hands_chlo_extractor_one_version)) {
479 chlo_extractor_versions = GetSupportedVersions();
480 } else {
481 QUIC_RESTART_FLAG_COUNT(
482 quic_dispatcher_hands_chlo_extractor_one_version);
483 chlo_extractor_versions = {packet_info->version};
484 // TODO(dschinazi) once we deprecate
485 // quic_dispatcher_hands_chlo_extractor_one_version, we should change
486 // ChloExtractor::Extract to only take one version.
487 }
fayang17230ac2019-06-21 06:28:28 -0700488 if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) &&
dschinazi76992e72019-07-17 20:40:40 -0700489 !ChloExtractor::Extract(packet_info->packet, chlo_extractor_versions,
fayang17230ac2019-06-21 06:28:28 -0700490 config_->create_session_tag_indicators(),
491 &alpn_extractor,
492 server_connection_id.length())) {
493 // Buffer non-CHLO packets.
fayang1ed1f762019-06-24 11:40:04 -0700494 BufferEarlyPacket(*packet_info);
fayang17230ac2019-06-21 06:28:28 -0700495 break;
496 }
fayang1ed1f762019-06-24 11:40:04 -0700497 ProcessChlo(alpn_extractor.ConsumeAlpn(), packet_info);
dschinazi76992e72019-07-17 20:40:40 -0700498 } break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500499 case kFateTimeWait:
wub0a4b9c52019-05-28 13:18:58 -0700500 // Add this connection_id to the time-wait state, to safely reject
501 // future packets.
502 QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
503 << " to time-wait list.";
504 QUIC_CODE_COUNT(quic_reject_fate_time_wait);
505 StatelesslyTerminateConnection(
fayang1ed1f762019-06-24 11:40:04 -0700506 server_connection_id, packet_info->form, packet_info->version_flag,
dschinazi48ac9192019-07-31 00:07:26 -0700507 packet_info->use_length_prefix, packet_info->version,
508 QUIC_HANDSHAKE_FAILED, "Reject connection",
wub0a4b9c52019-05-28 13:18:58 -0700509 quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
510
dschinazi7b9278c2019-05-20 07:36:21 -0700511 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
512 server_connection_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500513 time_wait_list_manager_->ProcessPacket(
fayang1ed1f762019-06-24 11:40:04 -0700514 packet_info->self_address, packet_info->peer_address,
515 server_connection_id, packet_info->form, GetPerPacketContext());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500516
dschinazi7b9278c2019-05-20 07:36:21 -0700517 buffered_packets_.DiscardPackets(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500518 break;
fayangd057e662019-07-10 13:29:41 -0700519 case kFateDrop:
520 break;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500521 }
522}
523
524QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
fayang1ed1f762019-06-24 11:40:04 -0700525 const ReceivedPacketInfo& packet_info) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500526 // To have all the checks work properly without tears, insert any new check
527 // into the framework of this method in the section for checks that return the
528 // check's fate value. The sections for checks must be ordered with the
529 // highest priority fate first.
530
QUICHE teama6ef0a62019-03-07 20:34:33 -0500531 // All packets within a connection sent by a client before receiving a
532 // response from the server are required to have the version negotiation flag
533 // set. Since this may be a client continuing a connection we lost track of
534 // via server restart, send a rejection to fast-fail the connection.
fayang1ed1f762019-06-24 11:40:04 -0700535 if (!packet_info.version_flag) {
dschinazi5b236be2019-08-19 14:55:22 -0700536 if (GetQuicReloadableFlag(quic_reply_to_old_android_conformance_test)) {
537 QUIC_RELOADABLE_FLAG_COUNT(quic_reply_to_old_android_conformance_test);
538 // The Android network conformance test contains a UDP test that sends a
539 // 12-byte packet with the following format:
540 // - 0x0c (public flags: 8-byte connection ID, 1-byte packet number)
541 // - randomized 8-byte connection ID
542 // - 0x01 (1-byte packet number)
543 // - 0x00 (private flags)
544 // - 0x07 (PING frame).
545 // That packet is invalid and we would normally drop it but in order to
546 // unblock this conformance testing we have the following workaround that
547 // will be removed once the fixed test is deployed.
548 // TODO(b/139691956) Remove this workaround once fixed test is deployed.
549 if (packet_info.packet.length() == 12 &&
550 packet_info.packet.data()[0] == 0x0c &&
551 packet_info.packet.data()[9] == 0x01 &&
552 packet_info.packet.data()[10] == 0x00 &&
553 packet_info.packet.data()[11] == 0x07) {
554 QUIC_DLOG(INFO) << "Received Android UDP network conformance test "
555 "packet with connection ID "
556 << packet_info.destination_connection_id;
557 // Respond with a public reset that the test will know how to parse
558 // then return kFateDrop to stop processing of this packet.
559 time_wait_list_manager()->SendPublicReset(
560 packet_info.self_address, packet_info.peer_address,
561 packet_info.destination_connection_id,
562 /*ietf_quic=*/false, GetPerPacketContext());
563 return kFateDrop;
564 }
565 }
566
QUICHE teama6ef0a62019-03-07 20:34:33 -0500567 QUIC_DLOG(INFO)
568 << "Packet without version arrived for unknown connection ID "
fayang1ed1f762019-06-24 11:40:04 -0700569 << packet_info.destination_connection_id;
fayangd057e662019-07-10 13:29:41 -0700570 if (GetQuicReloadableFlag(quic_reject_unprocessable_packets_statelessly)) {
571 QUIC_RELOADABLE_FLAG_COUNT(quic_reject_unprocessable_packets_statelessly);
572 MaybeResetPacketsWithNoVersion(packet_info);
573 return kFateDrop;
574 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500575 return kFateTimeWait;
576 }
577
fayang91475c42019-06-19 08:04:26 -0700578 // Let the connection parse and validate packet number.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500579 return kFateProcess;
580}
581
582void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
583 QuicConnection* connection,
dschinazi17d42422019-06-18 16:35:07 -0700584 ConnectionCloseSource /*source*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500585 write_blocked_list_.erase(connection);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500586 QuicTimeWaitListManager::TimeWaitAction action =
587 QuicTimeWaitListManager::SEND_STATELESS_RESET;
588 if (connection->termination_packets() != nullptr &&
589 !connection->termination_packets()->empty()) {
590 action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
fayang51c23732019-06-24 06:59:55 -0700591 } else {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500592 if (!connection->IsHandshakeConfirmed()) {
fayangd4291e42019-05-30 10:31:21 -0700593 if (!VersionHasIetfInvariantHeader(connection->transport_version())) {
fayang1de67892019-04-19 05:59:45 -0700594 QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed);
595 } else {
596 QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed);
597 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500598 action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
599 // This serializes a connection close termination packet with error code
600 // QUIC_HANDSHAKE_FAILED and adds the connection to the time wait list.
601 StatelesslyTerminateConnection(
fayang1de67892019-04-19 05:59:45 -0700602 connection->connection_id(),
fayangd4291e42019-05-30 10:31:21 -0700603 VersionHasIetfInvariantHeader(connection->transport_version())
fayang1de67892019-04-19 05:59:45 -0700604 ? IETF_QUIC_LONG_HEADER_PACKET
605 : GOOGLE_QUIC_PACKET,
dschinazi48ac9192019-07-31 00:07:26 -0700606 /*version_flag=*/true,
607 connection->version().HasLengthPrefixedConnectionIds(),
608 connection->version(), QUIC_HANDSHAKE_FAILED,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500609 "Connection is closed by server before handshake confirmed",
610 // Although it is our intention to send termination packets, the
611 // |action| argument is not used by this call to
612 // StatelesslyTerminateConnection().
613 action);
614 session_map_.erase(it);
615 return;
616 }
617 QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_stateless_reset);
618 }
619 time_wait_list_manager_->AddConnectionIdToTimeWait(
fayangd4291e42019-05-30 10:31:21 -0700620 it->first, VersionHasIetfInvariantHeader(connection->transport_version()),
621 action, connection->encryption_level(),
622 connection->termination_packets());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500623 session_map_.erase(it);
624}
625
626void QuicDispatcher::StopAcceptingNewConnections() {
627 accept_new_connections_ = false;
628}
629
630std::unique_ptr<QuicPerPacketContext> QuicDispatcher::GetPerPacketContext()
631 const {
632 return nullptr;
633}
634
635void QuicDispatcher::DeleteSessions() {
QUICHE teamaa1d6a82019-03-13 09:14:13 -0700636 if (!write_blocked_list_.empty()) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500637 for (const std::unique_ptr<QuicSession>& session : closed_session_list_) {
638 if (write_blocked_list_.erase(session->connection()) != 0) {
639 QUIC_BUG << "QuicConnection was in WriteBlockedList before destruction";
640 }
641 }
642 }
643 closed_session_list_.clear();
644}
645
646void QuicDispatcher::OnCanWrite() {
647 // The socket is now writable.
648 writer_->SetWritable();
649
650 // Move every blocked writer in |write_blocked_list_| to a temporary list.
651 const size_t num_blocked_writers_before = write_blocked_list_.size();
652 WriteBlockedList temp_list;
653 temp_list.swap(write_blocked_list_);
654 DCHECK(write_blocked_list_.empty());
655
656 // Give each blocked writer a chance to write what they indended to write.
657 // If they are blocked again, they will call |OnWriteBlocked| to add
658 // themselves back into |write_blocked_list_|.
659 while (!temp_list.empty()) {
660 QuicBlockedWriterInterface* blocked_writer = temp_list.begin()->first;
661 temp_list.erase(temp_list.begin());
662 blocked_writer->OnBlockedWriterCanWrite();
663 }
664 const size_t num_blocked_writers_after = write_blocked_list_.size();
665 if (num_blocked_writers_after != 0) {
666 if (num_blocked_writers_before == num_blocked_writers_after) {
667 QUIC_CODE_COUNT(quic_zero_progress_on_can_write);
668 } else {
669 QUIC_CODE_COUNT(quic_blocked_again_on_can_write);
670 }
671 }
672}
673
674bool QuicDispatcher::HasPendingWrites() const {
675 return !write_blocked_list_.empty();
676}
677
678void QuicDispatcher::Shutdown() {
679 while (!session_map_.empty()) {
680 QuicSession* session = session_map_.begin()->second.get();
681 session->connection()->CloseConnection(
682 QUIC_PEER_GOING_AWAY, "Server shutdown imminent",
683 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
684 // Validate that the session removes itself from the session map on close.
685 DCHECK(session_map_.empty() ||
686 session_map_.begin()->second.get() != session);
687 }
688 DeleteSessions();
689}
690
dschinazi7b9278c2019-05-20 07:36:21 -0700691void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500692 QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700693 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500694 ConnectionCloseSource source) {
dschinazi7b9278c2019-05-20 07:36:21 -0700695 auto it = session_map_.find(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500696 if (it == session_map_.end()) {
dschinazi7b9278c2019-05-20 07:36:21 -0700697 QUIC_BUG << "ConnectionId " << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500698 << " does not exist in the session map. Error: "
699 << QuicErrorCodeToString(error);
700 QUIC_BUG << QuicStackTrace();
701 return;
702 }
703
704 QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR)
dschinazi7b9278c2019-05-20 07:36:21 -0700705 << "Closing connection (" << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500706 << ") due to error: " << QuicErrorCodeToString(error)
707 << ", with details: " << error_details;
708
709 QuicConnection* connection = it->second->connection();
710 if (ShouldDestroySessionAsynchronously()) {
711 // Set up alarm to fire immediately to bring destruction of this session
712 // out of current call stack.
713 if (closed_session_list_.empty()) {
714 delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(),
715 QuicTime::Delta::Zero());
716 }
717 closed_session_list_.push_back(std::move(it->second));
718 }
wub5f64ec42019-06-06 07:31:19 -0700719 CleanUpSession(it, connection, source);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500720}
721
722void QuicDispatcher::OnWriteBlocked(
723 QuicBlockedWriterInterface* blocked_writer) {
724 if (!blocked_writer->IsWriterBlocked()) {
725 // It is a programming error if this ever happens. When we are sure it is
726 // not happening, replace it with a DCHECK.
727 QUIC_BUG
728 << "Tried to add writer into blocked list when it shouldn't be added";
729 // Return without adding the connection to the blocked list, to avoid
730 // infinite loops in OnCanWrite.
731 return;
732 }
733
734 write_blocked_list_.insert(std::make_pair(blocked_writer, true));
735}
736
dschinazi17d42422019-06-18 16:35:07 -0700737void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& /*frame*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500738
dschinazi17d42422019-06-18 16:35:07 -0700739void QuicDispatcher::OnStopSendingReceived(
740 const QuicStopSendingFrame& /*frame*/) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500741
742void QuicDispatcher::OnConnectionAddedToTimeWaitList(
dschinazi7b9278c2019-05-20 07:36:21 -0700743 QuicConnectionId server_connection_id) {
744 QUIC_DLOG(INFO) << "Connection " << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500745 << " added to time wait list.";
746}
747
748void QuicDispatcher::StatelesslyTerminateConnection(
dschinazi7b9278c2019-05-20 07:36:21 -0700749 QuicConnectionId server_connection_id,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500750 PacketHeaderFormat format,
fayang1de67892019-04-19 05:59:45 -0700751 bool version_flag,
dschinazi48ac9192019-07-31 00:07:26 -0700752 bool use_length_prefix,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500753 ParsedQuicVersion version,
754 QuicErrorCode error_code,
vasilvvc48c8712019-03-11 13:38:16 -0700755 const std::string& error_details,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500756 QuicTimeWaitListManager::TimeWaitAction action) {
fayang51c23732019-06-24 06:59:55 -0700757 if (format != IETF_QUIC_LONG_HEADER_PACKET && !version_flag) {
dschinazi7b9278c2019-05-20 07:36:21 -0700758 QUIC_DVLOG(1) << "Statelessly terminating " << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500759 << " based on a non-ietf-long packet, action:" << action
760 << ", error_code:" << error_code
761 << ", error_details:" << error_details;
762 time_wait_list_manager_->AddConnectionIdToTimeWait(
dschinazi7b9278c2019-05-20 07:36:21 -0700763 server_connection_id, format != GOOGLE_QUIC_PACKET, action,
764 ENCRYPTION_INITIAL, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500765 return;
766 }
767
768 // If the version is known and supported by framer, send a connection close.
fayangccbab732019-05-13 10:11:25 -0700769 if (IsSupportedVersion(version)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500770 QUIC_DVLOG(1)
dschinazi7b9278c2019-05-20 07:36:21 -0700771 << "Statelessly terminating " << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500772 << " based on an ietf-long packet, which has a supported version:"
773 << version << ", error_code:" << error_code
774 << ", error_details:" << error_details;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500775
dschinazi7b9278c2019-05-20 07:36:21 -0700776 StatelessConnectionTerminator terminator(server_connection_id, version,
777 helper_.get(),
778 time_wait_list_manager_.get());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500779 // This also adds the connection to time wait list.
fayang1de67892019-04-19 05:59:45 -0700780 terminator.CloseConnection(error_code, error_details,
781 format != GOOGLE_QUIC_PACKET);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500782 return;
783 }
784
785 QUIC_DVLOG(1)
dschinazi7b9278c2019-05-20 07:36:21 -0700786 << "Statelessly terminating " << server_connection_id
QUICHE teama6ef0a62019-03-07 20:34:33 -0500787 << " based on an ietf-long packet, which has an unsupported version:"
788 << version << ", error_code:" << error_code
789 << ", error_details:" << error_details;
790 // Version is unknown or unsupported by framer, send a version negotiation
791 // with an empty version list, which can be understood by the client.
792 std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
793 termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket(
dschinazib417d602019-05-29 13:08:45 -0700794 server_connection_id, EmptyQuicConnectionId(),
dschinazi48ac9192019-07-31 00:07:26 -0700795 /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix,
dschinazi1ac22cc2019-06-25 11:47:50 -0700796 /*versions=*/{}));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500797 time_wait_list_manager()->AddConnectionIdToTimeWait(
dschinazi7b9278c2019-05-20 07:36:21 -0700798 server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
QUICHE team6987b4a2019-03-15 16:23:04 -0700799 QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500800 &termination_packets);
801}
802
QUICHE teama6ef0a62019-03-07 20:34:33 -0500803bool QuicDispatcher::ShouldCreateSessionForUnknownVersion(
804 QuicVersionLabel /*version_label*/) {
805 return false;
806}
807
QUICHE teama6ef0a62019-03-07 20:34:33 -0500808void QuicDispatcher::OnExpiredPackets(
dschinazi7b9278c2019-05-20 07:36:21 -0700809 QuicConnectionId server_connection_id,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500810 BufferedPacketList early_arrived_packets) {
811 QUIC_CODE_COUNT(quic_reject_buffered_packets_expired);
812 StatelesslyTerminateConnection(
dschinazi7b9278c2019-05-20 07:36:21 -0700813 server_connection_id,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500814 early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET
815 : GOOGLE_QUIC_PACKET,
dschinazi48ac9192019-07-31 00:07:26 -0700816 /*version_flag=*/true,
817 early_arrived_packets.version.HasLengthPrefixedConnectionIds(),
818 early_arrived_packets.version, QUIC_HANDSHAKE_FAILED,
819 "Packets buffered for too long",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500820 quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
821}
822
823void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
824 // Reset the counter before starting creating connections.
825 new_sessions_allowed_per_event_loop_ = max_connections_to_create;
826 for (; new_sessions_allowed_per_event_loop_ > 0;
827 --new_sessions_allowed_per_event_loop_) {
dschinazi7b9278c2019-05-20 07:36:21 -0700828 QuicConnectionId server_connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500829 BufferedPacketList packet_list =
dschinazi7b9278c2019-05-20 07:36:21 -0700830 buffered_packets_.DeliverPacketsForNextConnection(
831 &server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500832 const std::list<BufferedPacket>& packets = packet_list.buffered_packets;
833 if (packets.empty()) {
834 return;
835 }
dschinazi7b9278c2019-05-20 07:36:21 -0700836 QuicConnectionId original_connection_id = server_connection_id;
837 server_connection_id = MaybeReplaceServerConnectionId(server_connection_id,
838 packet_list.version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500839 QuicSession* session =
dschinazi7b9278c2019-05-20 07:36:21 -0700840 CreateQuicSession(server_connection_id, packets.front().peer_address,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500841 packet_list.alpn, packet_list.version);
dschinazi7b9278c2019-05-20 07:36:21 -0700842 if (original_connection_id != server_connection_id) {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700843 session->connection()->AddIncomingConnectionId(original_connection_id);
dschinazi5c030852019-07-11 15:45:53 -0700844 session->connection()->InstallInitialCrypters(original_connection_id);
QUICHE teamc65d1d12019-03-19 20:58:04 -0700845 }
dschinazi7b9278c2019-05-20 07:36:21 -0700846 QUIC_DLOG(INFO) << "Created new session for " << server_connection_id;
dschinazi5c030852019-07-11 15:45:53 -0700847
848 DCHECK(session_map_.find(server_connection_id) == session_map_.end())
849 << "Tried to add session map existing entry " << server_connection_id;
850
dschinazi7b9278c2019-05-20 07:36:21 -0700851 session_map_.insert(
852 std::make_pair(server_connection_id, QuicWrapUnique(session)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500853 DeliverPacketsToSession(packets, session);
854 }
855}
856
857bool QuicDispatcher::HasChlosBuffered() const {
858 return buffered_packets_.HasChlosBuffered();
859}
860
861bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection(
fayang1ed1f762019-06-24 11:40:04 -0700862 const ReceivedPacketInfo& packet_info) {
dschinazi7b9278c2019-05-20 07:36:21 -0700863 QUIC_VLOG(1) << "Received packet from new connection "
fayang1ed1f762019-06-24 11:40:04 -0700864 << packet_info.destination_connection_id;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500865 return true;
866}
867
868// Return true if there is any packet buffered in the store.
dschinazi7b9278c2019-05-20 07:36:21 -0700869bool QuicDispatcher::HasBufferedPackets(QuicConnectionId server_connection_id) {
870 return buffered_packets_.HasBufferedPackets(server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500871}
872
dschinazi7b9278c2019-05-20 07:36:21 -0700873void QuicDispatcher::OnBufferPacketFailure(
874 EnqueuePacketResult result,
875 QuicConnectionId server_connection_id) {
876 QUIC_DLOG(INFO) << "Fail to buffer packet on connection "
877 << server_connection_id << " because of " << result;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500878}
879
QUICHE teama6ef0a62019-03-07 20:34:33 -0500880QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
881 return new QuicTimeWaitListManager(writer_.get(), this, helper_->GetClock(),
882 alarm_factory_.get());
883}
884
fayang1ed1f762019-06-24 11:40:04 -0700885void QuicDispatcher::BufferEarlyPacket(const ReceivedPacketInfo& packet_info) {
886 bool is_new_connection = !buffered_packets_.HasBufferedPackets(
887 packet_info.destination_connection_id);
888 if (is_new_connection &&
889 !ShouldCreateOrBufferPacketForConnection(packet_info)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500890 return;
891 }
892
893 EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
fayang1ed1f762019-06-24 11:40:04 -0700894 packet_info.destination_connection_id,
895 packet_info.form != GOOGLE_QUIC_PACKET, packet_info.packet,
896 packet_info.self_address, packet_info.peer_address, /*is_chlo=*/false,
897 /*alpn=*/"", packet_info.version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500898 if (rs != EnqueuePacketResult::SUCCESS) {
fayang1ed1f762019-06-24 11:40:04 -0700899 OnBufferPacketFailure(rs, packet_info.destination_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500900 }
901}
902
fayang1ed1f762019-06-24 11:40:04 -0700903void QuicDispatcher::ProcessChlo(const std::string& alpn,
904 ReceivedPacketInfo* packet_info) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500905 if (!accept_new_connections_) {
906 // Don't any create new connection.
907 QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections);
908 StatelesslyTerminateConnection(
fayang1ed1f762019-06-24 11:40:04 -0700909 packet_info->destination_connection_id, packet_info->form,
dschinazi48ac9192019-07-31 00:07:26 -0700910 /*version_flag=*/true, packet_info->use_length_prefix,
911 packet_info->version, QUIC_HANDSHAKE_FAILED,
fayang1ed1f762019-06-24 11:40:04 -0700912 "Stop accepting new connections",
QUICHE teama6ef0a62019-03-07 20:34:33 -0500913 quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
914 // Time wait list will reject the packet correspondingly.
915 time_wait_list_manager()->ProcessPacket(
fayang1ed1f762019-06-24 11:40:04 -0700916 packet_info->self_address, packet_info->peer_address,
917 packet_info->destination_connection_id, packet_info->form,
918 GetPerPacketContext());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500919 return;
920 }
fayang1ed1f762019-06-24 11:40:04 -0700921 if (!buffered_packets_.HasBufferedPackets(
922 packet_info->destination_connection_id) &&
923 !ShouldCreateOrBufferPacketForConnection(*packet_info)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500924 return;
925 }
danzh88e3e052019-06-13 11:47:18 -0700926 if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) &&
QUICHE teama6ef0a62019-03-07 20:34:33 -0500927 new_sessions_allowed_per_event_loop_ <= 0) {
928 // Can't create new session any more. Wait till next event loop.
fayang1ed1f762019-06-24 11:40:04 -0700929 QUIC_BUG_IF(buffered_packets_.HasChloForConnection(
930 packet_info->destination_connection_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500931 EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
fayang1ed1f762019-06-24 11:40:04 -0700932 packet_info->destination_connection_id,
933 packet_info->form != GOOGLE_QUIC_PACKET, packet_info->packet,
934 packet_info->self_address, packet_info->peer_address,
935 /*is_chlo=*/true, alpn, packet_info->version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500936 if (rs != EnqueuePacketResult::SUCCESS) {
fayang1ed1f762019-06-24 11:40:04 -0700937 OnBufferPacketFailure(rs, packet_info->destination_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500938 }
939 return;
940 }
QUICHE teamc65d1d12019-03-19 20:58:04 -0700941
fayang1ed1f762019-06-24 11:40:04 -0700942 QuicConnectionId original_connection_id =
943 packet_info->destination_connection_id;
944 packet_info->destination_connection_id = MaybeReplaceServerConnectionId(
945 original_connection_id, packet_info->version);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500946 // Creates a new session and process all buffered packets for this connection.
dschinazi7b9278c2019-05-20 07:36:21 -0700947 QuicSession* session =
fayang1ed1f762019-06-24 11:40:04 -0700948 CreateQuicSession(packet_info->destination_connection_id,
949 packet_info->peer_address, alpn, packet_info->version);
950 if (original_connection_id != packet_info->destination_connection_id) {
QUICHE teamc65d1d12019-03-19 20:58:04 -0700951 session->connection()->AddIncomingConnectionId(original_connection_id);
dschinazi5c030852019-07-11 15:45:53 -0700952 session->connection()->InstallInitialCrypters(original_connection_id);
QUICHE teamc65d1d12019-03-19 20:58:04 -0700953 }
dschinazi7b9278c2019-05-20 07:36:21 -0700954 QUIC_DLOG(INFO) << "Created new session for "
fayang1ed1f762019-06-24 11:40:04 -0700955 << packet_info->destination_connection_id;
dschinazi5c030852019-07-11 15:45:53 -0700956
957 DCHECK(session_map_.find(packet_info->destination_connection_id) ==
958 session_map_.end())
959 << "Tried to add session map existing entry "
960 << packet_info->destination_connection_id;
961
fayang1ed1f762019-06-24 11:40:04 -0700962 session_map_.insert(std::make_pair(packet_info->destination_connection_id,
963 QuicWrapUnique(session)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500964 std::list<BufferedPacket> packets =
fayang1ed1f762019-06-24 11:40:04 -0700965 buffered_packets_.DeliverPackets(packet_info->destination_connection_id)
dschinazi7b9278c2019-05-20 07:36:21 -0700966 .buffered_packets;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500967 // Process CHLO at first.
fayang1ed1f762019-06-24 11:40:04 -0700968 session->ProcessUdpPacket(packet_info->self_address,
969 packet_info->peer_address, packet_info->packet);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500970 // Deliver queued-up packets in the same order as they arrived.
971 // Do this even when flag is off because there might be still some packets
972 // buffered in the store before flag is turned off.
973 DeliverPacketsToSession(packets, session);
974 --new_sessions_allowed_per_event_loop_;
975}
976
QUICHE teama6ef0a62019-03-07 20:34:33 -0500977bool QuicDispatcher::ShouldDestroySessionAsynchronously() {
978 return true;
979}
980
981void QuicDispatcher::SetLastError(QuicErrorCode error) {
982 last_error_ = error;
983}
984
fayang91475c42019-06-19 08:04:26 -0700985bool QuicDispatcher::OnFailedToDispatchPacket(
fayang1ed1f762019-06-24 11:40:04 -0700986 const ReceivedPacketInfo& /*packet_info*/) {
fayang91475c42019-06-19 08:04:26 -0700987 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500988}
989
QUICHE teama6ef0a62019-03-07 20:34:33 -0500990const QuicTransportVersionVector&
991QuicDispatcher::GetSupportedTransportVersions() {
992 return version_manager_->GetSupportedTransportVersions();
993}
994
995const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() {
996 return version_manager_->GetSupportedVersions();
997}
998
999void QuicDispatcher::DeliverPacketsToSession(
1000 const std::list<BufferedPacket>& packets,
1001 QuicSession* session) {
1002 for (const BufferedPacket& packet : packets) {
1003 session->ProcessUdpPacket(packet.self_address, packet.peer_address,
1004 *(packet.packet));
1005 }
1006}
1007
fayangccbab732019-05-13 10:11:25 -07001008bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) {
fayangccbab732019-05-13 10:11:25 -07001009 for (const ParsedQuicVersion& supported_version :
1010 version_manager_->GetSupportedVersions()) {
1011 if (version == supported_version) {
1012 return true;
1013 }
1014 }
1015 return false;
QUICHE teama6ef0a62019-03-07 20:34:33 -05001016}
1017
fayangd057e662019-07-10 13:29:41 -07001018void QuicDispatcher::MaybeResetPacketsWithNoVersion(
1019 const ReceivedPacketInfo& packet_info) {
1020 DCHECK(!packet_info.version_flag);
1021 const size_t MinValidPacketLength =
1022 kPacketHeaderTypeSize + expected_server_connection_id_length_ +
1023 PACKET_1BYTE_PACKET_NUMBER + /*payload size=*/1 + /*tag size=*/12;
1024 if (packet_info.packet.length() < MinValidPacketLength) {
1025 // The packet size is too small.
1026 QUIC_CODE_COUNT(drop_too_small_packets);
1027 return;
1028 }
1029 // TODO(fayang): Consider rate limiting reset packets if reset packet size >
1030 // packet_length.
1031
1032 time_wait_list_manager()->SendPublicReset(
1033 packet_info.self_address, packet_info.peer_address,
1034 packet_info.destination_connection_id,
1035 packet_info.form != GOOGLE_QUIC_PACKET, GetPerPacketContext());
1036}
1037
QUICHE teama6ef0a62019-03-07 20:34:33 -05001038} // namespace quic