xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/bonnet/icmp_reachable_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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