blob: 78bbd3cfdaa5c0ba2f16c1a28e418385ebdffafb [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 Evansd41fdbf2021-03-03 09:15:48 +090034using testing::IsEmpty;
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090035using testing::Return;
Garrick Evansadde9852021-02-15 20:16:53 +090036using testing::SetArgPointee;
Garrick Evans2ca050d2021-02-09 18:21:36 +090037using testing::StrEq;
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090038
39class FakeShillClient : public shill::FakeClient {
40 public:
41 FakeShillClient(scoped_refptr<dbus::Bus> bus,
42 ManagerProxyInterface* manager_proxy)
43 : shill::FakeClient(bus), manager_proxy_(manager_proxy) {}
44
45 std::unique_ptr<shill::Client::ManagerPropertyAccessor> ManagerProperties(
46 const base::TimeDelta& timeout) const override {
47 return std::make_unique<shill::Client::ManagerPropertyAccessor>(
48 manager_proxy_);
49 }
50
Garrick Evansadde9852021-02-15 20:16:53 +090051 std::unique_ptr<shill::Client::Device> DefaultDevice(
52 bool exclude_vpn) override {
53 return std::move(default_device_);
54 }
55
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090056 bool IsInitialized() const { return init_; }
57
Garrick Evansadde9852021-02-15 20:16:53 +090058 std::unique_ptr<shill::Client::Device> default_device_;
59
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090060 private:
61 ManagerProxyInterface* manager_proxy_;
62};
63
64class FakePatchpanelClient : public patchpanel::FakeClient {
65 public:
66 FakePatchpanelClient() = default;
67 ~FakePatchpanelClient() = default;
68
69 void SetConnectNamespaceResult(
70 int fd, const patchpanel::ConnectNamespaceResponse& resp) {
71 ns_fd_ = fd;
72 ns_resp_ = resp;
73 }
74
75 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
76 ConnectNamespace(pid_t pid,
77 const std::string& outbound_ifname,
78 bool forward_user_traffic,
79 bool route_on_vpn,
80 patchpanel::TrafficCounter::Source traffic_source) override {
81 ns_ifname_ = outbound_ifname;
82 ns_rvpn_ = route_on_vpn;
83 ns_ts_ = traffic_source;
84 return {base::ScopedFD(ns_fd_), ns_resp_};
85 }
86
87 std::string ns_ifname_;
88 bool ns_rvpn_;
89 patchpanel::TrafficCounter::Source ns_ts_;
90 int ns_fd_;
91 patchpanel::ConnectNamespaceResponse ns_resp_;
92};
93
Garrick Evans2ca050d2021-02-09 18:21:36 +090094class MockResolver : public Resolver {
95 public:
Jason Jeremy Iman845f2932021-01-31 16:12:13 +090096 MockResolver()
97 : Resolver(kRequestTimeout, kRequestRetryDelay, kRequestMaxRetry) {}
Garrick Evans2ca050d2021-02-09 18:21:36 +090098 ~MockResolver() = default;
99
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900100 MOCK_METHOD(bool, ListenUDP, (struct sockaddr*), (override));
101 MOCK_METHOD(bool, ListenTCP, (struct sockaddr*), (override));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900102 MOCK_METHOD(void,
103 SetNameServers,
104 (const std::vector<std::string>&),
105 (override));
106 MOCK_METHOD(void,
107 SetDoHProviders,
108 (const std::vector<std::string>&, bool),
109 (override));
110};
111
112class TestProxy : public Proxy {
113 public:
114 TestProxy(const Options& opts,
115 std::unique_ptr<patchpanel::Client> patchpanel,
116 std::unique_ptr<shill::Client> shill)
117 : Proxy(opts, std::move(patchpanel), std::move(shill)) {}
118
119 std::unique_ptr<Resolver> resolver;
Jason Jeremy Iman845f2932021-01-31 16:12:13 +0900120 std::unique_ptr<Resolver> NewResolver(base::TimeDelta timeout,
121 base::TimeDelta retry_delay,
122 int max_num_retries) override {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900123 return std::move(resolver);
124 }
125};
126
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900127class ProxyTest : public ::testing::Test {
128 protected:
129 ProxyTest() : mock_bus_(new dbus::MockBus{dbus::Bus::Options{}}) {}
130 ~ProxyTest() { mock_bus_->ShutdownAndBlock(); }
131
132 std::unique_ptr<FakePatchpanelClient> PatchpanelClient() const {
133 return std::make_unique<FakePatchpanelClient>();
134 }
135
136 std::unique_ptr<FakeShillClient> ShillClient() const {
137 return std::make_unique<FakeShillClient>(
138 mock_bus_, reinterpret_cast<ManagerProxyInterface*>(
139 const_cast<ManagerProxyMock*>(&mock_manager_)));
140 }
141
142 int make_fd() const {
143 std::string fn(
144 ::testing::UnitTest::GetInstance()->current_test_info()->name());
145 fn = "/tmp/" + fn;
146 return open(fn.c_str(), O_CREAT, 0600);
147 }
148
149 protected:
150 scoped_refptr<dbus::MockBus> mock_bus_;
151 ManagerProxyMock mock_manager_;
152};
153
154TEST_F(ProxyTest, SystemProxy_OnShutdownClearsAddressPropertyOnShill) {
155 EXPECT_CALL(mock_manager_, SetProperty(shill::kDNSProxyIPv4AddressProperty,
156 brillo::Any(std::string()), _, _))
157 .WillOnce(Return(true));
158 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
159 ShillClient());
160 int unused;
161 proxy.OnShutdown(&unused);
162}
163
164TEST_F(ProxyTest, NonSystemProxy_OnShutdownDoesNotCallShill) {
165 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
166 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
167 ShillClient());
168 int unused;
169 proxy.OnShutdown(&unused);
170}
171
172TEST_F(ProxyTest, SystemProxy_SetShillPropertyWithNoRetriesCrashes) {
173 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
174 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
175 ShillClient());
176 EXPECT_DEATH(proxy.SetShillProperty("10.10.10.10", true, 0), "");
177}
178
179TEST_F(ProxyTest, SystemProxy_SetShillPropertyDoesntCrashIfDieFalse) {
180 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
181 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
182 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
183 ShillClient());
184 proxy.SetShillProperty("10.10.10.10", false, 0);
185}
186
Garrick Evansab03c462021-02-15 20:54:20 +0900187TEST_F(ProxyTest, ShillInitializedWhenReady) {
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900188 auto shill = ShillClient();
189 auto* shill_ptr = shill.get();
190 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
191 std::move(shill));
Garrick Evansab03c462021-02-15 20:54:20 +0900192 proxy.OnShillReady(true);
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900193 EXPECT_TRUE(shill_ptr->IsInitialized());
194}
195
196TEST_F(ProxyTest, SystemProxy_ConnectedNamedspace) {
197 auto pp = PatchpanelClient();
198 auto* pp_ptr = pp.get();
199 pp->SetConnectNamespaceResult(make_fd(),
200 patchpanel::ConnectNamespaceResponse());
201 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
202 ShillClient());
203 proxy.OnPatchpanelReady(true);
204 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
205 EXPECT_FALSE(pp_ptr->ns_rvpn_);
206 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::SYSTEM);
207}
208
209TEST_F(ProxyTest, DefaultProxy_ConnectedNamedspace) {
210 auto pp = PatchpanelClient();
211 auto* pp_ptr = pp.get();
212 pp->SetConnectNamespaceResult(make_fd(),
213 patchpanel::ConnectNamespaceResponse());
214 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, std::move(pp),
215 ShillClient());
216 proxy.OnPatchpanelReady(true);
217 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
218 EXPECT_TRUE(pp_ptr->ns_rvpn_);
219 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::USER);
220}
221
222TEST_F(ProxyTest, ArcProxy_ConnectedNamedspace) {
223 auto pp = PatchpanelClient();
224 auto* pp_ptr = pp.get();
225 pp->SetConnectNamespaceResult(make_fd(),
226 patchpanel::ConnectNamespaceResponse());
227 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
228 std::move(pp), ShillClient());
229 proxy.OnPatchpanelReady(true);
230 EXPECT_EQ(pp_ptr->ns_ifname_, "eth0");
231 EXPECT_FALSE(pp_ptr->ns_rvpn_);
232 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::ARC);
233}
234
235TEST_F(ProxyTest, CrashOnConnectNamespaceFailure) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900236 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900237 auto pp = PatchpanelClient();
238 pp->SetConnectNamespaceResult(-1 /* invalid fd */,
239 patchpanel::ConnectNamespaceResponse());
240 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
241 std::move(pp), ShillClient());
242 EXPECT_DEATH(proxy.OnPatchpanelReady(true), "namespace");
243}
244
245TEST_F(ProxyTest, CrashOnPatchpanelNotReady) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900246 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900247 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
248 PatchpanelClient(), ShillClient());
249 EXPECT_DEATH(proxy.OnPatchpanelReady(false), "patchpanel");
250}
251
252TEST_F(ProxyTest, ShillResetRestoresAddressProperty) {
253 auto pp = PatchpanelClient();
254 patchpanel::ConnectNamespaceResponse resp;
Garrick Evansab03c462021-02-15 20:54:20 +0900255 resp.set_peer_ipv4_address(patchpanel::Ipv4Addr(10, 10, 10, 10));
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900256 pp->SetConnectNamespaceResult(make_fd(), resp);
257 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
258 ShillClient());
259 proxy.OnPatchpanelReady(true);
260 EXPECT_CALL(mock_manager_,
261 SetProperty(shill::kDNSProxyIPv4AddressProperty,
262 brillo::Any(std::string("10.10.10.10")), _, _))
263 .WillOnce(Return(true));
264 proxy.OnShillReset(true);
265}
266
Garrick Evans2ca050d2021-02-09 18:21:36 +0900267TEST_F(ProxyTest, StateClearedIfDefaultServiceDrops) {
268 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
269 ShillClient());
270 proxy.device_ = std::make_unique<shill::Client::Device>();
271 proxy.resolver_ = std::make_unique<MockResolver>();
272 proxy.OnDefaultDeviceChanged(nullptr /* no service */);
273 EXPECT_FALSE(proxy.device_);
274 EXPECT_FALSE(proxy.resolver_);
275}
276
277TEST_F(ProxyTest, ArcProxy_IgnoredIfDefaultServiceDrops) {
278 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC}, PatchpanelClient(),
279 ShillClient());
280 proxy.device_ = std::make_unique<shill::Client::Device>();
281 proxy.resolver_ = std::make_unique<MockResolver>();
282 proxy.OnDefaultDeviceChanged(nullptr /* no service */);
283 EXPECT_TRUE(proxy.device_);
284 EXPECT_TRUE(proxy.resolver_);
285}
286
287TEST_F(ProxyTest, StateClearedIfDefaultServiceIsNotOnline) {
288 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
289 ShillClient());
290 proxy.device_ = std::make_unique<shill::Client::Device>();
291 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
292 proxy.resolver_ = std::make_unique<MockResolver>();
293 shill::Client::Device dev;
294 dev.state = shill::Client::Device::ConnectionState::kReady;
295 proxy.OnDefaultDeviceChanged(&dev);
296 EXPECT_FALSE(proxy.device_);
297 EXPECT_FALSE(proxy.resolver_);
298}
299
300TEST_F(ProxyTest, NewResolverStartsListeningOnDefaultServiceComesOnline) {
301 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kDefault},
302 PatchpanelClient(), ShillClient());
303 proxy.device_ = std::make_unique<shill::Client::Device>();
304 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
305 auto resolver = std::make_unique<MockResolver>();
306 MockResolver* mock_resolver = resolver.get();
307 proxy.resolver = std::move(resolver);
308 shill::Client::Device dev;
309 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900310 EXPECT_CALL(*mock_resolver, ListenUDP(_)).WillOnce(Return(true));
311 EXPECT_CALL(*mock_resolver, ListenTCP(_)).WillOnce(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900312 brillo::VariantDictionary props;
313 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
314 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900315 proxy.OnDefaultDeviceChanged(&dev);
316 EXPECT_TRUE(proxy.resolver_);
317}
318
319TEST_F(ProxyTest, CrashOnListenFailure) {
320 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
321 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
322 PatchpanelClient(), ShillClient());
323 proxy.device_ = std::make_unique<shill::Client::Device>();
324 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
325 auto resolver = std::make_unique<MockResolver>();
326 MockResolver* mock_resolver = resolver.get();
327 proxy.resolver = std::move(resolver);
328 shill::Client::Device dev;
329 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900330 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(false));
331 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(false));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900332 EXPECT_DEATH(proxy.OnDefaultDeviceChanged(&dev), "relay loop");
333}
334
335TEST_F(ProxyTest, NameServersUpdatedOnDefaultServiceComesOnline) {
336 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
337 ShillClient());
338 proxy.device_ = std::make_unique<shill::Client::Device>();
339 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
340 auto resolver = std::make_unique<MockResolver>();
341 MockResolver* mock_resolver = resolver.get();
342 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900343 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900344 shill::Client::Device dev;
345 dev.state = shill::Client::Device::ConnectionState::kOnline;
346 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
347 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
348 // Doesn't call listen since the resolver already exists.
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900349 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
350 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900351 EXPECT_CALL(*mock_resolver,
352 SetNameServers(
353 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
354 proxy.OnDefaultDeviceChanged(&dev);
355}
356
357TEST_F(ProxyTest, SystemProxy_ShillPropertyUpdatedOnDefaultServiceComesOnline) {
358 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
359 ShillClient());
360 proxy.device_ = std::make_unique<shill::Client::Device>();
361 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
362 auto resolver = std::make_unique<MockResolver>();
363 MockResolver* mock_resolver = resolver.get();
364 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900365 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900366 shill::Client::Device dev;
367 dev.state = shill::Client::Device::ConnectionState::kOnline;
368 EXPECT_CALL(*mock_resolver, SetNameServers(_));
369 EXPECT_CALL(mock_manager_,
370 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
371 .WillOnce(Return(true));
372 proxy.OnDefaultDeviceChanged(&dev);
373}
374
Garrick Evansadde9852021-02-15 20:16:53 +0900375TEST_F(ProxyTest, SystemProxy_IgnoresVPN) {
376 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
377 PatchpanelClient(), ShillClient());
378 auto resolver = std::make_unique<MockResolver>();
379 MockResolver* mock_resolver = resolver.get();
380 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
381 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900382 brillo::VariantDictionary props;
383 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
384 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900385 EXPECT_CALL(mock_manager_,
386 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
387 .WillOnce(Return(true));
388 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900389 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900390 shill::Client::Device dev;
391 dev.type = shill::Client::Device::Type::kWifi;
392 dev.state = shill::Client::Device::ConnectionState::kOnline;
393 proxy.OnDefaultDeviceChanged(&dev);
394 EXPECT_TRUE(proxy.device_);
395 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
396 dev.type = shill::Client::Device::Type::kVPN;
397 proxy.OnDefaultDeviceChanged(&dev);
398 EXPECT_TRUE(proxy.device_);
399 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
400}
401
402TEST_F(ProxyTest, SystemProxy_GetsPhysicalDeviceOnInitialVPN) {
403 auto shill = ShillClient();
404 auto* shill_ptr = shill.get();
405 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
406 PatchpanelClient(), std::move(shill));
407 auto resolver = std::make_unique<MockResolver>();
408 MockResolver* mock_resolver = resolver.get();
409 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
410 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900411 brillo::VariantDictionary props;
412 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
413 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900414 EXPECT_CALL(mock_manager_,
415 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
416 .WillOnce(Return(true));
417 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900418 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900419 shill::Client::Device vpn;
420 vpn.type = shill::Client::Device::Type::kVPN;
421 vpn.state = shill::Client::Device::ConnectionState::kOnline;
422 shill_ptr->default_device_ = std::make_unique<shill::Client::Device>();
423 shill_ptr->default_device_->type = shill::Client::Device::Type::kWifi;
424 shill_ptr->default_device_->state =
425 shill::Client::Device::ConnectionState::kOnline;
426 proxy.OnDefaultDeviceChanged(&vpn);
427 EXPECT_TRUE(proxy.device_);
428 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
429}
430
431TEST_F(ProxyTest, DefaultProxy_UsesVPN) {
432 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kDefault},
433 PatchpanelClient(), ShillClient());
434 auto resolver = std::make_unique<MockResolver>();
435 MockResolver* mock_resolver = resolver.get();
436 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(true));
437 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(true));
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900438 brillo::VariantDictionary props;
439 EXPECT_CALL(mock_manager_, GetProperties(_, _, _))
440 .WillOnce(DoAll(SetArgPointee<0>(props), Return(true)));
Garrick Evansadde9852021-02-15 20:16:53 +0900441 proxy.resolver = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900442 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansadde9852021-02-15 20:16:53 +0900443 shill::Client::Device dev;
444 dev.type = shill::Client::Device::Type::kWifi;
445 dev.state = shill::Client::Device::ConnectionState::kOnline;
446 proxy.OnDefaultDeviceChanged(&dev);
447 EXPECT_TRUE(proxy.device_);
448 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kWifi);
449 dev.type = shill::Client::Device::Type::kVPN;
450 proxy.OnDefaultDeviceChanged(&dev);
451 EXPECT_TRUE(proxy.device_);
452 EXPECT_EQ(proxy.device_->type, shill::Client::Device::Type::kVPN);
453}
454
Garrick Evansa8c12be2021-02-17 16:06:45 +0900455TEST_F(ProxyTest, NameServersUpdatedOnDeviceChangeEvent) {
456 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
457 ShillClient());
458 proxy.device_ = std::make_unique<shill::Client::Device>();
459 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
460 auto resolver = std::make_unique<MockResolver>();
461 MockResolver* mock_resolver = resolver.get();
462 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900463 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansa8c12be2021-02-17 16:06:45 +0900464 shill::Client::Device dev;
465 dev.state = shill::Client::Device::ConnectionState::kOnline;
466 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
467 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
468 // Doesn't call listen since the resolver already exists.
469 EXPECT_CALL(mock_manager_,
470 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
471 .WillOnce(Return(true));
472 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
473 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
474 EXPECT_CALL(*mock_resolver,
475 SetNameServers(
476 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
477 proxy.OnDefaultDeviceChanged(&dev);
478
479 // Now trigger an ipconfig change.
480 dev.ipconfig.ipv4_dns_addresses = {"X"};
481 EXPECT_CALL(*mock_resolver,
482 SetNameServers(ElementsAre(StrEq("X"), StrEq("c"), StrEq("d"))));
483 proxy.OnDeviceChanged(&dev);
484}
485
486TEST_F(ProxyTest, DeviceChangeEventIgnored) {
487 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
488 ShillClient());
489 proxy.device_ = std::make_unique<shill::Client::Device>();
490 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
491 auto resolver = std::make_unique<MockResolver>();
492 MockResolver* mock_resolver = resolver.get();
493 proxy.resolver_ = std::move(resolver);
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900494 proxy.doh_config_.set_resolver(mock_resolver);
Garrick Evansa8c12be2021-02-17 16:06:45 +0900495 shill::Client::Device dev;
496 dev.ifname = "eth0";
497 dev.state = shill::Client::Device::ConnectionState::kOnline;
498 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
499 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
500 // Doesn't call listen since the resolver already exists.
501 EXPECT_CALL(mock_manager_,
502 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
503 .WillOnce(Return(true));
504 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
505 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
506 EXPECT_CALL(*mock_resolver,
507 SetNameServers(
508 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
509 proxy.OnDefaultDeviceChanged(&dev);
510
511 // No change to ipconfig, no call to SetNameServers
512 proxy.OnDeviceChanged(&dev);
513
514 // Different ifname, no call to SetNameServers
515 dev.ifname = "wlan0";
516 proxy.OnDeviceChanged(&dev);
517}
518
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900519TEST_F(ProxyTest, BasicDoHDisable) {
520 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
521 ShillClient());
522 proxy.device_ = std::make_unique<shill::Client::Device>();
523 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
524 auto resolver = std::make_unique<MockResolver>();
525 MockResolver* mock_resolver = resolver.get();
526 proxy.resolver_ = std::move(resolver);
527 proxy.doh_config_.set_resolver(mock_resolver);
528 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900529 brillo::VariantDictionary props;
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900530 proxy.OnDoHProvidersChanged(props);
531}
532
533TEST_F(ProxyTest, BasicDoHAlwaysOn) {
534 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
535 ShillClient());
536 proxy.device_ = std::make_unique<shill::Client::Device>();
537 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
538 auto resolver = std::make_unique<MockResolver>();
539 MockResolver* mock_resolver = resolver.get();
540 proxy.resolver_ = std::move(resolver);
541 proxy.doh_config_.set_resolver(mock_resolver);
542 EXPECT_CALL(
543 *mock_resolver,
544 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), true));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900545 brillo::VariantDictionary props;
546 props["https://dns.google.com"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900547 proxy.OnDoHProvidersChanged(props);
548}
549
550TEST_F(ProxyTest, BasicDoHAutomatic) {
551 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
552 ShillClient());
553 proxy.device_ = std::make_unique<shill::Client::Device>();
554 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
555 auto resolver = std::make_unique<MockResolver>();
556 MockResolver* mock_resolver = resolver.get();
557 proxy.resolver_ = std::move(resolver);
558 proxy.doh_config_.set_resolver(mock_resolver);
559 shill::Client::IPConfig ipconfig;
560 ipconfig.ipv4_dns_addresses = {"8.8.4.4"};
561 proxy.UpdateNameServers(ipconfig);
562
563 EXPECT_CALL(
564 *mock_resolver,
565 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900566 brillo::VariantDictionary props;
567 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900568 proxy.OnDoHProvidersChanged(props);
569}
570
571TEST_F(ProxyTest, NewResolverConfiguredWhenSet) {
572 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
573 ShillClient());
574 proxy.device_ = std::make_unique<shill::Client::Device>();
575 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900576 brillo::VariantDictionary props;
577 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900578 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900579 std::string("1.1.1.1,2606:4700:4700::1111");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900580 proxy.OnDoHProvidersChanged(props);
581 shill::Client::IPConfig ipconfig;
582 ipconfig.ipv4_dns_addresses = {"1.0.0.1", "1.1.1.1"};
583 proxy.UpdateNameServers(ipconfig);
584
585 auto resolver = std::make_unique<MockResolver>();
586 MockResolver* mock_resolver = resolver.get();
587 proxy.resolver_ = std::move(resolver);
588 EXPECT_CALL(*mock_resolver, SetNameServers(UnorderedElementsAre(
589 StrEq("1.1.1.1"), StrEq("1.0.0.1"))));
590 EXPECT_CALL(
591 *mock_resolver,
592 SetDoHProviders(
593 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
594 false));
595 proxy.doh_config_.set_resolver(mock_resolver);
596}
597
598TEST_F(ProxyTest, DoHModeChangingFixedNameServers) {
599 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
600 ShillClient());
601 proxy.device_ = std::make_unique<shill::Client::Device>();
602 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
603 auto resolver = std::make_unique<MockResolver>();
604 MockResolver* mock_resolver = resolver.get();
605 proxy.resolver_ = std::move(resolver);
606 proxy.doh_config_.set_resolver(mock_resolver);
607
608 // Initially off.
609 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
610 shill::Client::IPConfig ipconfig;
611 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "9.9.9.9"};
612 proxy.UpdateNameServers(ipconfig);
613
614 // Automatic mode - matched cloudflare.
615 EXPECT_CALL(
616 *mock_resolver,
617 SetDoHProviders(
618 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
619 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900620 brillo::VariantDictionary props;
621 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900622 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900623 std::string("1.1.1.1,2606:4700:4700::1111");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900624 proxy.OnDoHProvidersChanged(props);
625
626 // Automatic mode - no match.
627 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
628 ipconfig.ipv4_dns_addresses = {"10.10.10.1"};
629 proxy.UpdateNameServers(ipconfig);
630
631 // Automatic mode - matched google.
632 EXPECT_CALL(
633 *mock_resolver,
634 SetDoHProviders(ElementsAre(StrEq("https://dns.google.com")), false));
635 ipconfig.ipv4_dns_addresses = {"8.8.4.4", "10.10.10.1", "8.8.8.8"};
636 proxy.UpdateNameServers(ipconfig);
637
638 // Explicitly turned off.
639 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
640 props.clear();
641 proxy.OnDoHProvidersChanged(props);
642
643 // Still off - even switching ns back.
644 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
645 ipconfig.ipv4_dns_addresses = {"8.8.4.4", "10.10.10.1", "8.8.8.8"};
646 proxy.UpdateNameServers(ipconfig);
647
648 // Always-on mode.
649 EXPECT_CALL(
650 *mock_resolver,
651 SetDoHProviders(ElementsAre(StrEq("https://doh.opendns.com/dns-query")),
652 true));
653 props.clear();
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900654 props["https://doh.opendns.com/dns-query"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900655 proxy.OnDoHProvidersChanged(props);
656
657 // Back to automatic mode, though no matching ns.
658 EXPECT_CALL(*mock_resolver, SetDoHProviders(IsEmpty(), false));
659 props.clear();
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900660 props["https://doh.opendns.com/dns-query"] = std::string(
661 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900662 proxy.OnDoHProvidersChanged(props);
663
664 // Automatic mode working on ns update.
665 EXPECT_CALL(
666 *mock_resolver,
667 SetDoHProviders(ElementsAre(StrEq("https://doh.opendns.com/dns-query")),
668 false));
669 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "2620:119:35::35"};
670 proxy.UpdateNameServers(ipconfig);
671}
672
673TEST_F(ProxyTest, MultipleDoHProvidersForAlwaysOnMode) {
674 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
675 ShillClient());
676 proxy.device_ = std::make_unique<shill::Client::Device>();
677 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
678 auto resolver = std::make_unique<MockResolver>();
679 MockResolver* mock_resolver = resolver.get();
680 proxy.resolver_ = std::move(resolver);
681 proxy.doh_config_.set_resolver(mock_resolver);
682 EXPECT_CALL(
683 *mock_resolver,
684 SetDoHProviders(UnorderedElementsAre(StrEq("https://dns.google.com"),
685 StrEq("https://doh.opendns.com")),
686 true));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900687 brillo::VariantDictionary props;
688 props["https://dns.google.com"] = std::string("");
689 props["https://doh.opendns.com"] = std::string("");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900690 proxy.OnDoHProvidersChanged(props);
691}
692
693TEST_F(ProxyTest, MultipleDoHProvidersForAutomaticMode) {
694 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
695 ShillClient());
696 proxy.device_ = std::make_unique<shill::Client::Device>();
697 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
698 auto resolver = std::make_unique<MockResolver>();
699 MockResolver* mock_resolver = resolver.get();
700 proxy.resolver_ = std::move(resolver);
701 proxy.doh_config_.set_resolver(mock_resolver);
702 shill::Client::IPConfig ipconfig;
703 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "10.10.10.10"};
704 proxy.UpdateNameServers(ipconfig);
705
706 EXPECT_CALL(
707 *mock_resolver,
708 SetDoHProviders(
709 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
710 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900711 brillo::VariantDictionary props;
712 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
713 props["https://dns.quad9.net/dns-query"] = std::string("9.9.9.9,2620:fe::9");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900714 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900715 std::string("1.1.1.1,2606:4700:4700::1111");
716 props["https://doh.opendns.com/dns-query"] = std::string(
717 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900718 proxy.OnDoHProvidersChanged(props);
719
720 EXPECT_CALL(*mock_resolver,
721 SetDoHProviders(UnorderedElementsAre(
722 StrEq("https://dns.google.com"),
723 StrEq("https://doh.opendns.com/dns-query"),
724 StrEq("https://dns.quad9.net/dns-query")),
725 false));
726 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "10.10.10.10"};
727 ipconfig.ipv6_dns_addresses = {"2620:fe::9", "2620:119:53::53"};
728 proxy.UpdateNameServers(ipconfig);
729}
730
731TEST_F(ProxyTest, DoHBadAlwaysOnConfigSetsAutomaticMode) {
732 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
733 ShillClient());
734 proxy.device_ = std::make_unique<shill::Client::Device>();
735 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
736 auto resolver = std::make_unique<MockResolver>();
737 MockResolver* mock_resolver = resolver.get();
738 proxy.resolver_ = std::move(resolver);
739 proxy.doh_config_.set_resolver(mock_resolver);
740 shill::Client::IPConfig ipconfig;
741 ipconfig.ipv4_dns_addresses = {"1.1.1.1", "10.10.10.10"};
742 proxy.UpdateNameServers(ipconfig);
743
744 EXPECT_CALL(
745 *mock_resolver,
746 SetDoHProviders(
747 ElementsAre(StrEq("https://chrome.cloudflare-dns.com/dns-query")),
748 false));
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900749 brillo::VariantDictionary props;
750 props["https://dns.opendns.com"] = std::string("");
751 props["https://dns.google.com"] = std::string("8.8.8.8, 8.8.4.4");
752 props["https://dns.quad9.net/dns-query"] = std::string("9.9.9.9,2620:fe::9");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900753 props["https://chrome.cloudflare-dns.com/dns-query"] =
Garrick Evans9e5cd1e2021-03-11 22:07:44 +0900754 std::string("1.1.1.1,2606:4700:4700::1111");
755 props["https://doh.opendns.com/dns-query"] = std::string(
756 "208.67.222.222,208.67.220.220,2620:119:35::35, 2620:119:53::53");
Garrick Evansd41fdbf2021-03-03 09:15:48 +0900757 proxy.OnDoHProvidersChanged(props);
758
759 EXPECT_CALL(*mock_resolver,
760 SetDoHProviders(UnorderedElementsAre(
761 StrEq("https://dns.google.com"),
762 StrEq("https://doh.opendns.com/dns-query"),
763 StrEq("https://dns.quad9.net/dns-query")),
764 false));
765 ipconfig.ipv4_dns_addresses = {"8.8.8.8", "10.10.10.10"};
766 ipconfig.ipv6_dns_addresses = {"2620:fe::9", "2620:119:53::53"};
767 proxy.UpdateNameServers(ipconfig);
768}
769
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900770} // namespace dns_proxy