blob: 455758d766df4f31e7b7317f1f59ef72a77c3300 [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::_;
34using testing::Return;
Garrick Evans2ca050d2021-02-09 18:21:36 +090035using testing::StrEq;
Garrick Evans5fe2a4f2021-02-03 17:04:48 +090036
37class FakeShillClient : public shill::FakeClient {
38 public:
39 FakeShillClient(scoped_refptr<dbus::Bus> bus,
40 ManagerProxyInterface* manager_proxy)
41 : shill::FakeClient(bus), manager_proxy_(manager_proxy) {}
42
43 std::unique_ptr<shill::Client::ManagerPropertyAccessor> ManagerProperties(
44 const base::TimeDelta& timeout) const override {
45 return std::make_unique<shill::Client::ManagerPropertyAccessor>(
46 manager_proxy_);
47 }
48
49 bool IsInitialized() const { return init_; }
50
51 private:
52 ManagerProxyInterface* manager_proxy_;
53};
54
55class FakePatchpanelClient : public patchpanel::FakeClient {
56 public:
57 FakePatchpanelClient() = default;
58 ~FakePatchpanelClient() = default;
59
60 void SetConnectNamespaceResult(
61 int fd, const patchpanel::ConnectNamespaceResponse& resp) {
62 ns_fd_ = fd;
63 ns_resp_ = resp;
64 }
65
66 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
67 ConnectNamespace(pid_t pid,
68 const std::string& outbound_ifname,
69 bool forward_user_traffic,
70 bool route_on_vpn,
71 patchpanel::TrafficCounter::Source traffic_source) override {
72 ns_ifname_ = outbound_ifname;
73 ns_rvpn_ = route_on_vpn;
74 ns_ts_ = traffic_source;
75 return {base::ScopedFD(ns_fd_), ns_resp_};
76 }
77
78 std::string ns_ifname_;
79 bool ns_rvpn_;
80 patchpanel::TrafficCounter::Source ns_ts_;
81 int ns_fd_;
82 patchpanel::ConnectNamespaceResponse ns_resp_;
83};
84
Garrick Evans2ca050d2021-02-09 18:21:36 +090085class MockResolver : public Resolver {
86 public:
Jason Jeremy Iman845f2932021-01-31 16:12:13 +090087 MockResolver()
88 : Resolver(kRequestTimeout, kRequestRetryDelay, kRequestMaxRetry) {}
Garrick Evans2ca050d2021-02-09 18:21:36 +090089 ~MockResolver() = default;
90
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +090091 MOCK_METHOD(bool, ListenUDP, (struct sockaddr*), (override));
92 MOCK_METHOD(bool, ListenTCP, (struct sockaddr*), (override));
Garrick Evans2ca050d2021-02-09 18:21:36 +090093 MOCK_METHOD(void,
94 SetNameServers,
95 (const std::vector<std::string>&),
96 (override));
97 MOCK_METHOD(void,
98 SetDoHProviders,
99 (const std::vector<std::string>&, bool),
100 (override));
101};
102
103class TestProxy : public Proxy {
104 public:
105 TestProxy(const Options& opts,
106 std::unique_ptr<patchpanel::Client> patchpanel,
107 std::unique_ptr<shill::Client> shill)
108 : Proxy(opts, std::move(patchpanel), std::move(shill)) {}
109
110 std::unique_ptr<Resolver> resolver;
Jason Jeremy Iman845f2932021-01-31 16:12:13 +0900111 std::unique_ptr<Resolver> NewResolver(base::TimeDelta timeout,
112 base::TimeDelta retry_delay,
113 int max_num_retries) override {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900114 return std::move(resolver);
115 }
116};
117
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900118class ProxyTest : public ::testing::Test {
119 protected:
120 ProxyTest() : mock_bus_(new dbus::MockBus{dbus::Bus::Options{}}) {}
121 ~ProxyTest() { mock_bus_->ShutdownAndBlock(); }
122
123 std::unique_ptr<FakePatchpanelClient> PatchpanelClient() const {
124 return std::make_unique<FakePatchpanelClient>();
125 }
126
127 std::unique_ptr<FakeShillClient> ShillClient() const {
128 return std::make_unique<FakeShillClient>(
129 mock_bus_, reinterpret_cast<ManagerProxyInterface*>(
130 const_cast<ManagerProxyMock*>(&mock_manager_)));
131 }
132
133 int make_fd() const {
134 std::string fn(
135 ::testing::UnitTest::GetInstance()->current_test_info()->name());
136 fn = "/tmp/" + fn;
137 return open(fn.c_str(), O_CREAT, 0600);
138 }
139
140 protected:
141 scoped_refptr<dbus::MockBus> mock_bus_;
142 ManagerProxyMock mock_manager_;
143};
144
145TEST_F(ProxyTest, SystemProxy_OnShutdownClearsAddressPropertyOnShill) {
146 EXPECT_CALL(mock_manager_, SetProperty(shill::kDNSProxyIPv4AddressProperty,
147 brillo::Any(std::string()), _, _))
148 .WillOnce(Return(true));
149 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
150 ShillClient());
151 int unused;
152 proxy.OnShutdown(&unused);
153}
154
155TEST_F(ProxyTest, NonSystemProxy_OnShutdownDoesNotCallShill) {
156 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
157 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
158 ShillClient());
159 int unused;
160 proxy.OnShutdown(&unused);
161}
162
163TEST_F(ProxyTest, SystemProxy_SetShillPropertyWithNoRetriesCrashes) {
164 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
165 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
166 ShillClient());
167 EXPECT_DEATH(proxy.SetShillProperty("10.10.10.10", true, 0), "");
168}
169
170TEST_F(ProxyTest, SystemProxy_SetShillPropertyDoesntCrashIfDieFalse) {
171 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
172 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
173 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
174 ShillClient());
175 proxy.SetShillProperty("10.10.10.10", false, 0);
176}
177
178TEST_F(ProxyTest, SetupInitializesShill) {
179 auto shill = ShillClient();
180 auto* shill_ptr = shill.get();
181 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
182 std::move(shill));
183 proxy.Setup();
184 EXPECT_TRUE(shill_ptr->IsInitialized());
185}
186
187TEST_F(ProxyTest, SystemProxy_ConnectedNamedspace) {
188 auto pp = PatchpanelClient();
189 auto* pp_ptr = pp.get();
190 pp->SetConnectNamespaceResult(make_fd(),
191 patchpanel::ConnectNamespaceResponse());
192 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
193 ShillClient());
194 proxy.OnPatchpanelReady(true);
195 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
196 EXPECT_FALSE(pp_ptr->ns_rvpn_);
197 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::SYSTEM);
198}
199
200TEST_F(ProxyTest, DefaultProxy_ConnectedNamedspace) {
201 auto pp = PatchpanelClient();
202 auto* pp_ptr = pp.get();
203 pp->SetConnectNamespaceResult(make_fd(),
204 patchpanel::ConnectNamespaceResponse());
205 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, std::move(pp),
206 ShillClient());
207 proxy.OnPatchpanelReady(true);
208 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
209 EXPECT_TRUE(pp_ptr->ns_rvpn_);
210 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::USER);
211}
212
213TEST_F(ProxyTest, ArcProxy_ConnectedNamedspace) {
214 auto pp = PatchpanelClient();
215 auto* pp_ptr = pp.get();
216 pp->SetConnectNamespaceResult(make_fd(),
217 patchpanel::ConnectNamespaceResponse());
218 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
219 std::move(pp), ShillClient());
220 proxy.OnPatchpanelReady(true);
221 EXPECT_EQ(pp_ptr->ns_ifname_, "eth0");
222 EXPECT_FALSE(pp_ptr->ns_rvpn_);
223 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::ARC);
224}
225
226TEST_F(ProxyTest, CrashOnConnectNamespaceFailure) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900227 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900228 auto pp = PatchpanelClient();
229 pp->SetConnectNamespaceResult(-1 /* invalid fd */,
230 patchpanel::ConnectNamespaceResponse());
231 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
232 std::move(pp), ShillClient());
233 EXPECT_DEATH(proxy.OnPatchpanelReady(true), "namespace");
234}
235
236TEST_F(ProxyTest, CrashOnPatchpanelNotReady) {
Garrick Evans2ca050d2021-02-09 18:21:36 +0900237 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900238 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
239 PatchpanelClient(), ShillClient());
240 EXPECT_DEATH(proxy.OnPatchpanelReady(false), "patchpanel");
241}
242
243TEST_F(ProxyTest, ShillResetRestoresAddressProperty) {
244 auto pp = PatchpanelClient();
245 patchpanel::ConnectNamespaceResponse resp;
246 resp.set_host_ipv4_address(patchpanel::Ipv4Addr(10, 10, 10, 10));
247 pp->SetConnectNamespaceResult(make_fd(), resp);
248 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
249 ShillClient());
250 proxy.OnPatchpanelReady(true);
251 EXPECT_CALL(mock_manager_,
252 SetProperty(shill::kDNSProxyIPv4AddressProperty,
253 brillo::Any(std::string("10.10.10.10")), _, _))
254 .WillOnce(Return(true));
255 proxy.OnShillReset(true);
256}
257
Garrick Evans2ca050d2021-02-09 18:21:36 +0900258TEST_F(ProxyTest, StateClearedIfDefaultServiceDrops) {
259 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
260 ShillClient());
261 proxy.device_ = std::make_unique<shill::Client::Device>();
262 proxy.resolver_ = std::make_unique<MockResolver>();
263 proxy.OnDefaultDeviceChanged(nullptr /* no service */);
264 EXPECT_FALSE(proxy.device_);
265 EXPECT_FALSE(proxy.resolver_);
266}
267
268TEST_F(ProxyTest, ArcProxy_IgnoredIfDefaultServiceDrops) {
269 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC}, 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_TRUE(proxy.device_);
275 EXPECT_TRUE(proxy.resolver_);
276}
277
278TEST_F(ProxyTest, StateClearedIfDefaultServiceIsNotOnline) {
279 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
280 ShillClient());
281 proxy.device_ = std::make_unique<shill::Client::Device>();
282 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
283 proxy.resolver_ = std::make_unique<MockResolver>();
284 shill::Client::Device dev;
285 dev.state = shill::Client::Device::ConnectionState::kReady;
286 proxy.OnDefaultDeviceChanged(&dev);
287 EXPECT_FALSE(proxy.device_);
288 EXPECT_FALSE(proxy.resolver_);
289}
290
291TEST_F(ProxyTest, NewResolverStartsListeningOnDefaultServiceComesOnline) {
292 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kDefault},
293 PatchpanelClient(), ShillClient());
294 proxy.device_ = std::make_unique<shill::Client::Device>();
295 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
296 auto resolver = std::make_unique<MockResolver>();
297 MockResolver* mock_resolver = resolver.get();
298 proxy.resolver = std::move(resolver);
299 shill::Client::Device dev;
300 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900301 EXPECT_CALL(*mock_resolver, ListenUDP(_)).WillOnce(Return(true));
302 EXPECT_CALL(*mock_resolver, ListenTCP(_)).WillOnce(Return(true));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900303 proxy.OnDefaultDeviceChanged(&dev);
304 EXPECT_TRUE(proxy.resolver_);
305}
306
307TEST_F(ProxyTest, CrashOnListenFailure) {
308 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
309 TestProxy proxy(Proxy::Options{.type = Proxy::Type::kSystem},
310 PatchpanelClient(), ShillClient());
311 proxy.device_ = std::make_unique<shill::Client::Device>();
312 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
313 auto resolver = std::make_unique<MockResolver>();
314 MockResolver* mock_resolver = resolver.get();
315 proxy.resolver = std::move(resolver);
316 shill::Client::Device dev;
317 dev.state = shill::Client::Device::ConnectionState::kOnline;
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900318 ON_CALL(*mock_resolver, ListenUDP(_)).WillByDefault(Return(false));
319 ON_CALL(*mock_resolver, ListenTCP(_)).WillByDefault(Return(false));
Garrick Evans2ca050d2021-02-09 18:21:36 +0900320 EXPECT_DEATH(proxy.OnDefaultDeviceChanged(&dev), "relay loop");
321}
322
323TEST_F(ProxyTest, NameServersUpdatedOnDefaultServiceComesOnline) {
324 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
325 ShillClient());
326 proxy.device_ = std::make_unique<shill::Client::Device>();
327 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
328 auto resolver = std::make_unique<MockResolver>();
329 MockResolver* mock_resolver = resolver.get();
330 proxy.resolver_ = std::move(resolver);
331 shill::Client::Device dev;
332 dev.state = shill::Client::Device::ConnectionState::kOnline;
333 dev.ipconfig.ipv4_dns_addresses = {"a", "b"};
334 dev.ipconfig.ipv6_dns_addresses = {"c", "d"};
335 // Doesn't call listen since the resolver already exists.
Jason Jeremy Iman6fd98552021-01-27 04:19:07 +0900336 EXPECT_CALL(*mock_resolver, ListenUDP(_)).Times(0);
337 EXPECT_CALL(*mock_resolver, ListenTCP(_)).Times(0);
Garrick Evans2ca050d2021-02-09 18:21:36 +0900338 EXPECT_CALL(*mock_resolver,
339 SetNameServers(
340 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), StrEq("d"))));
341 proxy.OnDefaultDeviceChanged(&dev);
342}
343
344TEST_F(ProxyTest, SystemProxy_ShillPropertyUpdatedOnDefaultServiceComesOnline) {
345 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
346 ShillClient());
347 proxy.device_ = std::make_unique<shill::Client::Device>();
348 proxy.device_->state = shill::Client::Device::ConnectionState::kOnline;
349 auto resolver = std::make_unique<MockResolver>();
350 MockResolver* mock_resolver = resolver.get();
351 proxy.resolver_ = std::move(resolver);
352 shill::Client::Device dev;
353 dev.state = shill::Client::Device::ConnectionState::kOnline;
354 EXPECT_CALL(*mock_resolver, SetNameServers(_));
355 EXPECT_CALL(mock_manager_,
356 SetProperty(shill::kDNSProxyIPv4AddressProperty, _, _, _))
357 .WillOnce(Return(true));
358 proxy.OnDefaultDeviceChanged(&dev);
359}
360
Garrick Evans5fe2a4f2021-02-03 17:04:48 +0900361} // namespace dns_proxy