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