xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_path_validator_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2020 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 "quiche/quic/core/quic_path_validator.h"
6 
7 #include <memory>
8 
9 #include "quiche/quic/core/frames/quic_path_challenge_frame.h"
10 #include "quiche/quic/core/quic_constants.h"
11 #include "quiche/quic/core/quic_types.h"
12 #include "quiche/quic/platform/api/quic_ip_address.h"
13 #include "quiche/quic/platform/api/quic_socket_address.h"
14 #include "quiche/quic/platform/api/quic_test.h"
15 #include "quiche/quic/test_tools/mock_clock.h"
16 #include "quiche/quic/test_tools/mock_random.h"
17 #include "quiche/quic/test_tools/quic_path_validator_peer.h"
18 #include "quiche/quic/test_tools/quic_test_utils.h"
19 
20 using testing::_;
21 using testing::Invoke;
22 using testing::Return;
23 
24 namespace quic {
25 namespace test {
26 
27 class MockSendDelegate : public QuicPathValidator::SendDelegate {
28  public:
29   // Send a PATH_CHALLENGE frame using given path information and populate
30   // |data_buffer| with the frame payload. Return true if the validator should
31   // move forward in validation, i.e. arm the retry timer.
32   MOCK_METHOD(bool, SendPathChallenge,
33               (const QuicPathFrameBuffer&, const QuicSocketAddress&,
34                const QuicSocketAddress&, const QuicSocketAddress&,
35                QuicPacketWriter*),
36               (override));
37 
38   MOCK_METHOD(QuicTime, GetRetryTimeout,
39               (const QuicSocketAddress&, QuicPacketWriter*), (const, override));
40 };
41 
42 class QuicPathValidatorTest : public QuicTest {
43  public:
QuicPathValidatorTest()44   QuicPathValidatorTest()
45       : path_validator_(&alarm_factory_, &arena_, &send_delegate_, &random_,
46                         &clock_,
47                         /*context=*/nullptr),
48         context_(new MockQuicPathValidationContext(
49             self_address_, peer_address_, effective_peer_address_, &writer_)),
50         result_delegate_(
51             new testing::StrictMock<MockQuicPathValidationResultDelegate>()) {
52     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
53     ON_CALL(send_delegate_, GetRetryTimeout(_, _))
54         .WillByDefault(
55             Return(clock_.ApproximateNow() +
56                    3 * QuicTime::Delta::FromMilliseconds(kInitialRttMs)));
57   }
58 
59  protected:
60   quic::test::MockAlarmFactory alarm_factory_;
61   MockSendDelegate send_delegate_;
62   MockRandom random_;
63   MockClock clock_;
64   QuicConnectionArena arena_;
65   QuicPathValidator path_validator_;
66   QuicSocketAddress self_address_{QuicIpAddress::Any4(), 443};
67   QuicSocketAddress peer_address_{QuicIpAddress::Loopback4(), 443};
68   QuicSocketAddress effective_peer_address_{QuicIpAddress::Loopback4(), 12345};
69   MockPacketWriter writer_;
70   MockQuicPathValidationContext* context_;
71   MockQuicPathValidationResultDelegate* result_delegate_;
72 };
73 
TEST_F(QuicPathValidatorTest,PathValidationSuccessOnFirstRound)74 TEST_F(QuicPathValidatorTest, PathValidationSuccessOnFirstRound) {
75   QuicPathFrameBuffer challenge_data;
76   EXPECT_CALL(send_delegate_,
77               SendPathChallenge(_, self_address_, peer_address_,
78                                 effective_peer_address_, &writer_))
79       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
80                            const QuicSocketAddress&, const QuicSocketAddress&,
81                            const QuicSocketAddress&, QuicPacketWriter*) {
82         memcpy(challenge_data.data(), payload.data(), payload.size());
83         return true;
84       }));
85   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_));
86   const QuicTime expected_start_time = clock_.Now();
87   path_validator_.StartPathValidation(
88       std::unique_ptr<QuicPathValidationContext>(context_),
89       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
90       PathValidationReason::kMultiPort);
91   EXPECT_TRUE(path_validator_.HasPendingPathValidation());
92   EXPECT_EQ(PathValidationReason::kMultiPort,
93             path_validator_.GetPathValidationReason());
94   EXPECT_TRUE(path_validator_.IsValidatingPeerAddress(effective_peer_address_));
95   EXPECT_CALL(*result_delegate_, OnPathValidationSuccess(_, _))
96       .WillOnce(Invoke([=](std::unique_ptr<QuicPathValidationContext> context,
97                            QuicTime start_time) {
98         EXPECT_EQ(context.get(), context_);
99         EXPECT_EQ(start_time, expected_start_time);
100       }));
101   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(kInitialRttMs));
102   path_validator_.OnPathResponse(challenge_data, self_address_);
103   EXPECT_FALSE(path_validator_.HasPendingPathValidation());
104   EXPECT_EQ(PathValidationReason::kReasonUnknown,
105             path_validator_.GetPathValidationReason());
106 }
107 
TEST_F(QuicPathValidatorTest,RespondWithDifferentSelfAddress)108 TEST_F(QuicPathValidatorTest, RespondWithDifferentSelfAddress) {
109   QuicPathFrameBuffer challenge_data;
110   EXPECT_CALL(send_delegate_,
111               SendPathChallenge(_, self_address_, peer_address_,
112                                 effective_peer_address_, &writer_))
113       .WillOnce(Invoke([&](const QuicPathFrameBuffer payload,
114                            const QuicSocketAddress&, const QuicSocketAddress&,
115                            const QuicSocketAddress&, QuicPacketWriter*) {
116         memcpy(challenge_data.data(), payload.data(), payload.size());
117         return true;
118       }));
119   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_));
120   const QuicTime expected_start_time = clock_.Now();
121   path_validator_.StartPathValidation(
122       std::unique_ptr<QuicPathValidationContext>(context_),
123       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
124       PathValidationReason::kMultiPort);
125 
126   // Reception of a PATH_RESPONSE on a different self address should be ignored.
127   const QuicSocketAddress kAlternativeSelfAddress(QuicIpAddress::Any6(), 54321);
128   EXPECT_NE(kAlternativeSelfAddress, self_address_);
129   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(kInitialRttMs));
130   path_validator_.OnPathResponse(challenge_data, kAlternativeSelfAddress);
131 
132   EXPECT_CALL(*result_delegate_, OnPathValidationSuccess(_, _))
133       .WillOnce(Invoke([=](std::unique_ptr<QuicPathValidationContext> context,
134                            QuicTime start_time) {
135         EXPECT_EQ(context->self_address(), self_address_);
136         EXPECT_EQ(start_time, expected_start_time);
137       }));
138   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(kInitialRttMs));
139   path_validator_.OnPathResponse(challenge_data, self_address_);
140   EXPECT_EQ(PathValidationReason::kReasonUnknown,
141             path_validator_.GetPathValidationReason());
142 }
143 
TEST_F(QuicPathValidatorTest,RespondAfter1stRetry)144 TEST_F(QuicPathValidatorTest, RespondAfter1stRetry) {
145   QuicPathFrameBuffer challenge_data;
146   EXPECT_CALL(send_delegate_,
147               SendPathChallenge(_, self_address_, peer_address_,
148                                 effective_peer_address_, &writer_))
149       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
150                            const QuicSocketAddress&, const QuicSocketAddress&,
151                            const QuicSocketAddress&, QuicPacketWriter*) {
152         // Store up the 1st PATH_CHALLANGE payload.
153         memcpy(challenge_data.data(), payload.data(), payload.size());
154         return true;
155       }))
156       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
157                            const QuicSocketAddress&, const QuicSocketAddress&,
158                            const QuicSocketAddress&, QuicPacketWriter*) {
159         EXPECT_NE(payload, challenge_data);
160         return true;
161       }));
162   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
163       .Times(2u);
164   const QuicTime start_time = clock_.Now();
165   path_validator_.StartPathValidation(
166       std::unique_ptr<QuicPathValidationContext>(context_),
167       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
168       PathValidationReason::kMultiPort);
169 
170   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs));
171   random_.ChangeValue();
172   alarm_factory_.FireAlarm(
173       QuicPathValidatorPeer::retry_timer(&path_validator_));
174 
175   EXPECT_CALL(*result_delegate_, OnPathValidationSuccess(_, start_time));
176   // Respond to the 1st PATH_CHALLENGE should complete the validation.
177   path_validator_.OnPathResponse(challenge_data, self_address_);
178   EXPECT_FALSE(path_validator_.HasPendingPathValidation());
179 }
180 
TEST_F(QuicPathValidatorTest,RespondToRetryChallenge)181 TEST_F(QuicPathValidatorTest, RespondToRetryChallenge) {
182   QuicPathFrameBuffer challenge_data;
183   EXPECT_CALL(send_delegate_,
184               SendPathChallenge(_, self_address_, peer_address_,
185                                 effective_peer_address_, &writer_))
186       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
187                            const QuicSocketAddress&, const QuicSocketAddress&,
188                            const QuicSocketAddress&, QuicPacketWriter*) {
189         memcpy(challenge_data.data(), payload.data(), payload.size());
190         return true;
191       }))
192       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
193                            const QuicSocketAddress&, const QuicSocketAddress&,
194                            const QuicSocketAddress&, QuicPacketWriter*) {
195         EXPECT_NE(challenge_data, payload);
196         memcpy(challenge_data.data(), payload.data(), payload.size());
197         return true;
198       }));
199   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
200       .Times(2u);
201   path_validator_.StartPathValidation(
202       std::unique_ptr<QuicPathValidationContext>(context_),
203       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
204       PathValidationReason::kMultiPort);
205 
206   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs));
207   const QuicTime start_time = clock_.Now();
208   random_.ChangeValue();
209   alarm_factory_.FireAlarm(
210       QuicPathValidatorPeer::retry_timer(&path_validator_));
211 
212   // Respond to the 2nd PATH_CHALLENGE should complete the validation.
213   EXPECT_CALL(*result_delegate_, OnPathValidationSuccess(_, start_time));
214   path_validator_.OnPathResponse(challenge_data, self_address_);
215   EXPECT_FALSE(path_validator_.HasPendingPathValidation());
216 }
217 
TEST_F(QuicPathValidatorTest,ValidationTimeOut)218 TEST_F(QuicPathValidatorTest, ValidationTimeOut) {
219   EXPECT_CALL(send_delegate_,
220               SendPathChallenge(_, self_address_, peer_address_,
221                                 effective_peer_address_, &writer_))
222       .Times(3u)
223       .WillRepeatedly(Return(true));
224   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
225       .Times(3u);
226   path_validator_.StartPathValidation(
227       std::unique_ptr<QuicPathValidationContext>(context_),
228       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
229       PathValidationReason::kMultiPort);
230 
231   QuicPathFrameBuffer challenge_data;
232   memset(challenge_data.data(), 'a', challenge_data.size());
233   // Reception of a PATH_RESPONSE with different payload should be ignored.
234   path_validator_.OnPathResponse(challenge_data, self_address_);
235 
236   // Retry 3 times. The 3rd time should fail the validation.
237   EXPECT_CALL(*result_delegate_, OnPathValidationFailure(_))
238       .WillOnce(Invoke([=](std::unique_ptr<QuicPathValidationContext> context) {
239         EXPECT_EQ(context_, context.get());
240       }));
241   for (size_t i = 0; i <= QuicPathValidator::kMaxRetryTimes; ++i) {
242     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3 * kInitialRttMs));
243     alarm_factory_.FireAlarm(
244         QuicPathValidatorPeer::retry_timer(&path_validator_));
245   }
246   EXPECT_EQ(PathValidationReason::kReasonUnknown,
247             path_validator_.GetPathValidationReason());
248 }
249 
TEST_F(QuicPathValidatorTest,SendPathChallengeError)250 TEST_F(QuicPathValidatorTest, SendPathChallengeError) {
251   EXPECT_CALL(send_delegate_,
252               SendPathChallenge(_, self_address_, peer_address_,
253                                 effective_peer_address_, &writer_))
254       .WillOnce(Invoke([&](const QuicPathFrameBuffer&, const QuicSocketAddress&,
255                            const QuicSocketAddress&, const QuicSocketAddress&,
256                            QuicPacketWriter*) {
257         // Abandon this validation in the call stack shouldn't cause crash and
258         // should cancel the alarm.
259         path_validator_.CancelPathValidation();
260         return false;
261       }));
262   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
263       .Times(0u);
264   EXPECT_CALL(*result_delegate_, OnPathValidationFailure(_));
265   path_validator_.StartPathValidation(
266       std::unique_ptr<QuicPathValidationContext>(context_),
267       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_),
268       PathValidationReason::kMultiPort);
269   EXPECT_FALSE(path_validator_.HasPendingPathValidation());
270   EXPECT_FALSE(QuicPathValidatorPeer::retry_timer(&path_validator_)->IsSet());
271   EXPECT_EQ(PathValidationReason::kReasonUnknown,
272             path_validator_.GetPathValidationReason());
273 }
274 
275 }  // namespace test
276 }  // namespace quic
277