blob: 3dde20cb996a298e41758f0be99eb0448834a817 [file] [log] [blame]
Garrick Evans5fe2a4f2021-02-03 17:04:48 +09001// Copyright 2021 The Chromium OS 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 "dns-proxy/proxy.h"
6
7#include <fcntl.h>
8#include <sys/stat.h>
9
10#include <memory>
11#include <utility>
Garrick Evans2ca050d2021-02-09 18:21:36 +090012#include <vector>
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090013
14#include <chromeos/patchpanel/net_util.h>
15#include <chromeos/patchpanel/dbus/fake_client.h>
16#include <dbus/mock_bus.h>
17#include <gmock/gmock.h>
18#include <gtest/gtest.h>
19#include <shill/dbus/client/fake_client.h>
20#include <shill/dbus-constants.h>
21#include <shill/dbus-proxy-mocks.h>
22
23namespace dns_proxy {
Jason Jeremy Iman1bb71c22021-01-26 21:49:55 +090024namespace {
25constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10000);
Jason Jeremy Iman845f2932021-01-31 16:12:13 +090026constexpr base::TimeDelta kRequestRetryDelay =
27 base::TimeDelta::FromMilliseconds(200);
28constexpr int32_t kRequestMaxRetry = 1;
29
Jason Jeremy Iman1bb71c22021-01-26 21:49:55 +090030} // namespace
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090031using org::chromium::flimflam::ManagerProxyInterface;
32using org::chromium::flimflam::ManagerProxyMock;
33using testing::_;
Garrick Evans09646fe2021-04-27 14:38:41 +090034using testing::DoAll;
Garrick Evansd41fdbf2021-03-03 09:15:48 +090035using testing::IsEmpty;
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090036using testing::Return;
Garrick Evansadde9852021-02-15 20:16:53 +090037using testing::SetArgPointee;
Garrick Evans2ca050d2021-02-09 18:21:36 +090038using testing::StrEq;
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090039
40class FakeShillClient : public shill::FakeClient {
41 public:
42 FakeShillClient(scoped_refptr<dbus::Bus> bus,
43 ManagerProxyInterface* manager_proxy)
44 : shill::FakeClient(bus), manager_proxy_(manager_proxy) {}
45
46 std::unique_ptr<shill::Client::ManagerPropertyAccessor> ManagerProperties(
47 const base::TimeDelta& timeout) const override {
48 return std::make_unique<shill::Client::ManagerPropertyAccessor>(
49 manager_proxy_);
50 }
51
Garrick Evansadde9852021-02-15 20:16:53 +090052 std::unique_ptr<shill::Client::Device> DefaultDevice(
53 bool exclude_vpn) override {
54 return std::move(default_device_);
55 }
56
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090057 bool IsInitialized() const { return init_; }
58
Garrick Evansadde9852021-02-15 20:16:53 +090059 std::unique_ptr<shill::Client::Device> default_device_;
60
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090061 private:
62 ManagerProxyInterface* manager_proxy_;
63};
64
65class FakePatchpanelClient : public patchpanel::FakeClient {
66 public:
67 FakePatchpanelClient() = default;
68 ~FakePatchpanelClient() = default;
69
70 void SetConnectNamespaceResult(
71 int fd, const patchpanel::ConnectNamespaceResponse& resp) {
72 ns_fd_ = fd;
73 ns_resp_ = resp;
74 }
75
76 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
77 ConnectNamespace(pid_t pid,
78 const std::string& outbound_ifname,
79 bool forward_user_traffic,
80 bool route_on_vpn,
81 patchpanel::TrafficCounter::Source traffic_source) override {
82 ns_ifname_ = outbound_ifname;
83 ns_rvpn_ = route_on_vpn;
84 ns_ts_ = traffic_source;
85 return {base::ScopedFD(ns_fd_), ns_resp_};
86 }
87
88 std::string ns_ifname_;
89 bool ns_rvpn_;
90 patchpanel::TrafficCounter::Source ns_ts_;
91 int ns_fd_;
92 patchpanel::ConnectNamespaceResponse ns_resp_;
93};
94
Garrick Evans2ca050d2021-02-09 18:21:36 +090095class MockResolver : public Resolver {
96 public:
Jason Jeremy Iman845f2932021-01-31 16:12:13 +090097 MockResolver()
98 : Resolver(kRequestTimeout, kRequestRetryDelay, kRequestMaxRetry) {}
Garrick Evans2ca050d2021-02-09 18:21:36 +090099 ~MockResolver() = default;
100
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900101 MOCK_METHOD(bool, ListenUDP, (struct sockaddr*), (override));
102 MOCK_METHOD(bool, ListenTCP, (struct sockaddr*), (override));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900103 MOCK_METHOD(void,
104 SetNameServers,
105 (const std::vector<std::string>&),
106 (override));
107 MOCK_METHOD(void,
108 SetDoHProviders,
109 (const std::vector<std::string>&, bool),
110 (override));
111};
112
113class TestProxy : public Proxy {
114 public:
115 TestProxy(const Options& opts,
116 std::unique_ptr<patchpanel::Client> patchpanel,
117 std::unique_ptr<shill::Client> shill)
118 : Proxy(opts, std::move(patchpanel), std::move(shill)) {}
119
120 std::unique_ptr<Resolver> resolver;
Jason Jeremy Iman845f2932021-01-31 16:12:13 +0900121 std::unique_ptr<Resolver> NewResolver(base::TimeDelta timeout,
122 base::TimeDelta retry_delay,
123 int max_num_retries) override {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900124 return std::move(resolver);
125 }
126};
127
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900128class ProxyTest : public ::testing::Test {
129 protected:
130 ProxyTest() : mock_bus_(new dbus::MockBus{dbus::Bus::Options{}}) {}
131 ~ProxyTest() { mock_bus_->ShutdownAndBlock(); }
132
133 std::unique_ptr<FakePatchpanelClient> PatchpanelClient() const {
134 return std::make_unique<FakePatchpanelClient>();
135 }
136
137 std::unique_ptr<FakeShillClient> ShillClient() const {
138 return std::make_unique<FakeShillClient>(
139 mock_bus_, reinterpret_cast<ManagerProxyInterface*>(
140 const_cast<ManagerProxyMock*>(&mock_manager_)));
141 }
142
143 int make_fd() const {
144 std::string fn(
145 ::testing::UnitTest::GetInstance()->current_test_info()->name());
146 fn = "/tmp/" + fn;
147 return open(fn.c_str(), O_CREAT, 0600);
148 }
149
150 protected:
151 scoped_refptr<dbus::MockBus> mock_bus_;
152 ManagerProxyMock mock_manager_;
153};
154
155TEST_F(ProxyTest, SystemProxy_OnShutdownClearsAddressPropertyOnShill) {
156 EXPECT_CALL(mock_manager_, SetProperty(shill::kDNSProxyIPv4AddressProperty,
157 brillo::Any(std::string()), _, _))
158 .WillOnce(Return(true));
159 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
160 ShillClient());
161 int unused;
162 proxy.OnShutdown(&unused);
163}
164
165TEST_F(ProxyTest, NonSystemProxy_OnShutdownDoesNotCallShill) {
166 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
167 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
168 ShillClient());
169 int unused;
170 proxy.OnShutdown(&unused);
171}
172
173TEST_F(ProxyTest, SystemProxy_SetShillPropertyWithNoRetriesCrashes) {
174 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
175 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
176 ShillClient());
177 EXPECT_DEATH(proxy.SetShillProperty("10.10.10.10", true, 0), "");
178}
179
180TEST_F(ProxyTest, SystemProxy_SetShillPropertyDoesntCrashIfDieFalse) {
181 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
182 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
183 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
184 ShillClient());
185 proxy.SetShillProperty("10.10.10.10", false, 0);
186}
187
Garrick Evansab03c462021-02-15 20:54:20 +0900188TEST_F(ProxyTest, ShillInitializedWhenReady) {
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900189 auto shill = ShillClient();
190 auto* shill_ptr = shill.get();
191 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
192 std::move(shill));
Garrick Evansab03c462021-02-15 20:54:20 +0900193 proxy.OnShillReady(true);
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900194 EXPECT_TRUE(shill_ptr->IsInitialized());
195}
196
197TEST_F(ProxyTest, SystemProxy_ConnectedNamedspace) {
198 auto pp = PatchpanelClient();
199 auto* pp_ptr = pp.get();
200 pp->SetConnectNamespaceResult(make_fd(),
201 patchpanel::ConnectNamespaceResponse());
202 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
203 ShillClient());
204 proxy.OnPatchpanelReady(true);
205 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
206 EXPECT_FALSE(pp_ptr->ns_rvpn_);
207 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::SYSTEM);
208}
209
210TEST_F(ProxyTest, DefaultProxy_ConnectedNamedspace) {
211 auto pp = PatchpanelClient();
212 auto* pp_ptr = pp.get();
213 pp->SetConnectNamespaceResult(make_fd(),
214 patchpanel::ConnectNamespaceResponse());
215 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, std::move(pp),
216 ShillClient());
217 proxy.OnPatchpanelReady(true);
218 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
219 EXPECT_TRUE(pp_ptr->ns_rvpn_);
220 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::USER);
221}
222
223TEST_F(ProxyTest, ArcProxy_ConnectedNamedspace) {
224 auto pp = PatchpanelClient();
225 auto* pp_ptr = pp.get();
226 pp->SetConnectNamespaceResult(make_fd(),
227 patchpanel::ConnectNamespaceResponse());
228 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
229 std::move(pp), ShillClient());
230 proxy.OnPatchpanelReady(true);
231 EXPECT_EQ(pp_ptr->ns_ifname_, "eth0");
232 EXPECT_FALSE(pp_ptr->ns_rvpn_);
233 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::ARC);
234}
235
236TEST_F(ProxyTest, CrashOnConnectNamespaceFailure) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900237 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900238 auto pp = PatchpanelClient();
239 pp->SetConnectNamespaceResult(-1 /* invalid fd */,
240 patchpanel::ConnectNamespaceResponse());
241 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
242 std::move(pp), ShillClient());
243 EXPECT_DEATH(proxy.OnPatchpanelReady(true), "namespace");
244}
245
246TEST_F(ProxyTest, CrashOnPatchpanelNotReady) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900247 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900248 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
249 PatchpanelClient(), ShillClient());
250 EXPECT_DEATH(proxy.OnPatchpanelReady(false), "patchpanel");
251}
252
253TEST_F(ProxyTest, ShillResetRestoresAddressProperty) {
254 auto pp = PatchpanelClient();
255 patchpanel::ConnectNamespaceResponse resp;
Garrick Evansab03c462021-02-15 20:54:20 +0900256 resp.set_peer_ipv4_address(patchpanel::Ipv4Addr(10, 10, 10, 10));
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900257 pp->SetConnectNamespaceResult(make_fd(), resp);
258 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
259 ShillClient());
260 proxy.OnPatchpanelReady(true);
261 EXPECT_CALL(mock_manager_,
262 SetProperty(shill::kDNSProxyIPv4AddressProperty,
263 brillo::Any(std::string("10.10.10.10")), _, _))
264 .WillOnce(Return(true));
265 proxy.OnShillReset(true);
266}
267
Garrick Evans2ca050d2021-02-09 18:21:36 +0900268TEST_F(ProxyTest, StateClearedIfDefaultServiceDrops) {
269 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
270 ShillClient());
271 proxy.device_ = std::make_unique<shill::Client::Device>();
272 proxy.resolver_ = std::make_unique<MockResolver>();
273 proxy.OnDefaultDeviceChanged(nullptr /* no service */);
274 EXPECT_FALSE(proxy.device_);
275 EXPECT_FALSE(proxy.resolver_);
276}
277
278TEST_F(ProxyTest, ArcProxy_IgnoredIfDefaultServiceDrops) {
279 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC}, PatchpanelClient(),
280 ShillClient());
281 proxy.device_ = std::make_unique<shill::Client::Device>();
282 proxy.resolver_ = std::make_unique<MockResolver>();
283 proxy.OnDefaultDeviceChanged(nullptr /* no service */);
284 EXPECT_TRUE(proxy.device_);
285 EXPECT_TRUE(proxy.resolver_);
286}
287
288TEST_F(ProxyTest, StateClearedIfDefaultServiceIsNotOnline) {
289 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
290 ShillClient());
291 proxy.device_ = std::make_unique<shill::Client::Device>();
292 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
293 proxy.resolver_ = std::make_unique<MockResolver>();
294 shill::Client::Device dev;
295 dev.state = shill::Client::Device::ConnectionState::kReady;
296 proxy.OnDefaultDeviceChanged(&dev);
297 EXPECT_FALSE(proxy.device_);
298 EXPECT_FALSE(proxy.resolver_);
299}
300
301TEST_F(ProxyTest, NewResolverStartsListeningOnDefaultServiceComesOnline) {
302 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kDefault},
303 PatchpanelClient(), ShillClient());
304 proxy.device_ = std::make_unique<shill::Client::Device>();
305 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
306 auto resolver = std::make_unique<MockResolver>();
307 MockResolver* mock_resolver = resolver.get();
308 proxy.resolver = std::move(resolver);
309 shill::Client::Device dev;
310 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900311 EXPECT_CALL(*mock_resolver, ListenUDP(_)).WillOnce(Return(true));
312 EXPECT_CALL(*mock_resolver, ListenTCP(_)).WillOnce(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900313 brillo::VariantDictionary props;
314 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
315 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900316 proxy.OnDefaultDeviceChanged(&dev);
317 EXPECT_TRUE(proxy.resolver_);
318}
319
320TEST_F(ProxyTest, CrashOnListenFailure) {
321 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
322 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
323 PatchpanelClient(), ShillClient());
324 proxy.device_ = std::make_unique<shill::Client::Device>();
325 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
326 auto resolver = std::make_unique<MockResolver>();
327 MockResolver* mock_resolver = resolver.get();
328 proxy.resolver = std::move(resolver);
329 shill::Client::Device dev;
330 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900331 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(false));
332 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(false));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900333 EXPECT_DEATH(proxy.OnDefaultDeviceChanged(&dev), "relay loop");
334}
335
336TEST_F(ProxyTest, NameServersUpdatedOnDefaultServiceComesOnline) {
337 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
338 ShillClient());
339 proxy.device_ = std::make_unique<shill::Client::Device>();
340 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
341 auto resolver = std::make_unique<MockResolver>();
342 MockResolver* mock_resolver = resolver.get();
343 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900344 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900345 shill::Client::Device dev;
346 dev.state = shill::Client::Device::ConnectionState::kOnline;
347 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
348 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
349 // Doesn't call listen since the resolver already exists.
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900350 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
351 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900352 EXPECT_CALL(*mock_resolver,
353 SetNameServers(
354 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
355 proxy.OnDefaultDeviceChanged(&dev);
356}
357
358TEST_F(ProxyTest, SystemProxy_ShillPropertyUpdatedOnDefaultServiceComesOnline) {
359 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
360 ShillClient());
361 proxy.device_ = std::make_unique<shill::Client::Device>();
362 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
363 auto resolver = std::make_unique<MockResolver>();
364 MockResolver* mock_resolver = resolver.get();
365 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900366 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900367 shill::Client::Device dev;
368 dev.state = shill::Client::Device::ConnectionState::kOnline;
369 EXPECT_CALL(*mock_resolver, SetNameServers(_));
370 EXPECT_CALL(mock_manager_,
371 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
372 .WillOnce(Return(true));
373 proxy.OnDefaultDeviceChanged(&dev);
374}
375
Garrick Evansadde9852021-02-15 20:16:53 +0900376TEST_F(ProxyTest, SystemProxy_IgnoresVPN) {
377 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
378 PatchpanelClient(), ShillClient());
379 auto resolver = std::make_unique<MockResolver>();
380 MockResolver* mock_resolver = resolver.get();
381 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
382 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900383 brillo::VariantDictionary props;
384 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
385 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900386 EXPECT_CALL(mock_manager_,
387 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
388 .WillOnce(Return(true));
389 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900390 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900391 shill::Client::Device dev;
392 dev.type = shill::Client::Device::Type::kWifi;
393 dev.state = shill::Client::Device::ConnectionState::kOnline;
394 proxy.OnDefaultDeviceChanged(&dev);
395 EXPECT_TRUE(proxy.device_);
396 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
397 dev.type = shill::Client::Device::Type::kVPN;
398 proxy.OnDefaultDeviceChanged(&dev);
399 EXPECT_TRUE(proxy.device_);
400 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
401}
402
403TEST_F(ProxyTest, SystemProxy_GetsPhysicalDeviceOnInitialVPN) {
404 auto shill = ShillClient();
405 auto* shill_ptr = shill.get();
406 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
407 PatchpanelClient(), std::move(shill));
408 auto resolver = std::make_unique<MockResolver>();
409 MockResolver* mock_resolver = resolver.get();
410 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
411 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900412 brillo::VariantDictionary props;
413 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
414 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900415 EXPECT_CALL(mock_manager_,
416 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
417 .WillOnce(Return(true));
418 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900419 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900420 shill::Client::Device vpn;
421 vpn.type = shill::Client::Device::Type::kVPN;
422 vpn.state = shill::Client::Device::ConnectionState::kOnline;
423 shill_ptr->default_device_ = std::make_unique<shill::Client::Device>();
424 shill_ptr->default_device_->type = shill::Client::Device::Type::kWifi;
425 shill_ptr->default_device_->state =
426 shill::Client::Device::ConnectionState::kOnline;
427 proxy.OnDefaultDeviceChanged(&vpn);
428 EXPECT_TRUE(proxy.device_);
429 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
430}
431
432TEST_F(ProxyTest, DefaultProxy_UsesVPN) {
433 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kDefault},
434 PatchpanelClient(), ShillClient());
435 auto resolver = std::make_unique<MockResolver>();
436 MockResolver* mock_resolver = resolver.get();
437 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
438 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900439 brillo::VariantDictionary props;
440 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
441 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900442 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900443 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900444 shill::Client::Device dev;
445 dev.type = shill::Client::Device::Type::kWifi;
446 dev.state = shill::Client::Device::ConnectionState::kOnline;
447 proxy.OnDefaultDeviceChanged(&dev);
448 EXPECT_TRUE(proxy.device_);
449 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
450 dev.type = shill::Client::Device::Type::kVPN;
451 proxy.OnDefaultDeviceChanged(&dev);
452 EXPECT_TRUE(proxy.device_);
453 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kVPN);
454}
455
Garrick Evansa8c12be2021-02-17 16:06:45 +0900456TEST_F(ProxyTest, NameServersUpdatedOnDeviceChangeEvent) {
457 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
458 ShillClient());
459 proxy.device_ = std::make_unique<shill::Client::Device>();
460 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
461 auto resolver = std::make_unique<MockResolver>();
462 MockResolver* mock_resolver = resolver.get();
463 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900464 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansa8c12be2021-02-17 16:06:45 +0900465 shill::Client::Device dev;
466 dev.state = shill::Client::Device::ConnectionState::kOnline;
467 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
468 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
469 // Doesn't call listen since the resolver already exists.
470 EXPECT_CALL(mock_manager_,
471 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
472 .WillOnce(Return(true));
473 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
474 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
475 EXPECT_CALL(*mock_resolver,
476 SetNameServers(
477 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
478 proxy.OnDefaultDeviceChanged(&dev);
479
480 // Now trigger an ipconfig change.
481 dev.ipconfig.ipv4_dns_addresses = {"X"};
482 EXPECT_CALL(*mock_resolver,
483 SetNameServers(ElementsAre(StrEq("X"), StrEq("c"), StrEq("d"))));
484 proxy.OnDeviceChanged(&dev);
485}
486
487TEST_F(ProxyTest, DeviceChangeEventIgnored) {
488 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
489 ShillClient());
490 proxy.device_ = std::make_unique<shill::Client::Device>();
491 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
492 auto resolver = std::make_unique<MockResolver>();
493 MockResolver* mock_resolver = resolver.get();
494 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900495 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansa8c12be2021-02-17 16:06:45 +0900496 shill::Client::Device dev;
497 dev.ifname = "eth0";
498 dev.state = shill::Client::Device::ConnectionState::kOnline;
499 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
500 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
501 // Doesn't call listen since the resolver already exists.
502 EXPECT_CALL(mock_manager_,
503 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
504 .WillOnce(Return(true));
505 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
506 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
507 EXPECT_CALL(*mock_resolver,
508 SetNameServers(
509 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
510 proxy.OnDefaultDeviceChanged(&dev);
511
512 // No change to ipconfig, no call to SetNameServers
513 proxy.OnDeviceChanged(&dev);
514
515 // Different ifname, no call to SetNameServers
516 dev.ifname = "wlan0";
517 proxy.OnDeviceChanged(&dev);
518}
519
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900520TEST_F(ProxyTest, BasicDoHDisable) {
521 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
522 ShillClient());
523 proxy.device_ = std::make_unique<shill::Client::Device>();
524 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
525 auto resolver = std::make_unique<MockResolver>();
526 MockResolver* mock_resolver = resolver.get();
527 proxy.resolver_ = std::move(resolver);
528 proxy.doh_config_.set_resolver(mock_resolver);
529 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900530 brillo::VariantDictionary props;
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900531 proxy.OnDoHProvidersChanged(props);
532}
533
534TEST_F(ProxyTest, BasicDoHAlwaysOn) {
535 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
536 ShillClient());
537 proxy.device_ = std::make_unique<shill::Client::Device>();
538 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
539 auto resolver = std::make_unique<MockResolver>();
540 MockResolver* mock_resolver = resolver.get();
541 proxy.resolver_ = std::move(resolver);
542 proxy.doh_config_.set_resolver(mock_resolver);
543 EXPECT_CALL(
544 *mock_resolver,
545 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), true));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900546 brillo::VariantDictionary props;
547 props["https://dns.google.com"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900548 proxy.OnDoHProvidersChanged(props);
549}
550
551TEST_F(ProxyTest, BasicDoHAutomatic) {
552 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
553 ShillClient());
554 proxy.device_ = std::make_unique<shill::Client::Device>();
555 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
556 auto resolver = std::make_unique<MockResolver>();
557 MockResolver* mock_resolver = resolver.get();
558 proxy.resolver_ = std::move(resolver);
559 proxy.doh_config_.set_resolver(mock_resolver);
560 shill::Client::IPConfig ipconfig;
561 ipconfig.ipv4_dns_addresses = {"8.8.4.4"};
562 proxy.UpdateNameServers(ipconfig);
563
564 EXPECT_CALL(
565 *mock_resolver,
566 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900567 brillo::VariantDictionary props;
568 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900569 proxy.OnDoHProvidersChanged(props);
570}
571
572TEST_F(ProxyTest, NewResolverConfiguredWhenSet) {
573 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
574 ShillClient());
575 proxy.device_ = std::make_unique<shill::Client::Device>();
576 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900577 brillo::VariantDictionary props;
578 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900579 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900580 std::string("1.1.1.1,2606:4700:4700::1111");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900581 proxy.OnDoHProvidersChanged(props);
582 shill::Client::IPConfig ipconfig;
583 ipconfig.ipv4_dns_addresses = {"1.0.0.1", "1.1.1.1"};
584 proxy.UpdateNameServers(ipconfig);
585
586 auto resolver = std::make_unique<MockResolver>();
587 MockResolver* mock_resolver = resolver.get();
588 proxy.resolver_ = std::move(resolver);
589 EXPECT_CALL(*mock_resolver, SetNameServers(UnorderedElementsAre(
590 StrEq("1.1.1.1"), StrEq("1.0.0.1"))));
591 EXPECT_CALL(
592 *mock_resolver,
593 SetDoHProviders(
594 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
595 false));
596 proxy.doh_config_.set_resolver(mock_resolver);
597}
598
599TEST_F(ProxyTest, DoHModeChangingFixedNameServers) {
600 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
601 ShillClient());
602 proxy.device_ = std::make_unique<shill::Client::Device>();
603 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
604 auto resolver = std::make_unique<MockResolver>();
605 MockResolver* mock_resolver = resolver.get();
606 proxy.resolver_ = std::move(resolver);
607 proxy.doh_config_.set_resolver(mock_resolver);
608
609 // Initially off.
610 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
611 shill::Client::IPConfig ipconfig;
612 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "9.9.9.9"};
613 proxy.UpdateNameServers(ipconfig);
614
615 // Automatic mode - matched cloudflare.
616 EXPECT_CALL(
617 *mock_resolver,
618 SetDoHProviders(
619 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
620 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900621 brillo::VariantDictionary props;
622 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900623 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900624 std::string("1.1.1.1,2606:4700:4700::1111");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900625 proxy.OnDoHProvidersChanged(props);
626
627 // Automatic mode - no match.
628 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
629 ipconfig.ipv4_dns_addresses = {"10.10.10.1"};
630 proxy.UpdateNameServers(ipconfig);
631
632 // Automatic mode - matched google.
633 EXPECT_CALL(
634 *mock_resolver,
635 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), false));
636 ipconfig.ipv4_dns_addresses = {"8.8.4.4", "10.10.10.1", "8.8.8.8"};
637 proxy.UpdateNameServers(ipconfig);
638
639 // Explicitly turned off.
640 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
641 props.clear();
642 proxy.OnDoHProvidersChanged(props);
643
644 // Still off - even switching ns back.
645 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
646 ipconfig.ipv4_dns_addresses = {"8.8.4.4", "10.10.10.1", "8.8.8.8"};
647 proxy.UpdateNameServers(ipconfig);
648
649 // Always-on mode.
650 EXPECT_CALL(
651 *mock_resolver,
652 SetDoHProviders(ElementsAre(StrEq("https://doh.opendns.com/dns-query")),
653 true));
654 props.clear();
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900655 props["https://doh.opendns.com/dns-query"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900656 proxy.OnDoHProvidersChanged(props);
657
658 // Back to automatic mode, though no matching ns.
659 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
660 props.clear();
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900661 props["https://doh.opendns.com/dns-query"] = std::string(
662 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900663 proxy.OnDoHProvidersChanged(props);
664
665 // Automatic mode working on ns update.
666 EXPECT_CALL(
667 *mock_resolver,
668 SetDoHProviders(ElementsAre(StrEq("https://doh.opendns.com/dns-query")),
669 false));
670 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "2620:119:35::35"};
671 proxy.UpdateNameServers(ipconfig);
672}
673
674TEST_F(ProxyTest, MultipleDoHProvidersForAlwaysOnMode) {
675 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
676 ShillClient());
677 proxy.device_ = std::make_unique<shill::Client::Device>();
678 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
679 auto resolver = std::make_unique<MockResolver>();
680 MockResolver* mock_resolver = resolver.get();
681 proxy.resolver_ = std::move(resolver);
682 proxy.doh_config_.set_resolver(mock_resolver);
683 EXPECT_CALL(
684 *mock_resolver,
685 SetDoHProviders(UnorderedElementsAre(StrEq("https://dns.google.com"),
686 StrEq("https://doh.opendns.com")),
687 true));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900688 brillo::VariantDictionary props;
689 props["https://dns.google.com"] = std::string("");
690 props["https://doh.opendns.com"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900691 proxy.OnDoHProvidersChanged(props);
692}
693
694TEST_F(ProxyTest, MultipleDoHProvidersForAutomaticMode) {
695 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
696 ShillClient());
697 proxy.device_ = std::make_unique<shill::Client::Device>();
698 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
699 auto resolver = std::make_unique<MockResolver>();
700 MockResolver* mock_resolver = resolver.get();
701 proxy.resolver_ = std::move(resolver);
702 proxy.doh_config_.set_resolver(mock_resolver);
703 shill::Client::IPConfig ipconfig;
704 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "10.10.10.10"};
705 proxy.UpdateNameServers(ipconfig);
706
707 EXPECT_CALL(
708 *mock_resolver,
709 SetDoHProviders(
710 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
711 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900712 brillo::VariantDictionary props;
713 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
714 props["https://dns.quad9.net/dns-query"] = std::string("9.9.9.9,2620:fe::9");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900715 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900716 std::string("1.1.1.1,2606:4700:4700::1111");
717 props["https://doh.opendns.com/dns-query"] = std::string(
718 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900719 proxy.OnDoHProvidersChanged(props);
720
721 EXPECT_CALL(*mock_resolver,
722 SetDoHProviders(UnorderedElementsAre(
723 StrEq("https://dns.google.com"),
724 StrEq("https://doh.opendns.com/dns-query"),
725 StrEq("https://dns.quad9.net/dns-query")),
726 false));
727 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "10.10.10.10"};
728 ipconfig.ipv6_dns_addresses = {"2620:fe::9", "2620:119:53::53"};
729 proxy.UpdateNameServers(ipconfig);
730}
731
732TEST_F(ProxyTest, DoHBadAlwaysOnConfigSetsAutomaticMode) {
733 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
734 ShillClient());
735 proxy.device_ = std::make_unique<shill::Client::Device>();
736 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
737 auto resolver = std::make_unique<MockResolver>();
738 MockResolver* mock_resolver = resolver.get();
739 proxy.resolver_ = std::move(resolver);
740 proxy.doh_config_.set_resolver(mock_resolver);
741 shill::Client::IPConfig ipconfig;
742 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "10.10.10.10"};
743 proxy.UpdateNameServers(ipconfig);
744
745 EXPECT_CALL(
746 *mock_resolver,
747 SetDoHProviders(
748 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
749 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900750 brillo::VariantDictionary props;
751 props["https://dns.opendns.com"] = std::string("");
752 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
753 props["https://dns.quad9.net/dns-query"] = std::string("9.9.9.9,2620:fe::9");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900754 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900755 std::string("1.1.1.1,2606:4700:4700::1111");
756 props["https://doh.opendns.com/dns-query"] = std::string(
757 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900758 proxy.OnDoHProvidersChanged(props);
759
760 EXPECT_CALL(*mock_resolver,
761 SetDoHProviders(UnorderedElementsAre(
762 StrEq("https://dns.google.com"),
763 StrEq("https://doh.opendns.com/dns-query"),
764 StrEq("https://dns.quad9.net/dns-query")),
765 false));
766 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "10.10.10.10"};
767 ipconfig.ipv6_dns_addresses = {"2620:fe::9", "2620:119:53::53"};
768 proxy.UpdateNameServers(ipconfig);
769}
770
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900771} // namespace dns_proxy