blob: b3db4b5c8ef6d0ff169d521f7e26b56c732e84bc [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>
12
13#include <chromeos/patchpanel/net_util.h>
14#include <chromeos/patchpanel/dbus/fake_client.h>
15#include <dbus/mock_bus.h>
16#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18#include <shill/dbus/client/fake_client.h>
19#include <shill/dbus-constants.h>
20#include <shill/dbus-proxy-mocks.h>
21
22namespace dns_proxy {
23
24using org::chromium::flimflam::ManagerProxyInterface;
25using org::chromium::flimflam::ManagerProxyMock;
26using testing::_;
27using testing::Return;
28
29class FakeShillClient : public shill::FakeClient {
30 public:
31 FakeShillClient(scoped_refptr<dbus::Bus> bus,
32 ManagerProxyInterface* manager_proxy)
33 : shill::FakeClient(bus), manager_proxy_(manager_proxy) {}
34
35 std::unique_ptr<shill::Client::ManagerPropertyAccessor> ManagerProperties(
36 const base::TimeDelta& timeout) const override {
37 return std::make_unique<shill::Client::ManagerPropertyAccessor>(
38 manager_proxy_);
39 }
40
41 bool IsInitialized() const { return init_; }
42
43 private:
44 ManagerProxyInterface* manager_proxy_;
45};
46
47class FakePatchpanelClient : public patchpanel::FakeClient {
48 public:
49 FakePatchpanelClient() = default;
50 ~FakePatchpanelClient() = default;
51
52 void SetConnectNamespaceResult(
53 int fd, const patchpanel::ConnectNamespaceResponse& resp) {
54 ns_fd_ = fd;
55 ns_resp_ = resp;
56 }
57
58 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
59 ConnectNamespace(pid_t pid,
60 const std::string& outbound_ifname,
61 bool forward_user_traffic,
62 bool route_on_vpn,
63 patchpanel::TrafficCounter::Source traffic_source) override {
64 ns_ifname_ = outbound_ifname;
65 ns_rvpn_ = route_on_vpn;
66 ns_ts_ = traffic_source;
67 return {base::ScopedFD(ns_fd_), ns_resp_};
68 }
69
70 std::string ns_ifname_;
71 bool ns_rvpn_;
72 patchpanel::TrafficCounter::Source ns_ts_;
73 int ns_fd_;
74 patchpanel::ConnectNamespaceResponse ns_resp_;
75};
76
77class ProxyTest : public ::testing::Test {
78 protected:
79 ProxyTest() : mock_bus_(new dbus::MockBus{dbus::Bus::Options{}}) {}
80 ~ProxyTest() { mock_bus_->ShutdownAndBlock(); }
81
82 std::unique_ptr<FakePatchpanelClient> PatchpanelClient() const {
83 return std::make_unique<FakePatchpanelClient>();
84 }
85
86 std::unique_ptr<FakeShillClient> ShillClient() const {
87 return std::make_unique<FakeShillClient>(
88 mock_bus_, reinterpret_cast<ManagerProxyInterface*>(
89 const_cast<ManagerProxyMock*>(&mock_manager_)));
90 }
91
92 int make_fd() const {
93 std::string fn(
94 ::testing::UnitTest::GetInstance()->current_test_info()->name());
95 fn = "/tmp/" + fn;
96 return open(fn.c_str(), O_CREAT, 0600);
97 }
98
99 protected:
100 scoped_refptr<dbus::MockBus> mock_bus_;
101 ManagerProxyMock mock_manager_;
102};
103
104TEST_F(ProxyTest, SystemProxy_OnShutdownClearsAddressPropertyOnShill) {
105 EXPECT_CALL(mock_manager_, SetProperty(shill::kDNSProxyIPv4AddressProperty,
106 brillo::Any(std::string()), _, _))
107 .WillOnce(Return(true));
108 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
109 ShillClient());
110 int unused;
111 proxy.OnShutdown(&unused);
112}
113
114TEST_F(ProxyTest, NonSystemProxy_OnShutdownDoesNotCallShill) {
115 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
116 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, PatchpanelClient(),
117 ShillClient());
118 int unused;
119 proxy.OnShutdown(&unused);
120}
121
122TEST_F(ProxyTest, SystemProxy_SetShillPropertyWithNoRetriesCrashes) {
123 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
124 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
125 ShillClient());
126 EXPECT_DEATH(proxy.SetShillProperty("10.10.10.10", true, 0), "");
127}
128
129TEST_F(ProxyTest, SystemProxy_SetShillPropertyDoesntCrashIfDieFalse) {
130 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
131 EXPECT_CALL(mock_manager_, SetProperty(_, _, _, _)).Times(0);
132 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
133 ShillClient());
134 proxy.SetShillProperty("10.10.10.10", false, 0);
135}
136
137TEST_F(ProxyTest, SetupInitializesShill) {
138 auto shill = ShillClient();
139 auto* shill_ptr = shill.get();
140 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, PatchpanelClient(),
141 std::move(shill));
142 proxy.Setup();
143 EXPECT_TRUE(shill_ptr->IsInitialized());
144}
145
146TEST_F(ProxyTest, SystemProxy_ConnectedNamedspace) {
147 auto pp = PatchpanelClient();
148 auto* pp_ptr = pp.get();
149 pp->SetConnectNamespaceResult(make_fd(),
150 patchpanel::ConnectNamespaceResponse());
151 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
152 ShillClient());
153 proxy.OnPatchpanelReady(true);
154 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
155 EXPECT_FALSE(pp_ptr->ns_rvpn_);
156 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::SYSTEM);
157}
158
159TEST_F(ProxyTest, DefaultProxy_ConnectedNamedspace) {
160 auto pp = PatchpanelClient();
161 auto* pp_ptr = pp.get();
162 pp->SetConnectNamespaceResult(make_fd(),
163 patchpanel::ConnectNamespaceResponse());
164 Proxy proxy(Proxy::Options{.type = Proxy::Type::kDefault}, std::move(pp),
165 ShillClient());
166 proxy.OnPatchpanelReady(true);
167 EXPECT_TRUE(pp_ptr->ns_ifname_.empty());
168 EXPECT_TRUE(pp_ptr->ns_rvpn_);
169 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::USER);
170}
171
172TEST_F(ProxyTest, ArcProxy_ConnectedNamedspace) {
173 auto pp = PatchpanelClient();
174 auto* pp_ptr = pp.get();
175 pp->SetConnectNamespaceResult(make_fd(),
176 patchpanel::ConnectNamespaceResponse());
177 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
178 std::move(pp), ShillClient());
179 proxy.OnPatchpanelReady(true);
180 EXPECT_EQ(pp_ptr->ns_ifname_, "eth0");
181 EXPECT_FALSE(pp_ptr->ns_rvpn_);
182 EXPECT_EQ(pp_ptr->ns_ts_, patchpanel::TrafficCounter::ARC);
183}
184
185TEST_F(ProxyTest, CrashOnConnectNamespaceFailure) {
186 auto pp = PatchpanelClient();
187 pp->SetConnectNamespaceResult(-1 /* invalid fd */,
188 patchpanel::ConnectNamespaceResponse());
189 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
190 std::move(pp), ShillClient());
191 EXPECT_DEATH(proxy.OnPatchpanelReady(true), "namespace");
192}
193
194TEST_F(ProxyTest, CrashOnPatchpanelNotReady) {
195 Proxy proxy(Proxy::Options{.type = Proxy::Type::kARC, .ifname = "eth0"},
196 PatchpanelClient(), ShillClient());
197 EXPECT_DEATH(proxy.OnPatchpanelReady(false), "patchpanel");
198}
199
200TEST_F(ProxyTest, ShillResetRestoresAddressProperty) {
201 auto pp = PatchpanelClient();
202 patchpanel::ConnectNamespaceResponse resp;
203 resp.set_host_ipv4_address(patchpanel::Ipv4Addr(10, 10, 10, 10));
204 pp->SetConnectNamespaceResult(make_fd(), resp);
205 Proxy proxy(Proxy::Options{.type = Proxy::Type::kSystem}, std::move(pp),
206 ShillClient());
207 proxy.OnPatchpanelReady(true);
208 EXPECT_CALL(mock_manager_,
209 SetProperty(shill::kDNSProxyIPv4AddressProperty,
210 brillo::Any(std::string("10.10.10.10")), _, _))
211 .WillOnce(Return(true));
212 proxy.OnShillReset(true);
213}
214
215} // namespace dns_proxy