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