xref: /aosp_15_r20/external/cronet/net/dns/loopback_only_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
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/dns/loopback_only.h"
6 
7 #include <optional>
8 #include <unordered_set>
9 
10 #include "base/test/bind.h"
11 #include "base/test/task_environment.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "net/base/mock_network_change_notifier.h"
14 #include "net/base/network_change_notifier.h"
15 #include "net/base/test_completion_callback.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 #if BUILDFLAG(IS_LINUX)
19 #include <linux/if.h>
20 #include <linux/netlink.h>
21 #include <linux/rtnetlink.h>
22 
23 #include "net/base/address_map_linux.h"
24 #endif  // BUILDFLAG(IS_LINUX)
25 
26 namespace net {
27 
28 #if BUILDFLAG(IS_LINUX)
29 
30 namespace {
31 
32 constexpr uint8_t kIpv4LoopbackBytes[] = {127, 0, 0, 1};
33 constexpr uint8_t kIpv4PrivateAddressBytes[] = {10, 0, 0, 1};
34 constexpr uint8_t kIpv6LoopbackBytes[] = {0, 0, 0, 0, 0, 0, 0, 0,
35                                           0, 0, 0, 0, 0, 0, 0, 1};
36 constexpr uint8_t kIpv6AddressBytes[] = {0xFE, 0xDC, 0xBA, 0x98, 0, 0, 0, 0,
37                                          0,    0,    0,    0,    0, 0, 0, 0};
38 
39 constexpr uint8_t kIpv4LinkLocalBytes[] = {169, 254, 0, 0};
40 constexpr uint8_t kIpv4InIpv6LinkLocalBytes[] = {
41     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 169, 254, 0, 0};
42 constexpr uint8_t kIpv6LinkLocalBytes[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0,
43                                            0,    0,    0, 0, 0, 0, 0, 0};
44 
45 class StubAddressMapOwnerLinux : public AddressMapOwnerLinux {
46  public:
GetAddressMap() const47   AddressMap GetAddressMap() const override { return address_map_; }
GetOnlineLinks() const48   std::unordered_set<int> GetOnlineLinks() const override {
49     return online_links_;
50   }
51 
address_map()52   AddressMap& address_map() { return address_map_; }
online_links()53   std::unordered_set<int>& online_links() { return online_links_; }
54 
55  private:
56   AddressMap address_map_;
57   std::unordered_set<int> online_links_;
58 };
59 
GetResultOfRunHaveOnlyLoopbackAddressesJob()60 bool GetResultOfRunHaveOnlyLoopbackAddressesJob() {
61   bool result = false;
62   net::TestClosure completion;
63   {
64     base::ScopedDisallowBlocking disallow_blocking;
65     RunHaveOnlyLoopbackAddressesJob(
66         base::BindLambdaForTesting([&](bool loopback_result) {
67           result = loopback_result;
68           completion.closure().Run();
69         }));
70   }
71   completion.WaitForResult();
72   return result;
73 }
74 
75 }  // namespace
76 
77 class LoopbackOnlyTest : public ::testing::Test {
78  public:
79   static constexpr int kTestInterfaceEth = 1;
80   static constexpr int kTestInterfaceLoopback = 2;
81 
82   static inline const net::IPAddress kIpv4Loopback{kIpv4LoopbackBytes};
83   static inline const net::IPAddress kIpv4PrivateAddress{
84       kIpv4PrivateAddressBytes};
85 
86   static inline const net::IPAddress kIpv6Loopback{kIpv6LoopbackBytes};
87   static inline const net::IPAddress kIpv6Address{kIpv6AddressBytes};
88 
89   static inline const net::IPAddress kIpv4LinkLocal{kIpv4LinkLocalBytes};
90   static inline const net::IPAddress kIpv4InIpv6LinkLocal{
91       kIpv4InIpv6LinkLocalBytes};
92   static inline const net::IPAddress kIpv6LinkLocal{kIpv6LinkLocalBytes};
93 
LoopbackOnlyTest()94   LoopbackOnlyTest() {
95     mock_notifier_.mock_network_change_notifier()->SetAddressMapOwnerLinux(
96         &stub_address_map_owner_);
97   }
98   ~LoopbackOnlyTest() override = default;
99 
100  protected:
101   base::test::TaskEnvironment task_environment_;
102   test::ScopedMockNetworkChangeNotifier mock_notifier_;
103   StubAddressMapOwnerLinux stub_address_map_owner_;
104 };
105 
TEST_F(LoopbackOnlyTest,HasOnlyLoopbackIpv4)106 TEST_F(LoopbackOnlyTest, HasOnlyLoopbackIpv4) {
107   // Include only a loopback interface.
108   stub_address_map_owner_.address_map() = {
109       {kIpv4Loopback, ifaddrmsg{
110                           .ifa_family = AF_INET,
111                           .ifa_flags = IFA_F_TEMPORARY,
112                           .ifa_index = kTestInterfaceLoopback,
113                       }}};
114   // AddressTrackerLinux does not insert loopback interfaces into
115   // `online_links`.
116   stub_address_map_owner_.online_links() = {};
117 
118   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
119 }
120 
TEST_F(LoopbackOnlyTest,HasActiveIPv4Connection)121 TEST_F(LoopbackOnlyTest, HasActiveIPv4Connection) {
122   stub_address_map_owner_.address_map() = {
123       {kIpv4Loopback, ifaddrmsg{.ifa_family = AF_INET,
124                                 .ifa_flags = IFA_F_TEMPORARY,
125                                 .ifa_index = kTestInterfaceLoopback}},
126       {kIpv4PrivateAddress, ifaddrmsg{.ifa_family = AF_INET,
127                                       .ifa_flags = IFA_F_TEMPORARY,
128                                       .ifa_index = kTestInterfaceEth}}};
129   // `online_links` includes kTestInterfaceEth so that kIpv4PrivateAddress is
130   // the active IPv4 connection. Also, AddressTrackerLinux does not insert
131   // loopback interfaces into `online_links`.
132   stub_address_map_owner_.online_links() = {kTestInterfaceEth};
133 
134   EXPECT_FALSE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
135 }
136 
TEST_F(LoopbackOnlyTest,HasInactiveIPv4Connection)137 TEST_F(LoopbackOnlyTest, HasInactiveIPv4Connection) {
138   stub_address_map_owner_.address_map() = {
139       {kIpv4Loopback, ifaddrmsg{.ifa_family = AF_INET,
140                                 .ifa_flags = IFA_F_TEMPORARY,
141                                 .ifa_index = kTestInterfaceLoopback}},
142       {kIpv4PrivateAddress, ifaddrmsg{.ifa_family = AF_INET,
143                                       .ifa_flags = IFA_F_TEMPORARY,
144                                       .ifa_index = kTestInterfaceEth}}};
145   // `online_links` does not include kTestInterfaceEth so that
146   // kIpv4PrivateAddress is the inactive IPv4 connection. Also,
147   // AddressTrackerLinux does not insert loopback interfaces into
148   // `online_links`.
149   stub_address_map_owner_.online_links() = {};
150 
151   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
152 }
153 
TEST_F(LoopbackOnlyTest,HasOnlyLoopbackIpv6)154 TEST_F(LoopbackOnlyTest, HasOnlyLoopbackIpv6) {
155   // Include only a loopback interface.
156   stub_address_map_owner_.address_map() = {
157       {kIpv6Loopback, ifaddrmsg{
158                           .ifa_family = AF_INET6,
159                           .ifa_flags = IFA_F_TEMPORARY,
160                           .ifa_index = kTestInterfaceLoopback,
161                       }}};
162   // AddressTrackerLinux does not insert loopback interfaces into
163   // `online_links`.
164   stub_address_map_owner_.online_links() = {};
165 
166   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
167 }
168 
TEST_F(LoopbackOnlyTest,HasActiveIPv6Connection)169 TEST_F(LoopbackOnlyTest, HasActiveIPv6Connection) {
170   stub_address_map_owner_.address_map() = {
171       {kIpv6Loopback, ifaddrmsg{.ifa_family = AF_INET6,
172                                 .ifa_flags = IFA_F_TEMPORARY,
173                                 .ifa_index = kTestInterfaceLoopback}},
174       {kIpv6Address, ifaddrmsg{.ifa_family = AF_INET6,
175                                .ifa_flags = IFA_F_TEMPORARY,
176                                .ifa_index = kTestInterfaceEth}}};
177   // `online_links` includes kTestInterfaceEth so that kIpv6Address is the
178   // active IPv6 connection. Also, AddressTrackerLinux does not insert loopback
179   // interfaces into `online_links`.
180   stub_address_map_owner_.online_links() = {kTestInterfaceEth};
181 
182   EXPECT_FALSE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
183 }
184 
TEST_F(LoopbackOnlyTest,HasInactiveIPv6Connection)185 TEST_F(LoopbackOnlyTest, HasInactiveIPv6Connection) {
186   stub_address_map_owner_.address_map() = {
187       {kIpv6Loopback, ifaddrmsg{.ifa_family = AF_INET6,
188                                 .ifa_flags = IFA_F_TEMPORARY,
189                                 .ifa_index = kTestInterfaceLoopback}},
190       {kIpv6Address, ifaddrmsg{.ifa_family = AF_INET6,
191                                .ifa_flags = IFA_F_TEMPORARY,
192                                .ifa_index = kTestInterfaceEth}}};
193   // `online_links` does not include kTestInterfaceEth so that kIpv6Address is
194   // the inactive IPv6 connection. Also, AddressTrackerLinux does not insert
195   // loopback interfaces into `online_links`.
196   stub_address_map_owner_.online_links() = {};
197 
198   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
199 }
200 
TEST_F(LoopbackOnlyTest,IPv6LinkLocal)201 TEST_F(LoopbackOnlyTest, IPv6LinkLocal) {
202   // Include only IPv6 link-local interfaces.
203   stub_address_map_owner_.address_map() = {
204       {kIpv6LinkLocal, ifaddrmsg{
205                            .ifa_family = AF_INET6,
206                            .ifa_flags = IFA_F_TEMPORARY,
207                            .ifa_index = 3,
208                        }}};
209   // Mark the IPv6 link-local interface as online.
210   stub_address_map_owner_.online_links() = {3};
211 
212   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
213 }
214 
TEST_F(LoopbackOnlyTest,ExtraOnlineLinks)215 TEST_F(LoopbackOnlyTest, ExtraOnlineLinks) {
216   // Include only IPv6 link-local interfaces.
217   stub_address_map_owner_.address_map() = {
218       {kIpv6LinkLocal, ifaddrmsg{
219                            .ifa_family = AF_INET6,
220                            .ifa_flags = IFA_F_TEMPORARY,
221                            .ifa_index = 3,
222                        }}};
223   // AddressTrackerLinux should not give us online links other than the ones
224   // listed in the AddressMap. However, it's better if this code is resilient to
225   // a mismatch if there is a bug (for example if the kernel truncates the
226   // messages or the buffer the AddressTrackerLinux provides to the kernel is
227   // too small). And if this code runs on a different thread from the
228   // AddressMapOwnerLinux, AddressMap and online links are updated separately,
229   // and so it is possible they can be inconsistent with each other.
230   stub_address_map_owner_.online_links() = {1, 2, 3};
231 
232   EXPECT_TRUE(GetResultOfRunHaveOnlyLoopbackAddressesJob());
233 }
234 
235 // TODO(crbug.com/1450403): Test HaveOnlyLoopbackAddressesUsingGetifaddrs().
236 
237 #endif  // BUILDFLAG(IS_LINUX)
238 
239 }  // namespace net
240