OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/tools/quic/quic_dispatcher.h" | 5 #include "net/tools/quic/quic_dispatcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/debug/stack_trace.h" | 9 #include "base/debug/stack_trace.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "net/quic/core/crypto/quic_random.h" | 13 #include "net/quic/core/crypto/quic_random.h" |
14 #include "net/quic/core/quic_bug_tracker.h" | 14 #include "net/quic/core/quic_bug_tracker.h" |
15 #include "net/quic/core/quic_flags.h" | 15 #include "net/quic/core/quic_flags.h" |
16 #include "net/quic/core/quic_utils.h" | 16 #include "net/quic/core/quic_utils.h" |
| 17 |
17 #include "net/tools/quic/chlo_extractor.h" | 18 #include "net/tools/quic/chlo_extractor.h" |
18 #include "net/tools/quic/quic_per_connection_packet_writer.h" | 19 #include "net/tools/quic/quic_per_connection_packet_writer.h" |
19 #include "net/tools/quic/quic_simple_server_session.h" | 20 #include "net/tools/quic/quic_simple_server_session.h" |
| 21 #include "net/tools/quic/quic_simple_server_session.h" |
20 #include "net/tools/quic/quic_time_wait_list_manager.h" | 22 #include "net/tools/quic/quic_time_wait_list_manager.h" |
21 #include "net/tools/quic/stateless_rejector.h" | 23 #include "net/tools/quic/stateless_rejector.h" |
22 | 24 |
23 using base::StringPiece; | 25 using base::StringPiece; |
24 using std::list; | 26 using std::list; |
25 using std::string; | 27 using std::string; |
26 | 28 |
27 namespace net { | 29 namespace net { |
28 | 30 |
29 typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; | 31 typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 // Set as the visitor of |creator_| to collect any generated packets. | 150 // Set as the visitor of |creator_| to collect any generated packets. |
149 PacketCollector collector_; | 151 PacketCollector collector_; |
150 QuicPacketCreator creator_; | 152 QuicPacketCreator creator_; |
151 QuicTimeWaitListManager* time_wait_list_manager_; | 153 QuicTimeWaitListManager* time_wait_list_manager_; |
152 }; | 154 }; |
153 | 155 |
154 // Class which sits between the ChloExtractor and the StatelessRejector | 156 // Class which sits between the ChloExtractor and the StatelessRejector |
155 // to give the QuicDispatcher a chance to apply policy checks to the CHLO. | 157 // to give the QuicDispatcher a chance to apply policy checks to the CHLO. |
156 class ChloValidator : public ChloExtractor::Delegate { | 158 class ChloValidator : public ChloExtractor::Delegate { |
157 public: | 159 public: |
158 ChloValidator(QuicServerSessionBase::Helper* helper, | 160 ChloValidator(QuicCryptoServerStream::Helper* helper, |
159 IPEndPoint self_address, | 161 IPEndPoint self_address, |
160 StatelessRejector* rejector) | 162 StatelessRejector* rejector) |
161 : helper_(helper), | 163 : helper_(helper), |
162 self_address_(self_address), | 164 self_address_(self_address), |
163 rejector_(rejector), | 165 rejector_(rejector), |
164 can_accept_(false) {} | 166 can_accept_(false) {} |
165 | 167 |
166 // ChloExtractor::Delegate implementation. | 168 // ChloExtractor::Delegate implementation. |
167 void OnChlo(QuicVersion version, | 169 void OnChlo(QuicVersion version, |
168 QuicConnectionId connection_id, | 170 QuicConnectionId connection_id, |
169 const CryptoHandshakeMessage& chlo) override { | 171 const CryptoHandshakeMessage& chlo) override { |
170 if (helper_->CanAcceptClientHello(chlo, self_address_, &error_details_)) { | 172 if (helper_->CanAcceptClientHello(chlo, self_address_, &error_details_)) { |
171 can_accept_ = true; | 173 can_accept_ = true; |
172 rejector_->OnChlo(version, connection_id, | 174 rejector_->OnChlo(version, connection_id, |
173 helper_->GenerateConnectionIdForReject(connection_id), | 175 helper_->GenerateConnectionIdForReject(connection_id), |
174 chlo); | 176 chlo); |
175 } | 177 } |
176 } | 178 } |
177 | 179 |
178 bool can_accept() const { return can_accept_; } | 180 bool can_accept() const { return can_accept_; } |
179 | 181 |
180 const string& error_details() const { return error_details_; } | 182 const string& error_details() const { return error_details_; } |
181 | 183 |
182 private: | 184 private: |
183 QuicServerSessionBase::Helper* helper_; // Unowned. | 185 QuicCryptoServerStream::Helper* helper_; // Unowned. |
184 IPEndPoint self_address_; | 186 IPEndPoint self_address_; |
185 StatelessRejector* rejector_; // Unowned. | 187 StatelessRejector* rejector_; // Unowned. |
186 bool can_accept_; | 188 bool can_accept_; |
187 string error_details_; | 189 string error_details_; |
188 }; | 190 }; |
189 | 191 |
190 } // namespace | 192 } // namespace |
191 | 193 |
192 QuicDispatcher::QuicDispatcher( | 194 QuicDispatcher::QuicDispatcher( |
193 const QuicConfig& config, | 195 const QuicConfig& config, |
194 const QuicCryptoServerConfig* crypto_config, | 196 const QuicCryptoServerConfig* crypto_config, |
195 QuicVersionManager* version_manager, | 197 QuicVersionManager* version_manager, |
196 std::unique_ptr<QuicConnectionHelperInterface> helper, | 198 std::unique_ptr<QuicConnectionHelperInterface> helper, |
197 std::unique_ptr<QuicServerSessionBase::Helper> session_helper, | 199 std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, |
198 std::unique_ptr<QuicAlarmFactory> alarm_factory) | 200 std::unique_ptr<QuicAlarmFactory> alarm_factory) |
199 : config_(config), | 201 : config_(config), |
200 crypto_config_(crypto_config), | 202 crypto_config_(crypto_config), |
201 compressed_certs_cache_( | 203 compressed_certs_cache_( |
202 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), | 204 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), |
203 helper_(std::move(helper)), | 205 helper_(std::move(helper)), |
204 session_helper_(std::move(session_helper)), | 206 session_helper_(std::move(session_helper)), |
205 alarm_factory_(std::move(alarm_factory)), | 207 alarm_factory_(std::move(alarm_factory)), |
206 delete_sessions_alarm_( | 208 delete_sessions_alarm_( |
207 alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))), | 209 alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))), |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 if (time_wait_list_manager_->IsConnectionIdInTimeWait( | 320 if (time_wait_list_manager_->IsConnectionIdInTimeWait( |
319 header.public_header.connection_id)) { | 321 header.public_header.connection_id)) { |
320 // This connection ID is already in time-wait state. | 322 // This connection ID is already in time-wait state. |
321 time_wait_list_manager_->ProcessPacket( | 323 time_wait_list_manager_->ProcessPacket( |
322 current_server_address_, current_client_address_, | 324 current_server_address_, current_client_address_, |
323 header.public_header.connection_id, header.packet_number, | 325 header.public_header.connection_id, header.packet_number, |
324 *current_packet_); | 326 *current_packet_); |
325 return false; | 327 return false; |
326 } | 328 } |
327 | 329 |
328 // Packet's connection ID is unknown. | 330 // Packet's connection ID is unknown. Apply the validity checks. |
329 // Apply the validity checks. | |
330 QuicPacketFate fate = ValidityChecks(header); | 331 QuicPacketFate fate = ValidityChecks(header); |
331 if (fate == kFateProcess) { | 332 if (fate == kFateProcess) { |
332 fate = MaybeRejectStatelessly(connection_id, header); | 333 // Execute stateless rejection logic to determine the packet fate, then |
| 334 // invoke ProcessUnauthenticatedHeaderFate. |
| 335 MaybeRejectStatelessly(connection_id, header); |
| 336 } else { |
| 337 // If the fate is already known, process it without executing stateless |
| 338 // rejection logic. |
| 339 ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number); |
333 } | 340 } |
| 341 |
| 342 return false; |
| 343 } |
| 344 |
| 345 void QuicDispatcher::ProcessUnauthenticatedHeaderFate( |
| 346 QuicPacketFate fate, |
| 347 QuicConnectionId connection_id, |
| 348 QuicPacketNumber packet_number) { |
334 switch (fate) { | 349 switch (fate) { |
335 case kFateProcess: { | 350 case kFateProcess: { |
336 ProcessChlo(); | 351 ProcessChlo(); |
337 break; | 352 break; |
338 } | 353 } |
339 case kFateTimeWait: | 354 case kFateTimeWait: |
340 // MaybeRejectStatelessly might have already added the connection to | 355 // MaybeRejectStatelessly might have already added the connection to |
341 // time wait, in which case it should not be added again. | 356 // time wait, in which case it should not be added again. |
342 if (!FLAGS_quic_use_cheap_stateless_rejects || | 357 if (!FLAGS_quic_use_cheap_stateless_rejects || |
343 !time_wait_list_manager_->IsConnectionIdInTimeWait( | 358 !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { |
344 header.public_header.connection_id)) { | |
345 // Add this connection_id to the time-wait state, to safely reject | 359 // Add this connection_id to the time-wait state, to safely reject |
346 // future packets. | 360 // future packets. |
347 DVLOG(1) << "Adding connection ID " << connection_id | 361 DVLOG(1) << "Adding connection ID " << connection_id |
348 << "to time-wait list."; | 362 << "to time-wait list."; |
349 time_wait_list_manager_->AddConnectionIdToTimeWait( | 363 time_wait_list_manager_->AddConnectionIdToTimeWait( |
350 connection_id, framer_.version(), | 364 connection_id, framer_.version(), |
351 /*connection_rejected_statelessly=*/false, nullptr); | 365 /*connection_rejected_statelessly=*/false, nullptr); |
352 } | 366 } |
353 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( | 367 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); |
354 header.public_header.connection_id)); | |
355 time_wait_list_manager_->ProcessPacket( | 368 time_wait_list_manager_->ProcessPacket( |
356 current_server_address_, current_client_address_, | 369 current_server_address_, current_client_address_, connection_id, |
357 header.public_header.connection_id, header.packet_number, | 370 packet_number, *current_packet_); |
358 *current_packet_); | |
359 break; | 371 break; |
360 case kFateBuffer: | 372 case kFateBuffer: |
361 // This packet is a non-CHLO packet which has arrived out of order. | 373 // This packet is a non-CHLO packet which has arrived out of order. |
362 // Buffer it. | 374 // Buffer it. |
363 BufferEarlyPacket(connection_id); | 375 BufferEarlyPacket(connection_id); |
364 break; | 376 break; |
365 case kFateDrop: | 377 case kFateDrop: |
366 // Do nothing with the packet. | 378 // Do nothing with the packet. |
367 break; | 379 break; |
368 } | 380 } |
369 | |
370 return false; | |
371 } | 381 } |
372 | 382 |
373 QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( | 383 QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks( |
374 const QuicPacketHeader& header) { | 384 const QuicPacketHeader& header) { |
375 // To have all the checks work properly without tears, insert any new check | 385 // To have all the checks work properly without tears, insert any new check |
376 // into the framework of this method in the section for checks that return the | 386 // into the framework of this method in the section for checks that return the |
377 // check's fate value. The sections for checks must be ordered with the | 387 // check's fate value. The sections for checks must be ordered with the |
378 // highest priority fate first. | 388 // highest priority fate first. |
379 | 389 |
380 // Checks that return kFateDrop. | 390 // Checks that return kFateDrop. |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 | 760 |
751 void QuicDispatcher::SetLastError(QuicErrorCode error) { | 761 void QuicDispatcher::SetLastError(QuicErrorCode error) { |
752 last_error_ = error; | 762 last_error_ = error; |
753 } | 763 } |
754 | 764 |
755 bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( | 765 bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( |
756 const QuicPacketPublicHeader& header) { | 766 const QuicPacketPublicHeader& header) { |
757 return true; | 767 return true; |
758 } | 768 } |
759 | 769 |
760 QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly( | 770 class StatelessRejectorProcessDoneCallback |
761 QuicConnectionId connection_id, | 771 : public StatelessRejector::ProcessDoneCallback { |
762 const QuicPacketHeader& header) { | 772 public: |
| 773 StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, |
| 774 QuicPacketNumber packet_number, |
| 775 QuicVersion first_version) |
| 776 : dispatcher_(dispatcher), |
| 777 packet_number_(packet_number), |
| 778 first_version_(first_version) {} |
| 779 |
| 780 void Run(std::unique_ptr<StatelessRejector> rejector) override { |
| 781 dispatcher_->OnStatelessRejectorProcessDone(std::move(rejector), |
| 782 packet_number_, first_version_); |
| 783 } |
| 784 |
| 785 private: |
| 786 QuicDispatcher* dispatcher_; |
| 787 QuicPacketNumber packet_number_; |
| 788 QuicVersion first_version_; |
| 789 }; |
| 790 |
| 791 void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, |
| 792 const QuicPacketHeader& header) { |
763 // TODO(rch): This logic should probably live completely inside the rejector. | 793 // TODO(rch): This logic should probably live completely inside the rejector. |
764 if (!FLAGS_quic_use_cheap_stateless_rejects || | 794 if (!FLAGS_quic_use_cheap_stateless_rejects || |
765 !FLAGS_enable_quic_stateless_reject_support || | 795 !FLAGS_enable_quic_stateless_reject_support || |
766 header.public_header.versions.front() <= QUIC_VERSION_32 || | 796 header.public_header.versions.front() <= QUIC_VERSION_32 || |
767 !ShouldAttemptCheapStatelessRejection()) { | 797 !ShouldAttemptCheapStatelessRejection()) { |
768 // Not use cheap stateless reject. | 798 // Not use cheap stateless reject. |
769 if (FLAGS_quic_buffer_packet_till_chlo && | 799 if (FLAGS_quic_buffer_packet_till_chlo && |
770 !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), | 800 !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), |
771 nullptr)) { | 801 nullptr)) { |
772 // Buffer non-CHLO packets. | 802 // Buffer non-CHLO packets. |
773 return kFateBuffer; | 803 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, |
| 804 header.packet_number); |
| 805 return; |
774 } | 806 } |
775 return kFateProcess; | 807 ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, |
| 808 header.packet_number); |
| 809 return; |
776 } | 810 } |
777 | 811 |
778 StatelessRejector rejector( | 812 std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( |
779 header.public_header.versions.front(), GetSupportedVersions(), | 813 header.public_header.versions.front(), GetSupportedVersions(), |
780 crypto_config_, &compressed_certs_cache_, helper()->GetClock(), | 814 crypto_config_, &compressed_certs_cache_, helper()->GetClock(), |
781 helper()->GetRandomGenerator(), current_packet_->length(), | 815 helper()->GetRandomGenerator(), current_packet_->length(), |
782 current_client_address_, current_server_address_); | 816 current_client_address_, current_server_address_)); |
783 ChloValidator validator(session_helper_.get(), current_server_address_, | 817 ChloValidator validator(session_helper_.get(), current_server_address_, |
784 &rejector); | 818 rejector.get()); |
785 if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), | 819 if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), |
786 &validator)) { | 820 &validator)) { |
787 if (!FLAGS_quic_buffer_packet_till_chlo) { | 821 if (!FLAGS_quic_buffer_packet_till_chlo) { |
788 QUIC_BUG | 822 QUIC_BUG |
789 << "Have to drop packet because buffering non-chlo packet is " | 823 << "Have to drop packet because buffering non-chlo packet is " |
790 "not supported while trying to do stateless reject. " | 824 "not supported while trying to do stateless reject. " |
791 "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false" | 825 "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false" |
792 " --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true"; | 826 " --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true"; |
793 return kFateDrop; | 827 ProcessUnauthenticatedHeaderFate(kFateDrop, connection_id, |
| 828 header.packet_number); |
| 829 return; |
794 } | 830 } |
795 return kFateBuffer; | 831 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, |
| 832 header.packet_number); |
| 833 return; |
796 } | 834 } |
797 | 835 |
798 if (!validator.can_accept()) { | 836 if (!validator.can_accept()) { |
799 // This CHLO is prohibited by policy. | 837 // This CHLO is prohibited by policy. |
800 StatelessConnectionTerminator terminator(connection_id, &framer_, helper(), | 838 StatelessConnectionTerminator terminator(connection_id, &framer_, helper(), |
801 time_wait_list_manager_.get()); | 839 time_wait_list_manager_.get()); |
802 terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, | 840 terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, |
803 validator.error_details()); | 841 validator.error_details()); |
804 OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED); | 842 OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED); |
805 return kFateTimeWait; | 843 ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, |
| 844 header.packet_number); |
| 845 return; |
806 } | 846 } |
807 | 847 |
808 // This packet included a CHLO. See if it can be rejected statelessly. | 848 // Continue stateless rejector processing |
809 switch (rejector.state()) { | 849 std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( |
| 850 new StatelessRejectorProcessDoneCallback( |
| 851 this, header.packet_number, header.public_header.versions.front())); |
| 852 StatelessRejector::Process(std::move(rejector), std::move(cb)); |
| 853 } |
| 854 |
| 855 void QuicDispatcher::OnStatelessRejectorProcessDone( |
| 856 std::unique_ptr<StatelessRejector> rejector, |
| 857 QuicPacketNumber packet_number, |
| 858 QuicVersion first_version) { |
| 859 QuicPacketFate fate; |
| 860 switch (rejector->state()) { |
810 case StatelessRejector::FAILED: { | 861 case StatelessRejector::FAILED: { |
811 // There was an error processing the client hello. | 862 // There was an error processing the client hello. |
812 StatelessConnectionTerminator terminator( | 863 StatelessConnectionTerminator terminator(rejector->connection_id(), |
813 connection_id, &framer_, helper(), time_wait_list_manager_.get()); | 864 &framer_, helper(), |
814 terminator.CloseConnection(rejector.error(), rejector.error_details()); | 865 time_wait_list_manager_.get()); |
815 return kFateTimeWait; | 866 terminator.CloseConnection(rejector->error(), rejector->error_details()); |
| 867 fate = kFateTimeWait; |
| 868 break; |
816 } | 869 } |
817 | 870 |
818 case StatelessRejector::UNSUPPORTED: | 871 case StatelessRejector::UNSUPPORTED: |
819 // Cheap stateless rejects are not supported so process the packet. | 872 // Cheap stateless rejects are not supported so process the packet. |
820 return kFateProcess; | 873 fate = kFateProcess; |
| 874 break; |
821 | 875 |
822 case StatelessRejector::ACCEPTED: | 876 case StatelessRejector::ACCEPTED: |
823 // Contains a valid CHLO, so process the packet and create a connection. | 877 // Contains a valid CHLO, so process the packet and create a connection. |
824 return kFateProcess; | 878 fate = kFateProcess; |
| 879 break; |
825 | 880 |
826 case StatelessRejector::REJECTED: { | 881 case StatelessRejector::REJECTED: { |
827 DCHECK_EQ(framer_.version(), header.public_header.versions.front()); | 882 DCHECK_EQ(framer_.version(), first_version); |
828 StatelessConnectionTerminator terminator( | 883 StatelessConnectionTerminator terminator(rejector->connection_id(), |
829 connection_id, &framer_, helper(), time_wait_list_manager_.get()); | 884 &framer_, helper(), |
| 885 time_wait_list_manager_.get()); |
830 terminator.RejectConnection( | 886 terminator.RejectConnection( |
831 rejector.reply().GetSerialized().AsStringPiece()); | 887 rejector->reply().GetSerialized().AsStringPiece()); |
832 OnConnectionRejectedStatelessly(); | 888 OnConnectionRejectedStatelessly(); |
833 return kFateTimeWait; | 889 fate = kFateTimeWait; |
| 890 break; |
834 } | 891 } |
| 892 |
| 893 default: |
| 894 QUIC_BUG << "Rejector has invalid state " << rejector->state(); |
| 895 fate = kFateDrop; |
| 896 break; |
835 } | 897 } |
836 | 898 ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), |
837 QUIC_BUG << "Rejector has unknown invalid state."; | 899 packet_number); |
838 return kFateDrop; | |
839 } | 900 } |
840 | 901 |
841 const QuicVersionVector& QuicDispatcher::GetSupportedVersions() { | 902 const QuicVersionVector& QuicDispatcher::GetSupportedVersions() { |
842 return version_manager_->GetSupportedVersions(); | 903 return version_manager_->GetSupportedVersions(); |
843 } | 904 } |
844 | 905 |
845 void QuicDispatcher::DeliverPacketsToSession( | 906 void QuicDispatcher::DeliverPacketsToSession( |
846 const std::list<BufferedPacket>& packets, | 907 const std::list<BufferedPacket>& packets, |
847 QuicServerSessionBase* session) { | 908 QuicServerSessionBase* session) { |
848 for (const BufferedPacket& packet : packets) { | 909 for (const BufferedPacket& packet : packets) { |
849 session->ProcessUdpPacket(packet.server_address, packet.client_address, | 910 session->ProcessUdpPacket(packet.server_address, packet.client_address, |
850 *(packet.packet)); | 911 *(packet.packet)); |
851 } | 912 } |
852 } | 913 } |
853 | 914 |
854 } // namespace net | 915 } // namespace net |
OLD | NEW |