QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // 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 | |
vasilvv | 872e7a3 | 2019-03-12 16:42:44 -0700 | [diff] [blame] | 7 | #include <string> |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 10 | #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" |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 13 | #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 14 | #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" |
dschinazi | 76992e7 | 2019-07-17 20:40:40 -0700 | [diff] [blame] | 17 | #include "net/third_party/quiche/src/quic/core/quic_versions.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 18 | #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" |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 24 | #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" |
| 25 | #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 26 | |
| 27 | namespace quic { |
| 28 | |
| 29 | typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; |
| 30 | typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList; |
| 31 | typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult; |
| 32 | |
| 33 | namespace { |
| 34 | |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 35 | // Minimal INITIAL packet length sent by clients is 1200. |
| 36 | const QuicPacketLength kMinClientInitialPacketLength = 1200; |
| 37 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 38 | // An alarm that informs the QuicDispatcher to delete old sessions. |
| 39 | class DeleteSessionsAlarm : public QuicAlarm::Delegate { |
| 40 | public: |
| 41 | explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher) |
| 42 | : dispatcher_(dispatcher) {} |
| 43 | DeleteSessionsAlarm(const DeleteSessionsAlarm&) = delete; |
| 44 | DeleteSessionsAlarm& operator=(const DeleteSessionsAlarm&) = delete; |
| 45 | |
| 46 | void OnAlarm() override { dispatcher_->DeleteSessions(); } |
| 47 | |
| 48 | private: |
| 49 | // Not owned. |
| 50 | QuicDispatcher* dispatcher_; |
| 51 | }; |
| 52 | |
| 53 | // Collects packets serialized by a QuicPacketCreator in order |
| 54 | // to be handed off to the time wait list manager. |
| 55 | class PacketCollector : public QuicPacketCreator::DelegateInterface, |
| 56 | public QuicStreamFrameDataProducer { |
| 57 | public: |
| 58 | explicit PacketCollector(QuicBufferAllocator* allocator) |
| 59 | : send_buffer_(allocator) {} |
| 60 | ~PacketCollector() override = default; |
| 61 | |
| 62 | // QuicPacketCreator::DelegateInterface methods: |
| 63 | void OnSerializedPacket(SerializedPacket* serialized_packet) override { |
| 64 | // Make a copy of the serialized packet to send later. |
| 65 | packets_.emplace_back( |
| 66 | new QuicEncryptedPacket(CopyBuffer(*serialized_packet), |
| 67 | serialized_packet->encrypted_length, true)); |
| 68 | serialized_packet->encrypted_buffer = nullptr; |
| 69 | DeleteFrames(&(serialized_packet->retransmittable_frames)); |
| 70 | serialized_packet->retransmittable_frames.clear(); |
| 71 | } |
| 72 | |
| 73 | char* GetPacketBuffer() override { |
| 74 | // Let QuicPacketCreator to serialize packets on stack buffer. |
| 75 | return nullptr; |
| 76 | } |
| 77 | |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 78 | void OnUnrecoverableError(QuicErrorCode /*error*/, |
| 79 | const std::string& /*error_details*/) override {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 80 | |
fayang | cad1179 | 2019-09-16 13:11:44 -0700 | [diff] [blame] | 81 | bool ShouldGeneratePacket(HasRetransmittableData /*retransmittable*/, |
| 82 | IsHandshake /*handshake*/) override { |
| 83 | DCHECK(false); |
| 84 | return true; |
| 85 | } |
| 86 | |
| 87 | const QuicFrames MaybeBundleAckOpportunistically() override { |
| 88 | DCHECK(false); |
| 89 | return {}; |
| 90 | } |
| 91 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 92 | // QuicStreamFrameDataProducer |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 93 | WriteStreamDataResult WriteStreamData(QuicStreamId /*id*/, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 94 | QuicStreamOffset offset, |
| 95 | QuicByteCount data_length, |
| 96 | QuicDataWriter* writer) override { |
| 97 | if (send_buffer_.WriteStreamData(offset, data_length, writer)) { |
| 98 | return WRITE_SUCCESS; |
| 99 | } |
| 100 | return WRITE_FAILED; |
| 101 | } |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 102 | bool WriteCryptoData(EncryptionLevel /*level*/, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 103 | QuicStreamOffset offset, |
| 104 | QuicByteCount data_length, |
| 105 | QuicDataWriter* writer) override { |
| 106 | return send_buffer_.WriteStreamData(offset, data_length, writer); |
| 107 | } |
| 108 | |
| 109 | std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() { |
| 110 | return &packets_; |
| 111 | } |
| 112 | |
| 113 | private: |
| 114 | std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_; |
| 115 | // This is only needed until the packets are encrypted. Once packets are |
| 116 | // encrypted, the stream data is no longer required. |
| 117 | QuicStreamSendBuffer send_buffer_; |
| 118 | }; |
| 119 | |
| 120 | // Helper for statelessly closing connections by generating the |
| 121 | // correct termination packets and adding the connection to the time wait |
| 122 | // list manager. |
| 123 | class StatelessConnectionTerminator { |
| 124 | public: |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 125 | StatelessConnectionTerminator(QuicConnectionId server_connection_id, |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 126 | const ParsedQuicVersion version, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 127 | QuicConnectionHelperInterface* helper, |
| 128 | QuicTimeWaitListManager* time_wait_list_manager) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 129 | : server_connection_id_(server_connection_id), |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 130 | framer_(ParsedQuicVersionVector{version}, |
| 131 | /*unused*/ QuicTime::Zero(), |
| 132 | Perspective::IS_SERVER, |
| 133 | /*unused*/ kQuicDefaultConnectionIdLength), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 134 | collector_(helper->GetStreamSendBufferAllocator()), |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 135 | creator_(server_connection_id, &framer_, &collector_), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 136 | time_wait_list_manager_(time_wait_list_manager) { |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 137 | framer_.set_data_producer(&collector_); |
nharper | ba30761 | 2019-11-11 16:56:17 -0800 | [diff] [blame] | 138 | framer_.SetInitialObfuscators(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 139 | } |
| 140 | |
| 141 | ~StatelessConnectionTerminator() { |
| 142 | // Clear framer's producer. |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 143 | framer_.set_data_producer(nullptr); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 144 | } |
| 145 | |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 146 | // Serializes a packet containing CONNECTION_CLOSE frame and send it (without |
| 147 | // adding connection to the time wait). |
| 148 | void StatelesslyCloseConnection(const QuicSocketAddress& self_address, |
| 149 | const QuicSocketAddress& peer_address, |
| 150 | QuicErrorCode error_code, |
| 151 | const std::string& error_details) { |
rch | 9d76c2d | 2019-12-20 12:19:48 -0800 | [diff] [blame] | 152 | // TODO(rch): Remove this method when quic_drop_small_initial_packets is |
| 153 | // deprecated. |
| 154 | DCHECK(!GetQuicReloadableFlag(quic_drop_small_initial_packets)); |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 155 | SerializeConnectionClosePacket(error_code, error_details); |
| 156 | |
| 157 | for (const auto& packet : *collector_.packets()) { |
| 158 | time_wait_list_manager_->SendPacket(self_address, peer_address, *packet); |
| 159 | } |
| 160 | } |
| 161 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 162 | // Generates a packet containing a CONNECTION_CLOSE frame specifying |
| 163 | // |error_code| and |error_details| and add the connection to time wait. |
| 164 | void CloseConnection(QuicErrorCode error_code, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 165 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 166 | bool ietf_quic) { |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 167 | SerializeConnectionClosePacket(error_code, error_details); |
| 168 | |
| 169 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
| 170 | server_connection_id_, ietf_quic, |
| 171 | QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, |
| 172 | quic::ENCRYPTION_INITIAL, collector_.packets()); |
| 173 | } |
| 174 | |
| 175 | private: |
| 176 | void SerializeConnectionClosePacket(QuicErrorCode error_code, |
| 177 | const std::string& error_details) { |
fkastenholz | 591814c | 2019-09-06 12:11:46 -0700 | [diff] [blame] | 178 | QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame( |
| 179 | framer_.transport_version(), error_code, error_details, |
| 180 | /*transport_close_frame_type=*/0); |
fkastenholz | 72f509b | 2019-04-10 09:17:49 -0700 | [diff] [blame] | 181 | |
renjietang | b63005e | 2019-11-19 23:08:53 -0800 | [diff] [blame] | 182 | if (!creator_.AddFrame(QuicFrame(frame), NOT_RETRANSMISSION)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 183 | QUIC_BUG << "Unable to add frame to an empty packet"; |
| 184 | delete frame; |
| 185 | return; |
| 186 | } |
fayang | 62b637b | 2019-09-16 08:40:49 -0700 | [diff] [blame] | 187 | creator_.FlushCurrentPacket(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 188 | DCHECK_EQ(1u, collector_.packets()->size()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 189 | } |
| 190 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 191 | QuicConnectionId server_connection_id_; |
fayang | f7c569c | 2019-05-07 11:56:51 -0700 | [diff] [blame] | 192 | QuicFramer framer_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 193 | // Set as the visitor of |creator_| to collect any generated packets. |
| 194 | PacketCollector collector_; |
| 195 | QuicPacketCreator creator_; |
| 196 | QuicTimeWaitListManager* time_wait_list_manager_; |
| 197 | }; |
| 198 | |
| 199 | // Class which extracts the ALPN from a CHLO packet. |
| 200 | class ChloAlpnExtractor : public ChloExtractor::Delegate { |
| 201 | public: |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 202 | void OnChlo(QuicTransportVersion /*version*/, |
| 203 | QuicConnectionId /*server_connection_id*/, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 204 | const CryptoHandshakeMessage& chlo) override { |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 205 | quiche::QuicheStringPiece alpn_value; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 206 | if (chlo.GetStringPiece(kALPN, &alpn_value)) { |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 207 | alpn_ = std::string(alpn_value); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 208 | } |
| 209 | } |
| 210 | |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 211 | std::string&& ConsumeAlpn() { return std::move(alpn_); } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 212 | |
| 213 | private: |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 214 | std::string alpn_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 215 | }; |
| 216 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 217 | } // namespace |
| 218 | |
| 219 | QuicDispatcher::QuicDispatcher( |
| 220 | const QuicConfig* config, |
| 221 | const QuicCryptoServerConfig* crypto_config, |
| 222 | QuicVersionManager* version_manager, |
| 223 | std::unique_ptr<QuicConnectionHelperInterface> helper, |
| 224 | std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, |
| 225 | std::unique_ptr<QuicAlarmFactory> alarm_factory, |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 226 | uint8_t expected_server_connection_id_length) |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 227 | : config_(config), |
| 228 | crypto_config_(crypto_config), |
| 229 | compressed_certs_cache_( |
| 230 | QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), |
| 231 | helper_(std::move(helper)), |
| 232 | session_helper_(std::move(session_helper)), |
| 233 | alarm_factory_(std::move(alarm_factory)), |
| 234 | delete_sessions_alarm_( |
| 235 | alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))), |
| 236 | buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 237 | version_manager_(version_manager), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 238 | last_error_(QUIC_NO_ERROR), |
| 239 | new_sessions_allowed_per_event_loop_(0u), |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 240 | accept_new_connections_(true), |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 241 | allow_short_initial_server_connection_ids_(false), |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 242 | expected_server_connection_id_length_( |
| 243 | expected_server_connection_id_length), |
dschinazi | c5589bd | 2019-09-12 14:50:11 -0700 | [diff] [blame] | 244 | should_update_expected_server_connection_id_length_(false) { |
dschinazi | 4101ead | 2019-12-06 15:26:07 -0800 | [diff] [blame] | 245 | QUIC_BUG_IF(GetSupportedVersions().empty()) |
| 246 | << "Trying to create dispatcher without any supported versions"; |
dschinazi | c5589bd | 2019-09-12 14:50:11 -0700 | [diff] [blame] | 247 | QUIC_DLOG(INFO) << "Created QuicDispatcher with versions: " |
| 248 | << ParsedQuicVersionVectorToString(GetSupportedVersions()); |
| 249 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 250 | |
| 251 | QuicDispatcher::~QuicDispatcher() { |
| 252 | session_map_.clear(); |
| 253 | closed_session_list_.clear(); |
| 254 | } |
| 255 | |
| 256 | void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) { |
| 257 | DCHECK(writer_ == nullptr); |
| 258 | writer_.reset(writer); |
| 259 | time_wait_list_manager_.reset(CreateQuicTimeWaitListManager()); |
| 260 | } |
| 261 | |
| 262 | void QuicDispatcher::ProcessPacket(const QuicSocketAddress& self_address, |
| 263 | const QuicSocketAddress& peer_address, |
| 264 | const QuicReceivedPacket& packet) { |
dschinazi | 965ce09 | 2019-05-23 06:29:01 -0700 | [diff] [blame] | 265 | QUIC_DVLOG(2) << "Dispatcher received encrypted " << packet.length() |
| 266 | << " bytes:" << std::endl |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 267 | << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece( |
| 268 | packet.data(), packet.length())); |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 269 | ReceivedPacketInfo packet_info(self_address, peer_address, packet); |
fayang | 1f12350 | 2019-05-14 08:05:16 -0700 | [diff] [blame] | 270 | std::string detailed_error; |
dschinazi | bf0413d | 2019-10-07 14:19:53 -0700 | [diff] [blame] | 271 | bool retry_token_present; |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 272 | quiche::QuicheStringPiece retry_token; |
dschinazi | bf0413d | 2019-10-07 14:19:53 -0700 | [diff] [blame] | 273 | const QuicErrorCode error = QuicFramer::ParsePublicHeaderDispatcher( |
| 274 | packet, expected_server_connection_id_length_, &packet_info.form, |
| 275 | &packet_info.long_packet_type, &packet_info.version_flag, |
| 276 | &packet_info.use_length_prefix, &packet_info.version_label, |
| 277 | &packet_info.version, &packet_info.destination_connection_id, |
| 278 | &packet_info.source_connection_id, &retry_token_present, &retry_token, |
| 279 | &detailed_error); |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 280 | if (error != QUIC_NO_ERROR) { |
| 281 | // Packet has framing error. |
| 282 | SetLastError(error); |
| 283 | QUIC_DLOG(ERROR) << detailed_error; |
| 284 | return; |
| 285 | } |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 286 | if (packet_info.destination_connection_id.length() != |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 287 | expected_server_connection_id_length_ && |
| 288 | !should_update_expected_server_connection_id_length_ && |
dschinazi | 97da52b | 2020-01-13 15:44:43 -0800 | [diff] [blame] | 289 | packet_info.version.IsKnown() && |
| 290 | !packet_info.version.AllowsVariableLengthConnectionIds()) { |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 291 | SetLastError(QUIC_INVALID_PACKET_HEADER); |
| 292 | QUIC_DLOG(ERROR) << "Invalid Connection Id Length"; |
| 293 | return; |
| 294 | } |
dschinazi | b953d02 | 2019-08-01 18:05:58 -0700 | [diff] [blame] | 295 | |
| 296 | if (packet_info.version_flag && IsSupportedVersion(packet_info.version)) { |
| 297 | if (!QuicUtils::IsConnectionIdValidForVersion( |
| 298 | packet_info.destination_connection_id, |
| 299 | packet_info.version.transport_version)) { |
| 300 | SetLastError(QUIC_INVALID_PACKET_HEADER); |
| 301 | QUIC_DLOG(ERROR) |
| 302 | << "Invalid destination connection ID length for version"; |
| 303 | return; |
| 304 | } |
| 305 | if (packet_info.version.SupportsClientConnectionIds() && |
| 306 | !QuicUtils::IsConnectionIdValidForVersion( |
| 307 | packet_info.source_connection_id, |
| 308 | packet_info.version.transport_version)) { |
| 309 | SetLastError(QUIC_INVALID_PACKET_HEADER); |
| 310 | QUIC_DLOG(ERROR) << "Invalid source connection ID length for version"; |
| 311 | return; |
| 312 | } |
| 313 | } |
| 314 | |
dschinazi | 8ff7482 | 2019-05-28 16:37:20 -0700 | [diff] [blame] | 315 | if (should_update_expected_server_connection_id_length_) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 316 | expected_server_connection_id_length_ = |
| 317 | packet_info.destination_connection_id.length(); |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 318 | } |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 319 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 320 | if (MaybeDispatchPacket(packet_info)) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 321 | // Packet has been dropped or successfully dispatched, stop processing. |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 322 | return; |
| 323 | } |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 324 | ProcessHeader(&packet_info); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 325 | } |
| 326 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 327 | QuicConnectionId QuicDispatcher::MaybeReplaceServerConnectionId( |
| 328 | QuicConnectionId server_connection_id, |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 329 | ParsedQuicVersion version) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 330 | if (server_connection_id.length() == expected_server_connection_id_length_) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 331 | return server_connection_id; |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 332 | } |
dschinazi | 97da52b | 2020-01-13 15:44:43 -0800 | [diff] [blame] | 333 | DCHECK(version.AllowsVariableLengthConnectionIds()); |
dschinazi | adc7507 | 2019-08-19 10:54:45 -0700 | [diff] [blame] | 334 | |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 335 | QuicConnectionId new_connection_id = |
wub | 662a3d6 | 2019-08-16 14:10:50 -0700 | [diff] [blame] | 336 | GenerateNewServerConnectionId(version, server_connection_id); |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 337 | DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length()); |
dschinazi | 28c1bf3 | 2019-08-19 11:54:46 -0700 | [diff] [blame] | 338 | |
| 339 | // Verify that GenerateNewServerConnectionId is deterministic. |
| 340 | DCHECK_EQ(new_connection_id, |
| 341 | GenerateNewServerConnectionId(version, server_connection_id)); |
| 342 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 343 | QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 344 | << " with " << new_connection_id; |
| 345 | return new_connection_id; |
| 346 | } |
| 347 | |
wub | 662a3d6 | 2019-08-16 14:10:50 -0700 | [diff] [blame] | 348 | QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId( |
| 349 | ParsedQuicVersion /*version*/, |
dschinazi | adc7507 | 2019-08-19 10:54:45 -0700 | [diff] [blame] | 350 | QuicConnectionId connection_id) const { |
dschinazi | adc7507 | 2019-08-19 10:54:45 -0700 | [diff] [blame] | 351 | return QuicUtils::CreateReplacementConnectionId(connection_id); |
wub | 662a3d6 | 2019-08-16 14:10:50 -0700 | [diff] [blame] | 352 | } |
| 353 | |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 354 | bool QuicDispatcher::MaybeDispatchPacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 355 | const ReceivedPacketInfo& packet_info) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 356 | // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC. |
| 357 | // Given that we can't even send a reply rejecting the packet, just drop the |
| 358 | // packet. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 359 | if (packet_info.peer_address.port() == 0) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 360 | return true; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 361 | } |
| 362 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 363 | QuicConnectionId server_connection_id = packet_info.destination_connection_id; |
QUICHE team | 8e2e453 | 2019-03-14 14:37:56 -0700 | [diff] [blame] | 364 | |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 365 | // The IETF spec requires the client to generate an initial server |
| 366 | // connection ID that is at least 64 bits long. After that initial |
| 367 | // connection ID, the dispatcher picks a new one of its expected length. |
| 368 | // Therefore we should never receive a connection ID that is smaller |
| 369 | // than 64 bits and smaller than what we expect. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 370 | if (server_connection_id.length() < kQuicMinimumInitialConnectionIdLength && |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 371 | server_connection_id.length() < expected_server_connection_id_length_ && |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 372 | !allow_short_initial_server_connection_ids_) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 373 | DCHECK(packet_info.version_flag); |
dschinazi | 97da52b | 2020-01-13 15:44:43 -0800 | [diff] [blame] | 374 | DCHECK(packet_info.version.AllowsVariableLengthConnectionIds()); |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 375 | QUIC_DLOG(INFO) << "Packet with short destination connection ID " |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 376 | << server_connection_id << " expected " |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 377 | << static_cast<int>(expected_server_connection_id_length_); |
dschinazi | 95025bf | 2019-09-06 15:08:47 -0700 | [diff] [blame] | 378 | // Drop the packet silently. |
| 379 | QUIC_CODE_COUNT(quic_dropped_invalid_small_initial_connection_id); |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 380 | return true; |
QUICHE team | 963d57e | 2019-03-21 10:58:47 -0700 | [diff] [blame] | 381 | } |
| 382 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 383 | // Packets with connection IDs for active connections are processed |
| 384 | // immediately. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 385 | auto it = session_map_.find(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 386 | if (it != session_map_.end()) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 387 | DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 388 | it->second->ProcessUdpPacket(packet_info.self_address, |
| 389 | packet_info.peer_address, packet_info.packet); |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 390 | return true; |
dschinazi | cc5a54c | 2019-09-24 08:30:14 -0700 | [diff] [blame] | 391 | } else if (packet_info.version.transport_version != |
| 392 | QUIC_VERSION_UNSUPPORTED) { |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 393 | // We did not find the connection ID, check if we've replaced it. |
dschinazi | cc5a54c | 2019-09-24 08:30:14 -0700 | [diff] [blame] | 394 | // This is only performed for supported versions because packets with |
| 395 | // unsupported versions can flow through this function in order to send |
| 396 | // a version negotiation packet, but we know that their connection ID |
| 397 | // did not get replaced since that is performed on connection creation, |
| 398 | // and that only happens for known verions. |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 399 | QuicConnectionId replaced_connection_id = MaybeReplaceServerConnectionId( |
| 400 | server_connection_id, packet_info.version); |
| 401 | if (replaced_connection_id != server_connection_id) { |
| 402 | // Search for the replacement. |
| 403 | auto it2 = session_map_.find(replaced_connection_id); |
| 404 | if (it2 != session_map_.end()) { |
| 405 | DCHECK(!buffered_packets_.HasBufferedPackets(replaced_connection_id)); |
| 406 | it2->second->ProcessUdpPacket(packet_info.self_address, |
| 407 | packet_info.peer_address, |
| 408 | packet_info.packet); |
| 409 | return true; |
| 410 | } |
| 411 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 412 | } |
| 413 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 414 | if (buffered_packets_.HasChloForConnection(server_connection_id)) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 415 | BufferEarlyPacket(packet_info); |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 416 | return true; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 417 | } |
| 418 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 419 | if (OnFailedToDispatchPacket(packet_info)) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 420 | return true; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 421 | } |
| 422 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 423 | if (time_wait_list_manager_->IsConnectionIdInTimeWait(server_connection_id)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 424 | // This connection ID is already in time-wait state. |
| 425 | time_wait_list_manager_->ProcessPacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 426 | packet_info.self_address, packet_info.peer_address, |
| 427 | packet_info.destination_connection_id, packet_info.form, |
| 428 | GetPerPacketContext()); |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 429 | return true; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 430 | } |
| 431 | |
| 432 | // The packet has an unknown connection ID. |
| 433 | |
| 434 | // Unless the packet provides a version, assume that we can continue |
| 435 | // processing using our preferred version. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 436 | if (packet_info.version_flag) { |
| 437 | if (!IsSupportedVersion(packet_info.version)) { |
| 438 | if (ShouldCreateSessionForUnknownVersion(packet_info.version_label)) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 439 | return false; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 440 | } |
| 441 | if (!crypto_config()->validate_chlo_size() || |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 442 | packet_info.packet.length() >= kMinPacketSizeForVersionNegotiation) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 443 | // Since the version is not supported, send a version negotiation |
| 444 | // packet and stop processing the current packet. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 445 | QuicConnectionId client_connection_id = |
| 446 | packet_info.source_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 447 | time_wait_list_manager()->SendVersionNegotiationPacket( |
dschinazi | 346b7ce | 2019-06-05 01:38:18 -0700 | [diff] [blame] | 448 | server_connection_id, client_connection_id, |
dschinazi | bf6a783 | 2019-10-08 18:03:52 -0700 | [diff] [blame] | 449 | packet_info.form != GOOGLE_QUIC_PACKET, |
| 450 | packet_info.use_length_prefix, GetSupportedVersions(), |
| 451 | packet_info.self_address, packet_info.peer_address, |
| 452 | GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 453 | } |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 454 | return true; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 455 | } |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 456 | |
fayang | 12512a8 | 2019-11-04 11:34:39 -0800 | [diff] [blame] | 457 | if (crypto_config()->validate_chlo_size() && |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 458 | packet_info.form == IETF_QUIC_LONG_HEADER_PACKET && |
| 459 | packet_info.long_packet_type == INITIAL && |
| 460 | packet_info.packet.length() < kMinClientInitialPacketLength) { |
rch | 9d76c2d | 2019-12-20 12:19:48 -0800 | [diff] [blame] | 461 | if (GetQuicReloadableFlag(quic_drop_small_initial_packets)) { |
| 462 | QUIC_DVLOG(1) << "Dropping initial packet which is too short, length: " |
| 463 | << packet_info.packet.length(); |
| 464 | QUIC_CODE_COUNT(quic_drop_small_initial_packets); |
| 465 | QUIC_RELOADABLE_FLAG_COUNT(quic_drop_small_initial_packets); |
| 466 | return true; |
| 467 | } |
fayang | e3f2f7b | 2019-09-19 17:01:57 -0700 | [diff] [blame] | 468 | StatelessConnectionTerminator terminator( |
| 469 | packet_info.destination_connection_id, packet_info.version, |
| 470 | helper_.get(), time_wait_list_manager_.get()); |
| 471 | QUIC_DVLOG(1) << "Initial packet too small: " |
| 472 | << packet_info.packet.length(); |
| 473 | terminator.StatelesslyCloseConnection( |
| 474 | packet_info.self_address, packet_info.peer_address, |
| 475 | IETF_QUIC_PROTOCOL_VIOLATION, "Initial packet too small"); |
| 476 | return true; |
| 477 | } |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 478 | } |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 479 | |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 480 | return false; |
| 481 | } |
| 482 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 483 | void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { |
| 484 | QuicConnectionId server_connection_id = |
| 485 | packet_info->destination_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 486 | // Packet's connection ID is unknown. Apply the validity checks. |
wub | 2a5670f | 2019-06-13 13:39:16 -0700 | [diff] [blame] | 487 | // TODO(wub): Determine the fate completely in ValidityChecks, then call |
| 488 | // ProcessUnauthenticatedHeaderFate in one place. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 489 | QuicPacketFate fate = ValidityChecks(*packet_info); |
fayang | 17230ac | 2019-06-21 06:28:28 -0700 | [diff] [blame] | 490 | ChloAlpnExtractor alpn_extractor; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 491 | switch (fate) { |
dschinazi | 76992e7 | 2019-07-17 20:40:40 -0700 | [diff] [blame] | 492 | case kFateProcess: { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 493 | if (packet_info->version.handshake_protocol == PROTOCOL_TLS1_3) { |
fayang | 17230ac | 2019-06-21 06:28:28 -0700 | [diff] [blame] | 494 | // TODO(nharper): Support buffering non-ClientHello packets when using |
| 495 | // TLS. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 496 | ProcessChlo(/*alpn=*/"", packet_info); |
fayang | 17230ac | 2019-06-21 06:28:28 -0700 | [diff] [blame] | 497 | break; |
| 498 | } |
| 499 | if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) && |
dschinazi | 4fd8cb1 | 2019-09-09 16:31:06 -0700 | [diff] [blame] | 500 | !ChloExtractor::Extract(packet_info->packet, packet_info->version, |
fayang | 17230ac | 2019-06-21 06:28:28 -0700 | [diff] [blame] | 501 | config_->create_session_tag_indicators(), |
| 502 | &alpn_extractor, |
| 503 | server_connection_id.length())) { |
| 504 | // Buffer non-CHLO packets. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 505 | BufferEarlyPacket(*packet_info); |
fayang | 17230ac | 2019-06-21 06:28:28 -0700 | [diff] [blame] | 506 | break; |
| 507 | } |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 508 | ProcessChlo(alpn_extractor.ConsumeAlpn(), packet_info); |
dschinazi | 76992e7 | 2019-07-17 20:40:40 -0700 | [diff] [blame] | 509 | } break; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 510 | case kFateTimeWait: |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 511 | // Add this connection_id to the time-wait state, to safely reject |
| 512 | // future packets. |
| 513 | QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id |
| 514 | << " to time-wait list."; |
| 515 | QUIC_CODE_COUNT(quic_reject_fate_time_wait); |
| 516 | StatelesslyTerminateConnection( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 517 | server_connection_id, packet_info->form, packet_info->version_flag, |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 518 | packet_info->use_length_prefix, packet_info->version, |
| 519 | QUIC_HANDSHAKE_FAILED, "Reject connection", |
wub | 0a4b9c5 | 2019-05-28 13:18:58 -0700 | [diff] [blame] | 520 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 521 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 522 | DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( |
| 523 | server_connection_id)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 524 | time_wait_list_manager_->ProcessPacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 525 | packet_info->self_address, packet_info->peer_address, |
| 526 | server_connection_id, packet_info->form, GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 527 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 528 | buffered_packets_.DiscardPackets(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 529 | break; |
fayang | d057e66 | 2019-07-10 13:29:41 -0700 | [diff] [blame] | 530 | case kFateDrop: |
| 531 | break; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 532 | } |
| 533 | } |
| 534 | |
| 535 | QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 536 | const ReceivedPacketInfo& packet_info) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 537 | if (!packet_info.version_flag) { |
dschinazi | 5b236be | 2019-08-19 14:55:22 -0700 | [diff] [blame] | 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 | } |
dschinazi | 5b236be | 2019-08-19 14:55:22 -0700 | [diff] [blame] | 565 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 566 | QUIC_DLOG(INFO) |
| 567 | << "Packet without version arrived for unknown connection ID " |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 568 | << packet_info.destination_connection_id; |
fayang | 9d6231c | 2019-12-04 07:10:13 -0800 | [diff] [blame] | 569 | MaybeResetPacketsWithNoVersion(packet_info); |
| 570 | return kFateDrop; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 571 | } |
| 572 | |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 573 | // Let the connection parse and validate packet number. |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 574 | return kFateProcess; |
| 575 | } |
| 576 | |
| 577 | void QuicDispatcher::CleanUpSession(SessionMap::iterator it, |
| 578 | QuicConnection* connection, |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 579 | ConnectionCloseSource /*source*/) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 580 | write_blocked_list_.erase(connection); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 581 | QuicTimeWaitListManager::TimeWaitAction action = |
| 582 | QuicTimeWaitListManager::SEND_STATELESS_RESET; |
| 583 | if (connection->termination_packets() != nullptr && |
| 584 | !connection->termination_packets()->empty()) { |
| 585 | action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; |
fayang | 51c2373 | 2019-06-24 06:59:55 -0700 | [diff] [blame] | 586 | } else { |
fayang | fa3b1d6 | 2019-11-18 08:02:13 -0800 | [diff] [blame] | 587 | if (!connection->IsHandshakeComplete()) { |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 588 | if (!VersionHasIetfInvariantHeader(connection->transport_version())) { |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 589 | QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed); |
| 590 | } else { |
| 591 | QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed); |
| 592 | } |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 593 | action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS; |
| 594 | // This serializes a connection close termination packet with error code |
| 595 | // QUIC_HANDSHAKE_FAILED and adds the connection to the time wait list. |
| 596 | StatelesslyTerminateConnection( |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 597 | connection->connection_id(), |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 598 | VersionHasIetfInvariantHeader(connection->transport_version()) |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 599 | ? IETF_QUIC_LONG_HEADER_PACKET |
| 600 | : GOOGLE_QUIC_PACKET, |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 601 | /*version_flag=*/true, |
| 602 | connection->version().HasLengthPrefixedConnectionIds(), |
| 603 | connection->version(), QUIC_HANDSHAKE_FAILED, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 604 | "Connection is closed by server before handshake confirmed", |
| 605 | // Although it is our intention to send termination packets, the |
| 606 | // |action| argument is not used by this call to |
| 607 | // StatelesslyTerminateConnection(). |
| 608 | action); |
| 609 | session_map_.erase(it); |
| 610 | return; |
| 611 | } |
| 612 | QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_stateless_reset); |
| 613 | } |
| 614 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
fayang | d4291e4 | 2019-05-30 10:31:21 -0700 | [diff] [blame] | 615 | it->first, VersionHasIetfInvariantHeader(connection->transport_version()), |
| 616 | action, connection->encryption_level(), |
| 617 | connection->termination_packets()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 618 | session_map_.erase(it); |
| 619 | } |
| 620 | |
| 621 | void QuicDispatcher::StopAcceptingNewConnections() { |
| 622 | accept_new_connections_ = false; |
| 623 | } |
| 624 | |
| 625 | std::unique_ptr<QuicPerPacketContext> QuicDispatcher::GetPerPacketContext() |
| 626 | const { |
| 627 | return nullptr; |
| 628 | } |
| 629 | |
| 630 | void QuicDispatcher::DeleteSessions() { |
QUICHE team | aa1d6a8 | 2019-03-13 09:14:13 -0700 | [diff] [blame] | 631 | if (!write_blocked_list_.empty()) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 632 | for (const std::unique_ptr<QuicSession>& session : closed_session_list_) { |
| 633 | if (write_blocked_list_.erase(session->connection()) != 0) { |
| 634 | QUIC_BUG << "QuicConnection was in WriteBlockedList before destruction"; |
| 635 | } |
| 636 | } |
| 637 | } |
| 638 | closed_session_list_.clear(); |
| 639 | } |
| 640 | |
| 641 | void QuicDispatcher::OnCanWrite() { |
| 642 | // The socket is now writable. |
| 643 | writer_->SetWritable(); |
| 644 | |
| 645 | // Move every blocked writer in |write_blocked_list_| to a temporary list. |
| 646 | const size_t num_blocked_writers_before = write_blocked_list_.size(); |
| 647 | WriteBlockedList temp_list; |
| 648 | temp_list.swap(write_blocked_list_); |
| 649 | DCHECK(write_blocked_list_.empty()); |
| 650 | |
| 651 | // Give each blocked writer a chance to write what they indended to write. |
| 652 | // If they are blocked again, they will call |OnWriteBlocked| to add |
| 653 | // themselves back into |write_blocked_list_|. |
| 654 | while (!temp_list.empty()) { |
| 655 | QuicBlockedWriterInterface* blocked_writer = temp_list.begin()->first; |
| 656 | temp_list.erase(temp_list.begin()); |
| 657 | blocked_writer->OnBlockedWriterCanWrite(); |
| 658 | } |
| 659 | const size_t num_blocked_writers_after = write_blocked_list_.size(); |
| 660 | if (num_blocked_writers_after != 0) { |
| 661 | if (num_blocked_writers_before == num_blocked_writers_after) { |
| 662 | QUIC_CODE_COUNT(quic_zero_progress_on_can_write); |
| 663 | } else { |
| 664 | QUIC_CODE_COUNT(quic_blocked_again_on_can_write); |
| 665 | } |
| 666 | } |
| 667 | } |
| 668 | |
| 669 | bool QuicDispatcher::HasPendingWrites() const { |
| 670 | return !write_blocked_list_.empty(); |
| 671 | } |
| 672 | |
| 673 | void QuicDispatcher::Shutdown() { |
| 674 | while (!session_map_.empty()) { |
| 675 | QuicSession* session = session_map_.begin()->second.get(); |
| 676 | session->connection()->CloseConnection( |
| 677 | QUIC_PEER_GOING_AWAY, "Server shutdown imminent", |
| 678 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 679 | // Validate that the session removes itself from the session map on close. |
| 680 | DCHECK(session_map_.empty() || |
| 681 | session_map_.begin()->second.get() != session); |
| 682 | } |
| 683 | DeleteSessions(); |
| 684 | } |
| 685 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 686 | void QuicDispatcher::OnConnectionClosed(QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 687 | QuicErrorCode error, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 688 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 689 | ConnectionCloseSource source) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 690 | auto it = session_map_.find(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 691 | if (it == session_map_.end()) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 692 | QUIC_BUG << "ConnectionId " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 693 | << " does not exist in the session map. Error: " |
| 694 | << QuicErrorCodeToString(error); |
| 695 | QUIC_BUG << QuicStackTrace(); |
| 696 | return; |
| 697 | } |
| 698 | |
| 699 | QUIC_DLOG_IF(INFO, error != QUIC_NO_ERROR) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 700 | << "Closing connection (" << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 701 | << ") due to error: " << QuicErrorCodeToString(error) |
| 702 | << ", with details: " << error_details; |
| 703 | |
| 704 | QuicConnection* connection = it->second->connection(); |
| 705 | if (ShouldDestroySessionAsynchronously()) { |
| 706 | // Set up alarm to fire immediately to bring destruction of this session |
| 707 | // out of current call stack. |
| 708 | if (closed_session_list_.empty()) { |
| 709 | delete_sessions_alarm_->Update(helper()->GetClock()->ApproximateNow(), |
| 710 | QuicTime::Delta::Zero()); |
| 711 | } |
| 712 | closed_session_list_.push_back(std::move(it->second)); |
| 713 | } |
wub | 5f64ec4 | 2019-06-06 07:31:19 -0700 | [diff] [blame] | 714 | CleanUpSession(it, connection, source); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 715 | } |
| 716 | |
| 717 | void QuicDispatcher::OnWriteBlocked( |
| 718 | QuicBlockedWriterInterface* blocked_writer) { |
| 719 | if (!blocked_writer->IsWriterBlocked()) { |
| 720 | // It is a programming error if this ever happens. When we are sure it is |
| 721 | // not happening, replace it with a DCHECK. |
| 722 | QUIC_BUG |
| 723 | << "Tried to add writer into blocked list when it shouldn't be added"; |
| 724 | // Return without adding the connection to the blocked list, to avoid |
| 725 | // infinite loops in OnCanWrite. |
| 726 | return; |
| 727 | } |
| 728 | |
| 729 | write_blocked_list_.insert(std::make_pair(blocked_writer, true)); |
| 730 | } |
| 731 | |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 732 | void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& /*frame*/) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 733 | |
dschinazi | 17d4242 | 2019-06-18 16:35:07 -0700 | [diff] [blame] | 734 | void QuicDispatcher::OnStopSendingReceived( |
| 735 | const QuicStopSendingFrame& /*frame*/) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 736 | |
| 737 | void QuicDispatcher::OnConnectionAddedToTimeWaitList( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 738 | QuicConnectionId server_connection_id) { |
| 739 | QUIC_DLOG(INFO) << "Connection " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 740 | << " added to time wait list."; |
| 741 | } |
| 742 | |
| 743 | void QuicDispatcher::StatelesslyTerminateConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 744 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 745 | PacketHeaderFormat format, |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 746 | bool version_flag, |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 747 | bool use_length_prefix, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 748 | ParsedQuicVersion version, |
| 749 | QuicErrorCode error_code, |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 750 | const std::string& error_details, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 751 | QuicTimeWaitListManager::TimeWaitAction action) { |
fayang | 51c2373 | 2019-06-24 06:59:55 -0700 | [diff] [blame] | 752 | if (format != IETF_QUIC_LONG_HEADER_PACKET && !version_flag) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 753 | QUIC_DVLOG(1) << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 754 | << " based on a non-ietf-long packet, action:" << action |
| 755 | << ", error_code:" << error_code |
| 756 | << ", error_details:" << error_details; |
| 757 | time_wait_list_manager_->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 758 | server_connection_id, format != GOOGLE_QUIC_PACKET, action, |
| 759 | ENCRYPTION_INITIAL, nullptr); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 760 | return; |
| 761 | } |
| 762 | |
| 763 | // If the version is known and supported by framer, send a connection close. |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 764 | if (IsSupportedVersion(version)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 765 | QUIC_DVLOG(1) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 766 | << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 767 | << " based on an ietf-long packet, which has a supported version:" |
| 768 | << version << ", error_code:" << error_code |
| 769 | << ", error_details:" << error_details; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 770 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 771 | StatelessConnectionTerminator terminator(server_connection_id, version, |
| 772 | helper_.get(), |
| 773 | time_wait_list_manager_.get()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 774 | // This also adds the connection to time wait list. |
fayang | 1de6789 | 2019-04-19 05:59:45 -0700 | [diff] [blame] | 775 | terminator.CloseConnection(error_code, error_details, |
| 776 | format != GOOGLE_QUIC_PACKET); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 777 | return; |
| 778 | } |
| 779 | |
| 780 | QUIC_DVLOG(1) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 781 | << "Statelessly terminating " << server_connection_id |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 782 | << " based on an ietf-long packet, which has an unsupported version:" |
| 783 | << version << ", error_code:" << error_code |
| 784 | << ", error_details:" << error_details; |
| 785 | // Version is unknown or unsupported by framer, send a version negotiation |
| 786 | // with an empty version list, which can be understood by the client. |
| 787 | std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; |
| 788 | termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket( |
dschinazi | b417d60 | 2019-05-29 13:08:45 -0700 | [diff] [blame] | 789 | server_connection_id, EmptyQuicConnectionId(), |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 790 | /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix, |
dschinazi | 1ac22cc | 2019-06-25 11:47:50 -0700 | [diff] [blame] | 791 | /*versions=*/{})); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 792 | time_wait_list_manager()->AddConnectionIdToTimeWait( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 793 | server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, |
QUICHE team | 6987b4a | 2019-03-15 16:23:04 -0700 | [diff] [blame] | 794 | QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 795 | &termination_packets); |
| 796 | } |
| 797 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 798 | bool QuicDispatcher::ShouldCreateSessionForUnknownVersion( |
| 799 | QuicVersionLabel /*version_label*/) { |
| 800 | return false; |
| 801 | } |
| 802 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 803 | void QuicDispatcher::OnExpiredPackets( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 804 | QuicConnectionId server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 805 | BufferedPacketList early_arrived_packets) { |
| 806 | QUIC_CODE_COUNT(quic_reject_buffered_packets_expired); |
| 807 | StatelesslyTerminateConnection( |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 808 | server_connection_id, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 809 | early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET |
| 810 | : GOOGLE_QUIC_PACKET, |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 811 | /*version_flag=*/true, |
| 812 | early_arrived_packets.version.HasLengthPrefixedConnectionIds(), |
| 813 | early_arrived_packets.version, QUIC_HANDSHAKE_FAILED, |
| 814 | "Packets buffered for too long", |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 815 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 816 | } |
| 817 | |
| 818 | void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) { |
| 819 | // Reset the counter before starting creating connections. |
| 820 | new_sessions_allowed_per_event_loop_ = max_connections_to_create; |
| 821 | for (; new_sessions_allowed_per_event_loop_ > 0; |
| 822 | --new_sessions_allowed_per_event_loop_) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 823 | QuicConnectionId server_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 824 | BufferedPacketList packet_list = |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 825 | buffered_packets_.DeliverPacketsForNextConnection( |
| 826 | &server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 827 | const std::list<BufferedPacket>& packets = packet_list.buffered_packets; |
| 828 | if (packets.empty()) { |
| 829 | return; |
| 830 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 831 | QuicConnectionId original_connection_id = server_connection_id; |
| 832 | server_connection_id = MaybeReplaceServerConnectionId(server_connection_id, |
| 833 | packet_list.version); |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 834 | std::unique_ptr<QuicSession> session = |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 835 | CreateQuicSession(server_connection_id, packets.front().peer_address, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 836 | packet_list.alpn, packet_list.version); |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 837 | if (original_connection_id != server_connection_id) { |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 838 | session->connection()->AddIncomingConnectionId(original_connection_id); |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 839 | session->connection()->InstallInitialCrypters(original_connection_id); |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 840 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 841 | QUIC_DLOG(INFO) << "Created new session for " << server_connection_id; |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 842 | |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 843 | auto insertion_result = session_map_.insert( |
| 844 | std::make_pair(server_connection_id, std::move(session))); |
| 845 | QUIC_BUG_IF(!insertion_result.second) |
| 846 | << "Tried to add a session to session_map with existing connection id: " |
| 847 | << server_connection_id; |
| 848 | DeliverPacketsToSession(packets, insertion_result.first->second.get()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 849 | } |
| 850 | } |
| 851 | |
| 852 | bool QuicDispatcher::HasChlosBuffered() const { |
| 853 | return buffered_packets_.HasChlosBuffered(); |
| 854 | } |
| 855 | |
| 856 | bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 857 | const ReceivedPacketInfo& packet_info) { |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 858 | QUIC_VLOG(1) << "Received packet from new connection " |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 859 | << packet_info.destination_connection_id; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 860 | return true; |
| 861 | } |
| 862 | |
| 863 | // Return true if there is any packet buffered in the store. |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 864 | bool QuicDispatcher::HasBufferedPackets(QuicConnectionId server_connection_id) { |
| 865 | return buffered_packets_.HasBufferedPackets(server_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 866 | } |
| 867 | |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 868 | void QuicDispatcher::OnBufferPacketFailure( |
| 869 | EnqueuePacketResult result, |
| 870 | QuicConnectionId server_connection_id) { |
| 871 | QUIC_DLOG(INFO) << "Fail to buffer packet on connection " |
| 872 | << server_connection_id << " because of " << result; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 873 | } |
| 874 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 875 | QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { |
| 876 | return new QuicTimeWaitListManager(writer_.get(), this, helper_->GetClock(), |
| 877 | alarm_factory_.get()); |
| 878 | } |
| 879 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 880 | void QuicDispatcher::BufferEarlyPacket(const ReceivedPacketInfo& packet_info) { |
| 881 | bool is_new_connection = !buffered_packets_.HasBufferedPackets( |
| 882 | packet_info.destination_connection_id); |
| 883 | if (is_new_connection && |
| 884 | !ShouldCreateOrBufferPacketForConnection(packet_info)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 885 | return; |
| 886 | } |
| 887 | |
| 888 | EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 889 | packet_info.destination_connection_id, |
| 890 | packet_info.form != GOOGLE_QUIC_PACKET, packet_info.packet, |
| 891 | packet_info.self_address, packet_info.peer_address, /*is_chlo=*/false, |
| 892 | /*alpn=*/"", packet_info.version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 893 | if (rs != EnqueuePacketResult::SUCCESS) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 894 | OnBufferPacketFailure(rs, packet_info.destination_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 895 | } |
| 896 | } |
| 897 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 898 | void QuicDispatcher::ProcessChlo(const std::string& alpn, |
| 899 | ReceivedPacketInfo* packet_info) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 900 | if (!accept_new_connections_) { |
| 901 | // Don't any create new connection. |
| 902 | QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections); |
| 903 | StatelesslyTerminateConnection( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 904 | packet_info->destination_connection_id, packet_info->form, |
dschinazi | 48ac919 | 2019-07-31 00:07:26 -0700 | [diff] [blame] | 905 | /*version_flag=*/true, packet_info->use_length_prefix, |
| 906 | packet_info->version, QUIC_HANDSHAKE_FAILED, |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 907 | "Stop accepting new connections", |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 908 | quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); |
| 909 | // Time wait list will reject the packet correspondingly. |
| 910 | time_wait_list_manager()->ProcessPacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 911 | packet_info->self_address, packet_info->peer_address, |
| 912 | packet_info->destination_connection_id, packet_info->form, |
| 913 | GetPerPacketContext()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 914 | return; |
| 915 | } |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 916 | if (!buffered_packets_.HasBufferedPackets( |
| 917 | packet_info->destination_connection_id) && |
| 918 | !ShouldCreateOrBufferPacketForConnection(*packet_info)) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 919 | return; |
| 920 | } |
danzh | 88e3e05 | 2019-06-13 11:47:18 -0700 | [diff] [blame] | 921 | if (GetQuicFlag(FLAGS_quic_allow_chlo_buffering) && |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 922 | new_sessions_allowed_per_event_loop_ <= 0) { |
| 923 | // Can't create new session any more. Wait till next event loop. |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 924 | QUIC_BUG_IF(buffered_packets_.HasChloForConnection( |
| 925 | packet_info->destination_connection_id)); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 926 | EnqueuePacketResult rs = buffered_packets_.EnqueuePacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 927 | packet_info->destination_connection_id, |
| 928 | packet_info->form != GOOGLE_QUIC_PACKET, packet_info->packet, |
| 929 | packet_info->self_address, packet_info->peer_address, |
| 930 | /*is_chlo=*/true, alpn, packet_info->version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 931 | if (rs != EnqueuePacketResult::SUCCESS) { |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 932 | OnBufferPacketFailure(rs, packet_info->destination_connection_id); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 933 | } |
| 934 | return; |
| 935 | } |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 936 | |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 937 | QuicConnectionId original_connection_id = |
| 938 | packet_info->destination_connection_id; |
| 939 | packet_info->destination_connection_id = MaybeReplaceServerConnectionId( |
| 940 | original_connection_id, packet_info->version); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 941 | // Creates a new session and process all buffered packets for this connection. |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 942 | std::unique_ptr<QuicSession> session = |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 943 | CreateQuicSession(packet_info->destination_connection_id, |
| 944 | packet_info->peer_address, alpn, packet_info->version); |
| 945 | if (original_connection_id != packet_info->destination_connection_id) { |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 946 | session->connection()->AddIncomingConnectionId(original_connection_id); |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 947 | session->connection()->InstallInitialCrypters(original_connection_id); |
QUICHE team | c65d1d1 | 2019-03-19 20:58:04 -0700 | [diff] [blame] | 948 | } |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 949 | QUIC_DLOG(INFO) << "Created new session for " |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 950 | << packet_info->destination_connection_id; |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 951 | |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 952 | auto insertion_result = session_map_.insert(std::make_pair( |
| 953 | packet_info->destination_connection_id, std::move(session))); |
| 954 | QUIC_BUG_IF(!insertion_result.second) |
| 955 | << "Tried to add a session to session_map with existing connection id: " |
dschinazi | 5c03085 | 2019-07-11 15:45:53 -0700 | [diff] [blame] | 956 | << packet_info->destination_connection_id; |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 957 | QuicSession* session_ptr = insertion_result.first->second.get(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 958 | std::list<BufferedPacket> packets = |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 959 | buffered_packets_.DeliverPackets(packet_info->destination_connection_id) |
dschinazi | 7b9278c | 2019-05-20 07:36:21 -0700 | [diff] [blame] | 960 | .buffered_packets; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 961 | // Process CHLO at first. |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 962 | session_ptr->ProcessUdpPacket(packet_info->self_address, |
| 963 | packet_info->peer_address, packet_info->packet); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 964 | // Deliver queued-up packets in the same order as they arrived. |
| 965 | // Do this even when flag is off because there might be still some packets |
| 966 | // buffered in the store before flag is turned off. |
wub | 89490e0 | 2019-12-12 12:45:58 -0800 | [diff] [blame] | 967 | DeliverPacketsToSession(packets, session_ptr); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 968 | --new_sessions_allowed_per_event_loop_; |
| 969 | } |
| 970 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 971 | bool QuicDispatcher::ShouldDestroySessionAsynchronously() { |
| 972 | return true; |
| 973 | } |
| 974 | |
| 975 | void QuicDispatcher::SetLastError(QuicErrorCode error) { |
| 976 | last_error_ = error; |
| 977 | } |
| 978 | |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 979 | bool QuicDispatcher::OnFailedToDispatchPacket( |
fayang | 1ed1f76 | 2019-06-24 11:40:04 -0700 | [diff] [blame] | 980 | const ReceivedPacketInfo& /*packet_info*/) { |
fayang | 91475c4 | 2019-06-19 08:04:26 -0700 | [diff] [blame] | 981 | return false; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 982 | } |
| 983 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 984 | const QuicTransportVersionVector& |
| 985 | QuicDispatcher::GetSupportedTransportVersions() { |
| 986 | return version_manager_->GetSupportedTransportVersions(); |
| 987 | } |
| 988 | |
| 989 | const ParsedQuicVersionVector& QuicDispatcher::GetSupportedVersions() { |
| 990 | return version_manager_->GetSupportedVersions(); |
| 991 | } |
| 992 | |
| 993 | void QuicDispatcher::DeliverPacketsToSession( |
| 994 | const std::list<BufferedPacket>& packets, |
| 995 | QuicSession* session) { |
| 996 | for (const BufferedPacket& packet : packets) { |
| 997 | session->ProcessUdpPacket(packet.self_address, packet.peer_address, |
| 998 | *(packet.packet)); |
| 999 | } |
| 1000 | } |
| 1001 | |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 1002 | bool QuicDispatcher::IsSupportedVersion(const ParsedQuicVersion version) { |
fayang | ccbab73 | 2019-05-13 10:11:25 -0700 | [diff] [blame] | 1003 | for (const ParsedQuicVersion& supported_version : |
| 1004 | version_manager_->GetSupportedVersions()) { |
| 1005 | if (version == supported_version) { |
| 1006 | return true; |
| 1007 | } |
| 1008 | } |
| 1009 | return false; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1010 | } |
| 1011 | |
fayang | d057e66 | 2019-07-10 13:29:41 -0700 | [diff] [blame] | 1012 | void QuicDispatcher::MaybeResetPacketsWithNoVersion( |
| 1013 | const ReceivedPacketInfo& packet_info) { |
| 1014 | DCHECK(!packet_info.version_flag); |
| 1015 | const size_t MinValidPacketLength = |
| 1016 | kPacketHeaderTypeSize + expected_server_connection_id_length_ + |
| 1017 | PACKET_1BYTE_PACKET_NUMBER + /*payload size=*/1 + /*tag size=*/12; |
| 1018 | if (packet_info.packet.length() < MinValidPacketLength) { |
| 1019 | // The packet size is too small. |
| 1020 | QUIC_CODE_COUNT(drop_too_small_packets); |
| 1021 | return; |
| 1022 | } |
| 1023 | // TODO(fayang): Consider rate limiting reset packets if reset packet size > |
| 1024 | // packet_length. |
| 1025 | |
| 1026 | time_wait_list_manager()->SendPublicReset( |
| 1027 | packet_info.self_address, packet_info.peer_address, |
| 1028 | packet_info.destination_connection_id, |
| 1029 | packet_info.form != GOOGLE_QUIC_PACKET, GetPerPacketContext()); |
| 1030 | } |
| 1031 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1032 | } // namespace quic |