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