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