1 // Copyright (c) 2019 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/qbone/bonnet/icmp_reachable.h"
6
7 #include <netinet/ip6.h>
8
9 #include <memory>
10
11 #include "absl/container/node_hash_map.h"
12 #include "quiche/quic/core/io/quic_default_event_loop.h"
13 #include "quiche/quic/core/io/quic_event_loop.h"
14 #include "quiche/quic/core/quic_default_clock.h"
15 #include "quiche/quic/platform/api/quic_ip_address.h"
16 #include "quiche/quic/platform/api/quic_test.h"
17 #include "quiche/quic/qbone/platform/mock_kernel.h"
18
19 namespace quic::test {
20 namespace {
21
22 using ::testing::_;
23 using ::testing::InSequence;
24 using ::testing::Invoke;
25 using ::testing::Return;
26 using ::testing::StrictMock;
27
28 constexpr char kSourceAddress[] = "fe80:1:2:3:4::1";
29 constexpr char kDestinationAddress[] = "fe80:4:3:2:1::1";
30
31 constexpr int kFakeWriteFd = 0;
32
GetHeaderFromPacket(const void * buf,size_t len)33 icmp6_hdr GetHeaderFromPacket(const void* buf, size_t len) {
34 QUICHE_CHECK_GE(len, sizeof(ip6_hdr) + sizeof(icmp6_hdr));
35
36 auto* buffer = reinterpret_cast<const char*>(buf);
37 return *reinterpret_cast<const icmp6_hdr*>(&buffer[sizeof(ip6_hdr)]);
38 }
39
40 class StatsInterface : public IcmpReachable::StatsInterface {
41 public:
OnEvent(IcmpReachable::ReachableEvent event)42 void OnEvent(IcmpReachable::ReachableEvent event) override {
43 switch (event.status) {
44 case IcmpReachable::REACHABLE: {
45 reachable_count_++;
46 break;
47 }
48 case IcmpReachable::UNREACHABLE: {
49 unreachable_count_++;
50 break;
51 }
52 }
53 current_source_ = event.source;
54 }
55
OnReadError(int error)56 void OnReadError(int error) override { read_errors_[error]++; }
57
OnWriteError(int error)58 void OnWriteError(int error) override { write_errors_[error]++; }
59
HasWriteErrors()60 bool HasWriteErrors() { return !write_errors_.empty(); }
61
WriteErrorCount(int error)62 int WriteErrorCount(int error) { return write_errors_[error]; }
63
HasReadErrors()64 bool HasReadErrors() { return !read_errors_.empty(); }
65
ReadErrorCount(int error)66 int ReadErrorCount(int error) { return read_errors_[error]; }
67
reachable_count()68 int reachable_count() { return reachable_count_; }
69
unreachable_count()70 int unreachable_count() { return unreachable_count_; }
71
current_source()72 std::string current_source() { return current_source_; }
73
74 private:
75 int reachable_count_ = 0;
76 int unreachable_count_ = 0;
77
78 std::string current_source_{};
79
80 absl::node_hash_map<int, int> read_errors_;
81 absl::node_hash_map<int, int> write_errors_;
82 };
83
84 class IcmpReachableTest : public QuicTest {
85 public:
IcmpReachableTest()86 IcmpReachableTest()
87 : event_loop_(GetDefaultEventLoop()->Create(QuicDefaultClock::Get())) {
88 QUICHE_CHECK(source_.FromString(kSourceAddress));
89 QUICHE_CHECK(destination_.FromString(kDestinationAddress));
90
91 int pipe_fds[2];
92 QUICHE_CHECK(pipe(pipe_fds) >= 0) << "pipe() failed";
93
94 read_fd_ = pipe_fds[0];
95 read_src_fd_ = pipe_fds[1];
96 }
97
SetFdExpectations()98 void SetFdExpectations() {
99 InSequence seq;
100 EXPECT_CALL(kernel_, socket(_, _, _)).WillOnce(Return(kFakeWriteFd));
101 EXPECT_CALL(kernel_, bind(kFakeWriteFd, _, _)).WillOnce(Return(0));
102
103 EXPECT_CALL(kernel_, socket(_, _, _)).WillOnce(Return(read_fd_));
104 EXPECT_CALL(kernel_, bind(read_fd_, _, _)).WillOnce(Return(0));
105
106 EXPECT_CALL(kernel_, setsockopt(read_fd_, SOL_ICMPV6, ICMP6_FILTER, _, _));
107
108 EXPECT_CALL(kernel_, close(read_fd_)).WillOnce(Invoke([](int fd) {
109 return close(fd);
110 }));
111 }
112
113 protected:
114 QuicIpAddress source_;
115 QuicIpAddress destination_;
116
117 int read_fd_;
118 int read_src_fd_;
119
120 StrictMock<MockKernel> kernel_;
121 std::unique_ptr<QuicEventLoop> event_loop_;
122 StatsInterface stats_;
123 };
124
TEST_F(IcmpReachableTest,SendsPings)125 TEST_F(IcmpReachableTest, SendsPings) {
126 IcmpReachable reachable(source_, destination_, QuicTime::Delta::Zero(),
127 &kernel_, event_loop_.get(), &stats_);
128
129 SetFdExpectations();
130 ASSERT_TRUE(reachable.Init());
131
132 EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
133 .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
134 const struct sockaddr* dest_addr, socklen_t addrlen) {
135 auto icmp_header = GetHeaderFromPacket(buf, len);
136 EXPECT_EQ(icmp_header.icmp6_type, ICMP6_ECHO_REQUEST);
137 EXPECT_EQ(icmp_header.icmp6_seq, 1);
138 return len;
139 }));
140
141 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
142 EXPECT_FALSE(stats_.HasWriteErrors());
143 }
144
TEST_F(IcmpReachableTest,HandlesUnreachableEvents)145 TEST_F(IcmpReachableTest, HandlesUnreachableEvents) {
146 IcmpReachable reachable(source_, destination_, QuicTime::Delta::Zero(),
147 &kernel_, event_loop_.get(), &stats_);
148
149 SetFdExpectations();
150 ASSERT_TRUE(reachable.Init());
151
152 EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
153 .Times(2)
154 .WillRepeatedly(Invoke([](int sockfd, const void* buf, size_t len,
155 int flags, const struct sockaddr* dest_addr,
156 socklen_t addrlen) { return len; }));
157
158 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
159 EXPECT_EQ(stats_.unreachable_count(), 0);
160
161 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
162 EXPECT_FALSE(stats_.HasWriteErrors());
163 EXPECT_EQ(stats_.unreachable_count(), 1);
164 EXPECT_EQ(stats_.current_source(), kNoSource);
165 }
166
TEST_F(IcmpReachableTest,HandlesReachableEvents)167 TEST_F(IcmpReachableTest, HandlesReachableEvents) {
168 IcmpReachable reachable(source_, destination_, QuicTime::Delta::Zero(),
169 &kernel_, event_loop_.get(), &stats_);
170
171 SetFdExpectations();
172 ASSERT_TRUE(reachable.Init());
173
174 icmp6_hdr last_request_hdr{};
175 EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
176 .Times(2)
177 .WillRepeatedly(
178 Invoke([&last_request_hdr](
179 int sockfd, const void* buf, size_t len, int flags,
180 const struct sockaddr* dest_addr, socklen_t addrlen) {
181 last_request_hdr = GetHeaderFromPacket(buf, len);
182 return len;
183 }));
184
185 sockaddr_in6 source_addr{};
186 std::string packed_source = source_.ToPackedString();
187 memcpy(&source_addr.sin6_addr, packed_source.data(), packed_source.size());
188
189 EXPECT_CALL(kernel_, recvfrom(read_fd_, _, _, _, _, _))
190 .WillOnce(
191 Invoke([&source_addr](int sockfd, void* buf, size_t len, int flags,
192 struct sockaddr* src_addr, socklen_t* addrlen) {
193 *reinterpret_cast<sockaddr_in6*>(src_addr) = source_addr;
194 return read(sockfd, buf, len);
195 }));
196
197 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
198 EXPECT_EQ(stats_.reachable_count(), 0);
199
200 icmp6_hdr response = last_request_hdr;
201 response.icmp6_type = ICMP6_ECHO_REPLY;
202
203 write(read_src_fd_, reinterpret_cast<const void*>(&response),
204 sizeof(icmp6_hdr));
205
206 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
207 EXPECT_FALSE(stats_.HasReadErrors());
208 EXPECT_FALSE(stats_.HasWriteErrors());
209 EXPECT_EQ(stats_.reachable_count(), 1);
210 EXPECT_EQ(stats_.current_source(), source_.ToString());
211 }
212
TEST_F(IcmpReachableTest,HandlesWriteErrors)213 TEST_F(IcmpReachableTest, HandlesWriteErrors) {
214 IcmpReachable reachable(source_, destination_, QuicTime::Delta::Zero(),
215 &kernel_, event_loop_.get(), &stats_);
216
217 SetFdExpectations();
218 ASSERT_TRUE(reachable.Init());
219
220 EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
221 .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
222 const struct sockaddr* dest_addr, socklen_t addrlen) {
223 errno = EAGAIN;
224 return 0;
225 }));
226
227 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
228 EXPECT_EQ(stats_.WriteErrorCount(EAGAIN), 1);
229 }
230
TEST_F(IcmpReachableTest,HandlesReadErrors)231 TEST_F(IcmpReachableTest, HandlesReadErrors) {
232 IcmpReachable reachable(source_, destination_, QuicTime::Delta::Zero(),
233 &kernel_, event_loop_.get(), &stats_);
234
235 SetFdExpectations();
236 ASSERT_TRUE(reachable.Init());
237
238 EXPECT_CALL(kernel_, sendto(kFakeWriteFd, _, _, _, _, _))
239 .WillOnce(Invoke([](int sockfd, const void* buf, size_t len, int flags,
240 const struct sockaddr* dest_addr,
241 socklen_t addrlen) { return len; }));
242
243 EXPECT_CALL(kernel_, recvfrom(read_fd_, _, _, _, _, _))
244 .WillOnce(Invoke([](int sockfd, void* buf, size_t len, int flags,
245 struct sockaddr* src_addr, socklen_t* addrlen) {
246 errno = EIO;
247 return -1;
248 }));
249
250 icmp6_hdr response{};
251
252 write(read_src_fd_, reinterpret_cast<const void*>(&response),
253 sizeof(icmp6_hdr));
254
255 event_loop_->RunEventLoopOnce(QuicTime::Delta::FromSeconds(1));
256 EXPECT_EQ(stats_.reachable_count(), 0);
257 EXPECT_EQ(stats_.ReadErrorCount(EIO), 1);
258 }
259
260 } // namespace
261 } // namespace quic::test
262