blob: 40bc7592a90157c89ac504b545294e5495960eec [file] [log] [blame]
Garrick Evans08843932019-09-17 14:41:08 +09001// Copyright 2016 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
Jason Jeremy Imanadffbcb2020-08-31 13:21:36 +09005#include "patchpanel/dbus/client.h"
Garrick Evans08843932019-09-17 14:41:08 +09006
Hugo Benichicc6850f2020-01-17 13:26:06 +09007#include <fcntl.h>
8
Jie Jiang0a70acf2020-10-02 11:57:32 +09009#include <base/bind.h>
Garrick Evans08843932019-09-17 14:41:08 +090010#include <base/logging.h>
Garrick Evans6a062012021-02-15 09:25:44 +090011#include <base/memory/weak_ptr.h>
Woody Chowdee3c8b2020-12-04 20:03:54 +090012#include <brillo/dbus/dbus_proxy_util.h>
Garrick Evans08843932019-09-17 14:41:08 +090013#include <chromeos/dbus/service_constants.h>
14#include <dbus/message.h>
15#include <dbus/object_path.h>
16
Garrick Evans3388a032020-03-24 11:25:55 +090017#include "patchpanel/net_util.h"
Hugo Benichicc6850f2020-01-17 13:26:06 +090018
Garrick Evans08843932019-09-17 14:41:08 +090019namespace patchpanel {
20
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090021namespace {
22
23std::ostream& operator<<(std::ostream& stream,
24 const ModifyPortRuleRequest& request) {
25 stream << "{ operation: "
26 << ModifyPortRuleRequest::Operation_Name(request.op())
27 << ", rule type: "
28 << ModifyPortRuleRequest::RuleType_Name(request.type())
29 << ", protocol: "
30 << ModifyPortRuleRequest::Protocol_Name(request.proto());
31 if (!request.input_ifname().empty()) {
32 stream << ", input interface name: " << request.input_ifname();
33 }
34 if (!request.input_dst_ip().empty()) {
35 stream << ", input destination IP: " << request.input_dst_ip();
36 }
37 stream << ", input destination port: " << request.input_dst_port();
38 if (!request.dst_ip().empty()) {
39 stream << ", destination IP: " << request.dst_ip();
40 }
41 if (request.dst_port() != 0) {
42 stream << ", destination port: " << request.dst_port();
43 }
44 stream << " }";
45 return stream;
46}
47
Jie Jiang0a70acf2020-10-02 11:57:32 +090048void OnGetTrafficCountersDBusResponse(
49 Client::GetTrafficCountersCallback callback,
50 dbus::Response* dbus_response) {
51 if (!dbus_response) {
52 LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
53 "service";
54 std::move(callback).Run({});
55 return;
56 }
57
58 TrafficCountersResponse response;
59 dbus::MessageReader reader(dbus_response);
60 if (!reader.PopArrayOfBytesAsProto(&response)) {
61 LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
62 std::move(callback).Run({});
63 return;
64 }
65
66 std::move(callback).Run(
67 {response.counters().begin(), response.counters().end()});
68}
69
Garrick Evansf04f0442020-12-01 12:36:44 +090070void OnNetworkDeviceChangedSignal(
71 const Client::NetworkDeviceChangedSignalHandler& handler,
72 dbus::Signal* signal) {
73 dbus::MessageReader reader(signal);
74 NetworkDeviceChangedSignal proto;
75 if (!reader.PopArrayOfBytesAsProto(&proto)) {
76 LOG(ERROR) << "Failed to parse NetworkDeviceChangedSignal proto";
77 return;
78 }
79
80 handler.Run(proto);
81}
82
Jie Jiang25c1b972020-11-12 15:42:53 +090083void OnNeighborReachabilityEventSignal(
84 const Client::NeighborReachabilityEventHandler& handler,
Jie Jiange2e4c0b2020-09-16 18:48:43 +090085 dbus::Signal* signal) {
86 dbus::MessageReader reader(signal);
Jie Jiang25c1b972020-11-12 15:42:53 +090087 NeighborReachabilityEventSignal proto;
Jie Jiange2e4c0b2020-09-16 18:48:43 +090088 if (!reader.PopArrayOfBytesAsProto(&proto)) {
89 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
90 return;
91 }
92
93 handler.Run(proto);
94}
95
96void OnSignalConnectedCallback(const std::string& interface_name,
97 const std::string& signal_name,
98 bool success) {
99 if (!success)
100 LOG(ERROR) << "Failed to connect to " << signal_name;
101}
102
Jie Jiang81c84db2020-09-29 17:40:16 +0900103class ClientImpl : public Client {
104 public:
Woody Chowdee3c8b2020-12-04 20:03:54 +0900105 ClientImpl(const scoped_refptr<dbus::Bus>& bus,
106 dbus::ObjectProxy* proxy,
107 bool owns_bus)
108 : bus_(std::move(bus)), proxy_(proxy), owns_bus_(owns_bus) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900109 ClientImpl(const ClientImpl&) = delete;
110 ClientImpl& operator=(const ClientImpl&) = delete;
111
Jie Jiang81c84db2020-09-29 17:40:16 +0900112 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900113
Garrick Evansd0a646e2020-11-25 21:08:32 +0900114 void RegisterOnAvailableCallback(
115 base::RepeatingCallback<void(bool)> callback) override;
116
Garrick Evans6a062012021-02-15 09:25:44 +0900117 void RegisterProcessChangedCallback(
118 base::RepeatingCallback<void(bool)> callback) override;
119
Jie Jiang81c84db2020-09-29 17:40:16 +0900120 bool NotifyArcStartup(pid_t pid) override;
121 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +0900122
Jie Jiang81c84db2020-09-29 17:40:16 +0900123 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
124 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900125
Jie Jiang81c84db2020-09-29 17:40:16 +0900126 bool NotifyTerminaVmStartup(uint32_t cid,
127 NetworkDevice* device,
128 IPv4Subnet* container_subnet) override;
129 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900130
Jie Jiang81c84db2020-09-29 17:40:16 +0900131 bool NotifyPluginVmStartup(uint64_t vm_id,
132 int subnet_index,
133 NetworkDevice* device) override;
134 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900135
Jie Jiang81c84db2020-09-29 17:40:16 +0900136 bool DefaultVpnRouting(int socket) override;
137
138 bool RouteOnVpn(int socket) override;
139
140 bool BypassVpn(int socket) override;
141
142 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
143 ConnectNamespace(pid_t pid,
144 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900145 bool forward_user_traffic,
146 bool route_on_vpn,
147 TrafficCounter::Source traffic_source) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900148
149 void GetTrafficCounters(const std::set<std::string>& devices,
150 GetTrafficCountersCallback callback) override;
151
152 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
153 patchpanel::ModifyPortRuleRequest::RuleType type,
154 patchpanel::ModifyPortRuleRequest::Protocol proto,
155 const std::string& input_ifname,
156 const std::string& input_dst_ip,
157 uint32_t input_dst_port,
158 const std::string& dst_ip,
159 uint32_t dst_port) override;
160
Hugo Benichi007abcc2021-05-14 10:44:45 +0900161 bool SetVpnLockdown(bool enable) override;
162
Garrick Evans9e637982020-11-30 11:59:27 +0900163 std::vector<NetworkDevice> GetDevices() override;
164
Garrick Evansf04f0442020-12-01 12:36:44 +0900165 void RegisterNetworkDeviceChangedSignalHandler(
166 NetworkDeviceChangedSignalHandler handler) override;
167
Jie Jiang25c1b972020-11-12 15:42:53 +0900168 void RegisterNeighborReachabilityEventHandler(
169 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900170
171 private:
172 scoped_refptr<dbus::Bus> bus_;
Woody Chowdee3c8b2020-12-04 20:03:54 +0900173 dbus::ObjectProxy* proxy_ = nullptr; // owned by |bus_|
174 bool owns_bus_; // Yes if |bus_| is created by Client::New
Jie Jiang81c84db2020-09-29 17:40:16 +0900175
Garrick Evans6a062012021-02-15 09:25:44 +0900176 base::RepeatingCallback<void(bool)> owner_callback_;
177
178 void OnOwnerChanged(const std::string& old_owner,
179 const std::string& new_owner);
180
Jie Jiang81c84db2020-09-29 17:40:16 +0900181 bool SendSetVpnIntentRequest(int socket,
182 SetVpnIntentRequest::VpnRoutingPolicy policy);
Garrick Evans6a062012021-02-15 09:25:44 +0900183
184 base::WeakPtrFactory<ClientImpl> weak_factory_{this};
Jie Jiang81c84db2020-09-29 17:40:16 +0900185};
186
187ClientImpl::~ClientImpl() {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900188 if (bus_ && owns_bus_)
Garrick Evans93a83fc2020-03-31 15:16:55 +0900189 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900190}
191
Garrick Evansd0a646e2020-11-25 21:08:32 +0900192void ClientImpl::RegisterOnAvailableCallback(
193 base::RepeatingCallback<void(bool)> callback) {
194 if (!proxy_) {
195 LOG(ERROR) << "Cannot register callback - no proxy";
196 return;
197 }
198 proxy_->WaitForServiceToBeAvailable(callback);
199}
200
Garrick Evans6a062012021-02-15 09:25:44 +0900201void ClientImpl::RegisterProcessChangedCallback(
202 base::RepeatingCallback<void(bool)> callback) {
203 owner_callback_ = callback;
204 bus_->GetObjectProxy(kPatchPanelServiceName, dbus::ObjectPath{"/"})
205 ->SetNameOwnerChangedCallback(
206 base::Bind(&ClientImpl::OnOwnerChanged, weak_factory_.GetWeakPtr()));
207}
208
209void ClientImpl::OnOwnerChanged(const std::string& old_owner,
210 const std::string& new_owner) {
211 if (new_owner.empty()) {
212 LOG(INFO) << "Patchpanel lost";
213 if (!owner_callback_.is_null())
214 owner_callback_.Run(false);
215 return;
216 }
217
218 LOG(INFO) << "Patchpanel reset";
219 if (!owner_callback_.is_null())
220 owner_callback_.Run(true);
221}
222
Jie Jiang81c84db2020-09-29 17:40:16 +0900223bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900224 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
225 dbus::MessageWriter writer(&method_call);
226
227 ArcStartupRequest request;
228 request.set_pid(static_cast<uint32_t>(pid));
229
230 if (!writer.AppendProtoAsArrayOfBytes(request)) {
231 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
232 return false;
233 }
234
Woody Chowdee3c8b2020-12-04 20:03:54 +0900235 std::unique_ptr<dbus::Response> dbus_response =
236 brillo::dbus_utils::CallDBusMethod(
237 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900238 if (!dbus_response) {
239 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
240 return false;
241 }
242
243 dbus::MessageReader reader(dbus_response.get());
244 ArcStartupResponse response;
245 if (!reader.PopArrayOfBytesAsProto(&response)) {
246 LOG(ERROR) << "Failed to parse response proto";
247 return false;
248 }
249
250 return true;
251}
252
Jie Jiang81c84db2020-09-29 17:40:16 +0900253bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900254 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
255 dbus::MessageWriter writer(&method_call);
256
257 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900258 if (!writer.AppendProtoAsArrayOfBytes(request)) {
259 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
260 return false;
261 }
262
Woody Chowdee3c8b2020-12-04 20:03:54 +0900263 std::unique_ptr<dbus::Response> dbus_response =
264 brillo::dbus_utils::CallDBusMethod(
265 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900266 if (!dbus_response) {
267 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
268 return false;
269 }
270
271 dbus::MessageReader reader(dbus_response.get());
272 ArcShutdownResponse response;
273 if (!reader.PopArrayOfBytesAsProto(&response)) {
274 LOG(ERROR) << "Failed to parse response proto";
275 return false;
276 }
277
278 return true;
279}
280
Jie Jiang81c84db2020-09-29 17:40:16 +0900281std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900282 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
283 dbus::MessageWriter writer(&method_call);
284
285 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900286 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900287
288 if (!writer.AppendProtoAsArrayOfBytes(request)) {
289 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
290 return {};
291 }
292
Woody Chowdee3c8b2020-12-04 20:03:54 +0900293 std::unique_ptr<dbus::Response> dbus_response =
294 brillo::dbus_utils::CallDBusMethod(
295 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900296 if (!dbus_response) {
297 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
298 return {};
299 }
300
301 dbus::MessageReader reader(dbus_response.get());
302 ArcVmStartupResponse response;
303 if (!reader.PopArrayOfBytesAsProto(&response)) {
304 LOG(ERROR) << "Failed to parse response proto";
305 return {};
306 }
307
Garrick Evans3388a032020-03-24 11:25:55 +0900308 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900309 for (const auto& d : response.devices()) {
310 devices.emplace_back(d);
311 }
312 return devices;
313}
314
Jie Jiang81c84db2020-09-29 17:40:16 +0900315bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900316 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
317 dbus::MessageWriter writer(&method_call);
318
319 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900320 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900321
322 if (!writer.AppendProtoAsArrayOfBytes(request)) {
323 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
324 return false;
325 }
326
Woody Chowdee3c8b2020-12-04 20:03:54 +0900327 std::unique_ptr<dbus::Response> dbus_response =
328 brillo::dbus_utils::CallDBusMethod(
329 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900330 if (!dbus_response) {
331 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
332 return false;
333 }
334
335 dbus::MessageReader reader(dbus_response.get());
336 ArcVmShutdownResponse response;
337 if (!reader.PopArrayOfBytesAsProto(&response)) {
338 LOG(ERROR) << "Failed to parse response proto";
339 return false;
340 }
341
342 return true;
343}
344
Jie Jiang81c84db2020-09-29 17:40:16 +0900345bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
346 NetworkDevice* device,
347 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900348 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
349 dbus::MessageWriter writer(&method_call);
350
351 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900352 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900353
354 if (!writer.AppendProtoAsArrayOfBytes(request)) {
355 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
356 return false;
357 }
358
Woody Chowdee3c8b2020-12-04 20:03:54 +0900359 std::unique_ptr<dbus::Response> dbus_response =
360 brillo::dbus_utils::CallDBusMethod(
361 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans27b74032019-11-19 13:33:47 +0900362 if (!dbus_response) {
363 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
364 return false;
365 }
366
367 dbus::MessageReader reader(dbus_response.get());
368 TerminaVmStartupResponse response;
369 if (!reader.PopArrayOfBytesAsProto(&response)) {
370 LOG(ERROR) << "Failed to parse response proto";
371 return false;
372 }
373
374 if (!response.has_device()) {
375 LOG(ERROR) << "No device found";
376 return false;
377 }
378 *device = response.device();
379
380 if (response.has_container_subnet()) {
381 *container_subnet = response.container_subnet();
382 } else {
383 LOG(WARNING) << "No container subnet found";
384 }
385
386 return true;
387}
388
Jie Jiang81c84db2020-09-29 17:40:16 +0900389bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900390 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
391 dbus::MessageWriter writer(&method_call);
392
393 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900394 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900395
396 if (!writer.AppendProtoAsArrayOfBytes(request)) {
397 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
398 return false;
399 }
400
Woody Chowdee3c8b2020-12-04 20:03:54 +0900401 std::unique_ptr<dbus::Response> dbus_response =
402 brillo::dbus_utils::CallDBusMethod(
403 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans27b74032019-11-19 13:33:47 +0900404 if (!dbus_response) {
405 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
406 return false;
407 }
408
409 dbus::MessageReader reader(dbus_response.get());
410 TerminaVmShutdownResponse response;
411 if (!reader.PopArrayOfBytesAsProto(&response)) {
412 LOG(ERROR) << "Failed to parse response proto";
413 return false;
414 }
415
416 return true;
417}
418
Jie Jiang81c84db2020-09-29 17:40:16 +0900419bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
420 int subnet_index,
421 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900422 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
423 dbus::MessageWriter writer(&method_call);
424
425 PluginVmStartupRequest request;
426 request.set_id(vm_id);
427 request.set_subnet_index(subnet_index);
428
429 if (!writer.AppendProtoAsArrayOfBytes(request)) {
430 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
431 return false;
432 }
433
Woody Chowdee3c8b2020-12-04 20:03:54 +0900434 std::unique_ptr<dbus::Response> dbus_response =
435 brillo::dbus_utils::CallDBusMethod(
436 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900437 if (!dbus_response) {
438 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
439 return false;
440 }
441
442 dbus::MessageReader reader(dbus_response.get());
443 PluginVmStartupResponse response;
444 if (!reader.PopArrayOfBytesAsProto(&response)) {
445 LOG(ERROR) << "Failed to parse response proto";
446 return false;
447 }
448
449 if (!response.has_device()) {
450 LOG(ERROR) << "No device found";
451 return false;
452 }
453 *device = response.device();
454
455 return true;
456}
457
Jie Jiang81c84db2020-09-29 17:40:16 +0900458bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900459 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
460 dbus::MessageWriter writer(&method_call);
461
462 PluginVmShutdownRequest request;
463 request.set_id(vm_id);
464
465 if (!writer.AppendProtoAsArrayOfBytes(request)) {
466 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
467 return false;
468 }
469
Woody Chowdee3c8b2020-12-04 20:03:54 +0900470 std::unique_ptr<dbus::Response> dbus_response =
471 brillo::dbus_utils::CallDBusMethod(
472 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900473 if (!dbus_response) {
474 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
475 return false;
476 }
477
478 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900479 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900480 if (!reader.PopArrayOfBytesAsProto(&response)) {
481 LOG(ERROR) << "Failed to parse response proto";
482 return false;
483 }
484
485 return true;
486}
487
Jie Jiang81c84db2020-09-29 17:40:16 +0900488bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900489 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
490}
491
Jie Jiang81c84db2020-09-29 17:40:16 +0900492bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900493 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
494}
495
Jie Jiang81c84db2020-09-29 17:40:16 +0900496bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900497 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
498}
499
Jie Jiang81c84db2020-09-29 17:40:16 +0900500bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900501 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
502 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
503 dbus::MessageWriter writer(&method_call);
504
505 SetVpnIntentRequest request;
506 SetVpnIntentResponse response;
507 request.set_policy(policy);
508
509 if (!writer.AppendProtoAsArrayOfBytes(request)) {
510 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
511 return false;
512 }
513 writer.AppendFileDescriptor(socket);
514
Woody Chowdee3c8b2020-12-04 20:03:54 +0900515 std::unique_ptr<dbus::Response> dbus_response =
516 brillo::dbus_utils::CallDBusMethod(
517 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900518 if (!dbus_response) {
519 LOG(ERROR)
520 << "Failed to send SetVpnIntentRequest message to patchpanel service";
521 return false;
522 }
523
524 dbus::MessageReader reader(dbus_response.get());
525 if (!reader.PopArrayOfBytesAsProto(&response)) {
526 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
527 return false;
528 }
529
530 if (!response.success()) {
531 LOG(ERROR) << "SetVpnIntentRequest failed";
532 return false;
533 }
534 return true;
535}
536
Hugo Benichicc6850f2020-01-17 13:26:06 +0900537std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900538ClientImpl::ConnectNamespace(pid_t pid,
539 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900540 bool forward_user_traffic,
541 bool route_on_vpn,
542 TrafficCounter::Source traffic_source) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900543 // Prepare and serialize the request proto.
544 ConnectNamespaceRequest request;
545 request.set_pid(static_cast<int32_t>(pid));
546 request.set_outbound_physical_device(outbound_ifname);
547 request.set_allow_user_traffic(forward_user_traffic);
Garrick Evans58697022020-12-03 12:41:13 +0900548 request.set_route_on_vpn(route_on_vpn);
549 request.set_traffic_source(traffic_source);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900550
551 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
552 dbus::MessageWriter writer(&method_call);
553 if (!writer.AppendProtoAsArrayOfBytes(request)) {
554 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
555 return {};
556 }
557
558 // Prepare an fd pair and append one fd directly after the serialized request.
559 int pipe_fds[2] = {-1, -1};
560 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
561 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
562 return {};
563 }
564 base::ScopedFD fd_local(pipe_fds[0]);
565 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
566 // make sure the original fd is closed eventually.
567 base::ScopedFD fd_remote(pipe_fds[1]);
568 writer.AppendFileDescriptor(pipe_fds[1]);
569
Woody Chowdee3c8b2020-12-04 20:03:54 +0900570 std::unique_ptr<dbus::Response> dbus_response =
571 brillo::dbus_utils::CallDBusMethod(
572 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900573 if (!dbus_response) {
574 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
575 return {};
576 }
577
578 dbus::MessageReader reader(dbus_response.get());
579 ConnectNamespaceResponse response;
580 if (!reader.PopArrayOfBytesAsProto(&response)) {
581 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
582 return {};
583 }
584
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900585 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900586 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
587 return {};
588 }
589
Garrick Evans3388a032020-03-24 11:25:55 +0900590 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900591 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
592 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900593 << " succeeded: peer_ifname=" << response.peer_ifname()
594 << " peer_ipv4_address="
595 << IPv4AddressToString(response.peer_ipv4_address())
596 << " host_ifname=" << response.host_ifname()
597 << " host_ipv4_address="
598 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900599 << " subnet=" << subnet_info;
600
601 return std::make_pair(std::move(fd_local), std::move(response));
602}
603
Jie Jiang81c84db2020-09-29 17:40:16 +0900604void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
605 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900606 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
607 dbus::MessageWriter writer(&method_call);
608
609 TrafficCountersRequest request;
610 for (const auto& device : devices) {
611 request.add_devices(device);
612 }
613
614 if (!writer.AppendProtoAsArrayOfBytes(request)) {
615 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900616 std::move(callback).Run({});
617 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900618 }
619
Jie Jiang0a70acf2020-10-02 11:57:32 +0900620 proxy_->CallMethod(
621 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
622 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900623}
624
Jie Jiang81c84db2020-09-29 17:40:16 +0900625bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
626 ModifyPortRuleRequest::RuleType type,
627 ModifyPortRuleRequest::Protocol proto,
628 const std::string& input_ifname,
629 const std::string& input_dst_ip,
630 uint32_t input_dst_port,
631 const std::string& dst_ip,
632 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900633 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
634 dbus::MessageWriter writer(&method_call);
635
636 ModifyPortRuleRequest request;
637 ModifyPortRuleResponse response;
638
639 request.set_op(op);
640 request.set_type(type);
641 request.set_proto(proto);
642 request.set_input_ifname(input_ifname);
643 request.set_input_dst_ip(input_dst_ip);
644 request.set_input_dst_port(input_dst_port);
645 request.set_dst_ip(dst_ip);
646 request.set_dst_port(dst_port);
647
648 if (!writer.AppendProtoAsArrayOfBytes(request)) {
649 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
650 return false;
651 }
652
Woody Chowdee3c8b2020-12-04 20:03:54 +0900653 std::unique_ptr<dbus::Response> dbus_response =
654 brillo::dbus_utils::CallDBusMethod(
655 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900656 if (!dbus_response) {
657 LOG(ERROR)
658 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
659 << request;
660 return false;
661 }
662
663 dbus::MessageReader reader(dbus_response.get());
664 if (!reader.PopArrayOfBytesAsProto(&response)) {
665 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
666 return false;
667 }
668
669 if (!response.success()) {
670 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
671 return false;
672 }
673 return true;
674}
675
Hugo Benichi007abcc2021-05-14 10:44:45 +0900676bool ClientImpl::SetVpnLockdown(bool enable) {
677 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnLockdown);
678 dbus::MessageWriter writer(&method_call);
679
680 SetVpnLockdownRequest request;
681 SetVpnLockdownResponse response;
682
683 request.set_enable_vpn_lockdown(enable);
684 if (!writer.AppendProtoAsArrayOfBytes(request)) {
685 LOG(ERROR) << "Failed to encode SetVpnLockdownRequest proto";
686 return false;
687 }
688
689 std::unique_ptr<dbus::Response> dbus_response =
690 brillo::dbus_utils::CallDBusMethod(
691 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
692 if (!dbus_response) {
693 LOG(ERROR) << "Failed to call SetVpnLockdown patchpanel API";
694 return false;
695 }
696
697 dbus::MessageReader reader(dbus_response.get());
698 if (!reader.PopArrayOfBytesAsProto(&response)) {
699 LOG(ERROR) << "Failed to parse SetVpnLockdownResponse";
700 return false;
701 }
702
703 return true;
704}
705
Garrick Evans9e637982020-11-30 11:59:27 +0900706std::vector<NetworkDevice> ClientImpl::GetDevices() {
707 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
708 dbus::MessageWriter writer(&method_call);
709
710 GetDevicesRequest request;
711 if (!writer.AppendProtoAsArrayOfBytes(request)) {
712 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
713 return {};
714 }
715
Woody Chowdee3c8b2020-12-04 20:03:54 +0900716 std::unique_ptr<dbus::Response> dbus_response =
717 brillo::dbus_utils::CallDBusMethod(
718 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans9e637982020-11-30 11:59:27 +0900719 if (!dbus_response) {
720 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
721 return {};
722 }
723
724 dbus::MessageReader reader(dbus_response.get());
725 GetDevicesResponse response;
726 if (!reader.PopArrayOfBytesAsProto(&response)) {
727 LOG(ERROR) << "Failed to parse response proto";
728 return {};
729 }
730
731 std::vector<NetworkDevice> devices;
732 for (const auto& d : response.devices()) {
733 devices.emplace_back(d);
734 }
735 return devices;
736}
737
Garrick Evansf04f0442020-12-01 12:36:44 +0900738void ClientImpl::RegisterNetworkDeviceChangedSignalHandler(
739 NetworkDeviceChangedSignalHandler handler) {
740 proxy_->ConnectToSignal(
741 kPatchPanelInterface, kNetworkDeviceChangedSignal,
742 base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
743 base::BindOnce(OnSignalConnectedCallback));
744}
745
Jie Jiang25c1b972020-11-12 15:42:53 +0900746void ClientImpl::RegisterNeighborReachabilityEventHandler(
747 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900748 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900749 kPatchPanelInterface, kNeighborReachabilityEventSignal,
750 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900751 base::BindOnce(OnSignalConnectedCallback));
752}
753
Woody Chowdee3c8b2020-12-04 20:03:54 +0900754dbus::ObjectProxy* GetProxy(const scoped_refptr<dbus::Bus>& bus) {
755 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
756 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
757 if (!proxy) {
758 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
759 }
760 return proxy;
761}
762
Jie Jiang81c84db2020-09-29 17:40:16 +0900763} // namespace
764
765// static
766std::unique_ptr<Client> Client::New() {
767 dbus::Bus::Options opts;
768 opts.bus_type = dbus::Bus::SYSTEM;
769 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
770
771 if (!bus->Connect()) {
772 LOG(ERROR) << "Failed to connect to system bus";
773 return nullptr;
774 }
775
Woody Chowdee3c8b2020-12-04 20:03:54 +0900776 dbus::ObjectProxy* proxy = GetProxy(bus);
777 if (!proxy)
Jie Jiang81c84db2020-09-29 17:40:16 +0900778 return nullptr;
Jie Jiang81c84db2020-09-29 17:40:16 +0900779
Woody Chowdee3c8b2020-12-04 20:03:54 +0900780 return std::make_unique<ClientImpl>(std::move(bus), proxy,
781 true /* owns_bus */);
782}
783
784std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus) {
785 dbus::ObjectProxy* proxy = GetProxy(bus);
786 if (!proxy)
787 return nullptr;
788
789 return std::make_unique<ClientImpl>(std::move(bus), proxy,
790 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900791}
792
793std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
794 dbus::ObjectProxy* proxy) {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900795 return std::make_unique<ClientImpl>(std::move(bus), proxy,
796 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900797}
798
Garrick Evans08843932019-09-17 14:41:08 +0900799} // namespace patchpanel