blob: 322cea4262d62abaa2bd5df947dcede085705fdf [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>
Woody Chowdee3c8b2020-12-04 20:03:54 +090011#include <brillo/dbus/dbus_proxy_util.h>
Garrick Evans08843932019-09-17 14:41:08 +090012#include <chromeos/dbus/service_constants.h>
13#include <dbus/message.h>
14#include <dbus/object_path.h>
15
Garrick Evans3388a032020-03-24 11:25:55 +090016#include "patchpanel/net_util.h"
Hugo Benichicc6850f2020-01-17 13:26:06 +090017
Garrick Evans08843932019-09-17 14:41:08 +090018namespace patchpanel {
19
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090020namespace {
21
22std::ostream& operator<<(std::ostream& stream,
23 const ModifyPortRuleRequest& request) {
24 stream << "{ operation: "
25 << ModifyPortRuleRequest::Operation_Name(request.op())
26 << ", rule type: "
27 << ModifyPortRuleRequest::RuleType_Name(request.type())
28 << ", protocol: "
29 << ModifyPortRuleRequest::Protocol_Name(request.proto());
30 if (!request.input_ifname().empty()) {
31 stream << ", input interface name: " << request.input_ifname();
32 }
33 if (!request.input_dst_ip().empty()) {
34 stream << ", input destination IP: " << request.input_dst_ip();
35 }
36 stream << ", input destination port: " << request.input_dst_port();
37 if (!request.dst_ip().empty()) {
38 stream << ", destination IP: " << request.dst_ip();
39 }
40 if (request.dst_port() != 0) {
41 stream << ", destination port: " << request.dst_port();
42 }
43 stream << " }";
44 return stream;
45}
46
Jie Jiang0a70acf2020-10-02 11:57:32 +090047void OnGetTrafficCountersDBusResponse(
48 Client::GetTrafficCountersCallback callback,
49 dbus::Response* dbus_response) {
50 if (!dbus_response) {
51 LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
52 "service";
53 std::move(callback).Run({});
54 return;
55 }
56
57 TrafficCountersResponse response;
58 dbus::MessageReader reader(dbus_response);
59 if (!reader.PopArrayOfBytesAsProto(&response)) {
60 LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
61 std::move(callback).Run({});
62 return;
63 }
64
65 std::move(callback).Run(
66 {response.counters().begin(), response.counters().end()});
67}
68
Garrick Evansf04f0442020-12-01 12:36:44 +090069void OnNetworkDeviceChangedSignal(
70 const Client::NetworkDeviceChangedSignalHandler& handler,
71 dbus::Signal* signal) {
72 dbus::MessageReader reader(signal);
73 NetworkDeviceChangedSignal proto;
74 if (!reader.PopArrayOfBytesAsProto(&proto)) {
75 LOG(ERROR) << "Failed to parse NetworkDeviceChangedSignal proto";
76 return;
77 }
78
79 handler.Run(proto);
80}
81
Jie Jiang25c1b972020-11-12 15:42:53 +090082void OnNeighborReachabilityEventSignal(
83 const Client::NeighborReachabilityEventHandler& handler,
Jie Jiange2e4c0b2020-09-16 18:48:43 +090084 dbus::Signal* signal) {
85 dbus::MessageReader reader(signal);
Jie Jiang25c1b972020-11-12 15:42:53 +090086 NeighborReachabilityEventSignal proto;
Jie Jiange2e4c0b2020-09-16 18:48:43 +090087 if (!reader.PopArrayOfBytesAsProto(&proto)) {
88 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
89 return;
90 }
91
92 handler.Run(proto);
93}
94
95void OnSignalConnectedCallback(const std::string& interface_name,
96 const std::string& signal_name,
97 bool success) {
98 if (!success)
99 LOG(ERROR) << "Failed to connect to " << signal_name;
100}
101
Jie Jiang81c84db2020-09-29 17:40:16 +0900102class ClientImpl : public Client {
103 public:
Woody Chowdee3c8b2020-12-04 20:03:54 +0900104 ClientImpl(const scoped_refptr<dbus::Bus>& bus,
105 dbus::ObjectProxy* proxy,
106 bool owns_bus)
107 : bus_(std::move(bus)), proxy_(proxy), owns_bus_(owns_bus) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900108 ClientImpl(const ClientImpl&) = delete;
109 ClientImpl& operator=(const ClientImpl&) = delete;
110
Jie Jiang81c84db2020-09-29 17:40:16 +0900111 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900112
Garrick Evansd0a646e2020-11-25 21:08:32 +0900113 void RegisterOnAvailableCallback(
114 base::RepeatingCallback<void(bool)> callback) override;
115
Jie Jiang81c84db2020-09-29 17:40:16 +0900116 bool NotifyArcStartup(pid_t pid) override;
117 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +0900118
Jie Jiang81c84db2020-09-29 17:40:16 +0900119 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
120 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900121
Jie Jiang81c84db2020-09-29 17:40:16 +0900122 bool NotifyTerminaVmStartup(uint32_t cid,
123 NetworkDevice* device,
124 IPv4Subnet* container_subnet) override;
125 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900126
Jie Jiang81c84db2020-09-29 17:40:16 +0900127 bool NotifyPluginVmStartup(uint64_t vm_id,
128 int subnet_index,
129 NetworkDevice* device) override;
130 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900131
Jie Jiang81c84db2020-09-29 17:40:16 +0900132 bool DefaultVpnRouting(int socket) override;
133
134 bool RouteOnVpn(int socket) override;
135
136 bool BypassVpn(int socket) override;
137
138 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
139 ConnectNamespace(pid_t pid,
140 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900141 bool forward_user_traffic,
142 bool route_on_vpn,
143 TrafficCounter::Source traffic_source) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900144
145 void GetTrafficCounters(const std::set<std::string>& devices,
146 GetTrafficCountersCallback callback) override;
147
148 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
149 patchpanel::ModifyPortRuleRequest::RuleType type,
150 patchpanel::ModifyPortRuleRequest::Protocol proto,
151 const std::string& input_ifname,
152 const std::string& input_dst_ip,
153 uint32_t input_dst_port,
154 const std::string& dst_ip,
155 uint32_t dst_port) override;
156
Garrick Evans9e637982020-11-30 11:59:27 +0900157 std::vector<NetworkDevice> GetDevices() override;
158
Garrick Evansf04f0442020-12-01 12:36:44 +0900159 void RegisterNetworkDeviceChangedSignalHandler(
160 NetworkDeviceChangedSignalHandler handler) override;
161
Jie Jiang25c1b972020-11-12 15:42:53 +0900162 void RegisterNeighborReachabilityEventHandler(
163 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900164
165 private:
166 scoped_refptr<dbus::Bus> bus_;
Woody Chowdee3c8b2020-12-04 20:03:54 +0900167 dbus::ObjectProxy* proxy_ = nullptr; // owned by |bus_|
168 bool owns_bus_; // Yes if |bus_| is created by Client::New
Jie Jiang81c84db2020-09-29 17:40:16 +0900169
170 bool SendSetVpnIntentRequest(int socket,
171 SetVpnIntentRequest::VpnRoutingPolicy policy);
Jie Jiang81c84db2020-09-29 17:40:16 +0900172};
173
174ClientImpl::~ClientImpl() {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900175 if (bus_ && owns_bus_)
Garrick Evans93a83fc2020-03-31 15:16:55 +0900176 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900177}
178
Garrick Evansd0a646e2020-11-25 21:08:32 +0900179void ClientImpl::RegisterOnAvailableCallback(
180 base::RepeatingCallback<void(bool)> callback) {
181 if (!proxy_) {
182 LOG(ERROR) << "Cannot register callback - no proxy";
183 return;
184 }
185 proxy_->WaitForServiceToBeAvailable(callback);
186}
187
Jie Jiang81c84db2020-09-29 17:40:16 +0900188bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900189 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
190 dbus::MessageWriter writer(&method_call);
191
192 ArcStartupRequest request;
193 request.set_pid(static_cast<uint32_t>(pid));
194
195 if (!writer.AppendProtoAsArrayOfBytes(request)) {
196 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
197 return false;
198 }
199
Woody Chowdee3c8b2020-12-04 20:03:54 +0900200 std::unique_ptr<dbus::Response> dbus_response =
201 brillo::dbus_utils::CallDBusMethod(
202 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900203 if (!dbus_response) {
204 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
205 return false;
206 }
207
208 dbus::MessageReader reader(dbus_response.get());
209 ArcStartupResponse response;
210 if (!reader.PopArrayOfBytesAsProto(&response)) {
211 LOG(ERROR) << "Failed to parse response proto";
212 return false;
213 }
214
215 return true;
216}
217
Jie Jiang81c84db2020-09-29 17:40:16 +0900218bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900219 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
220 dbus::MessageWriter writer(&method_call);
221
222 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900223 if (!writer.AppendProtoAsArrayOfBytes(request)) {
224 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
225 return false;
226 }
227
Woody Chowdee3c8b2020-12-04 20:03:54 +0900228 std::unique_ptr<dbus::Response> dbus_response =
229 brillo::dbus_utils::CallDBusMethod(
230 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900231 if (!dbus_response) {
232 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
233 return false;
234 }
235
236 dbus::MessageReader reader(dbus_response.get());
237 ArcShutdownResponse response;
238 if (!reader.PopArrayOfBytesAsProto(&response)) {
239 LOG(ERROR) << "Failed to parse response proto";
240 return false;
241 }
242
243 return true;
244}
245
Jie Jiang81c84db2020-09-29 17:40:16 +0900246std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900247 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
248 dbus::MessageWriter writer(&method_call);
249
250 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900251 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900252
253 if (!writer.AppendProtoAsArrayOfBytes(request)) {
254 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
255 return {};
256 }
257
Woody Chowdee3c8b2020-12-04 20:03:54 +0900258 std::unique_ptr<dbus::Response> dbus_response =
259 brillo::dbus_utils::CallDBusMethod(
260 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900261 if (!dbus_response) {
262 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
263 return {};
264 }
265
266 dbus::MessageReader reader(dbus_response.get());
267 ArcVmStartupResponse response;
268 if (!reader.PopArrayOfBytesAsProto(&response)) {
269 LOG(ERROR) << "Failed to parse response proto";
270 return {};
271 }
272
Garrick Evans3388a032020-03-24 11:25:55 +0900273 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900274 for (const auto& d : response.devices()) {
275 devices.emplace_back(d);
276 }
277 return devices;
278}
279
Jie Jiang81c84db2020-09-29 17:40:16 +0900280bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900281 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
282 dbus::MessageWriter writer(&method_call);
283
284 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900285 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900286
287 if (!writer.AppendProtoAsArrayOfBytes(request)) {
288 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
289 return false;
290 }
291
Woody Chowdee3c8b2020-12-04 20:03:54 +0900292 std::unique_ptr<dbus::Response> dbus_response =
293 brillo::dbus_utils::CallDBusMethod(
294 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900295 if (!dbus_response) {
296 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
297 return false;
298 }
299
300 dbus::MessageReader reader(dbus_response.get());
301 ArcVmShutdownResponse response;
302 if (!reader.PopArrayOfBytesAsProto(&response)) {
303 LOG(ERROR) << "Failed to parse response proto";
304 return false;
305 }
306
307 return true;
308}
309
Jie Jiang81c84db2020-09-29 17:40:16 +0900310bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
311 NetworkDevice* device,
312 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900313 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
314 dbus::MessageWriter writer(&method_call);
315
316 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900317 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900318
319 if (!writer.AppendProtoAsArrayOfBytes(request)) {
320 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
321 return false;
322 }
323
Woody Chowdee3c8b2020-12-04 20:03:54 +0900324 std::unique_ptr<dbus::Response> dbus_response =
325 brillo::dbus_utils::CallDBusMethod(
326 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans27b74032019-11-19 13:33:47 +0900327 if (!dbus_response) {
328 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
329 return false;
330 }
331
332 dbus::MessageReader reader(dbus_response.get());
333 TerminaVmStartupResponse response;
334 if (!reader.PopArrayOfBytesAsProto(&response)) {
335 LOG(ERROR) << "Failed to parse response proto";
336 return false;
337 }
338
339 if (!response.has_device()) {
340 LOG(ERROR) << "No device found";
341 return false;
342 }
343 *device = response.device();
344
345 if (response.has_container_subnet()) {
346 *container_subnet = response.container_subnet();
347 } else {
348 LOG(WARNING) << "No container subnet found";
349 }
350
351 return true;
352}
353
Jie Jiang81c84db2020-09-29 17:40:16 +0900354bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900355 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
356 dbus::MessageWriter writer(&method_call);
357
358 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900359 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900360
361 if (!writer.AppendProtoAsArrayOfBytes(request)) {
362 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
363 return false;
364 }
365
Woody Chowdee3c8b2020-12-04 20:03:54 +0900366 std::unique_ptr<dbus::Response> dbus_response =
367 brillo::dbus_utils::CallDBusMethod(
368 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans27b74032019-11-19 13:33:47 +0900369 if (!dbus_response) {
370 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
371 return false;
372 }
373
374 dbus::MessageReader reader(dbus_response.get());
375 TerminaVmShutdownResponse response;
376 if (!reader.PopArrayOfBytesAsProto(&response)) {
377 LOG(ERROR) << "Failed to parse response proto";
378 return false;
379 }
380
381 return true;
382}
383
Jie Jiang81c84db2020-09-29 17:40:16 +0900384bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
385 int subnet_index,
386 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900387 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
388 dbus::MessageWriter writer(&method_call);
389
390 PluginVmStartupRequest request;
391 request.set_id(vm_id);
392 request.set_subnet_index(subnet_index);
393
394 if (!writer.AppendProtoAsArrayOfBytes(request)) {
395 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
396 return false;
397 }
398
Woody Chowdee3c8b2020-12-04 20:03:54 +0900399 std::unique_ptr<dbus::Response> dbus_response =
400 brillo::dbus_utils::CallDBusMethod(
401 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900402 if (!dbus_response) {
403 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
404 return false;
405 }
406
407 dbus::MessageReader reader(dbus_response.get());
408 PluginVmStartupResponse response;
409 if (!reader.PopArrayOfBytesAsProto(&response)) {
410 LOG(ERROR) << "Failed to parse response proto";
411 return false;
412 }
413
414 if (!response.has_device()) {
415 LOG(ERROR) << "No device found";
416 return false;
417 }
418 *device = response.device();
419
420 return true;
421}
422
Jie Jiang81c84db2020-09-29 17:40:16 +0900423bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900424 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
425 dbus::MessageWriter writer(&method_call);
426
427 PluginVmShutdownRequest request;
428 request.set_id(vm_id);
429
430 if (!writer.AppendProtoAsArrayOfBytes(request)) {
431 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
432 return false;
433 }
434
Woody Chowdee3c8b2020-12-04 20:03:54 +0900435 std::unique_ptr<dbus::Response> dbus_response =
436 brillo::dbus_utils::CallDBusMethod(
437 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900438 if (!dbus_response) {
439 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
440 return false;
441 }
442
443 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900444 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900445 if (!reader.PopArrayOfBytesAsProto(&response)) {
446 LOG(ERROR) << "Failed to parse response proto";
447 return false;
448 }
449
450 return true;
451}
452
Jie Jiang81c84db2020-09-29 17:40:16 +0900453bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900454 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
455}
456
Jie Jiang81c84db2020-09-29 17:40:16 +0900457bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900458 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
459}
460
Jie Jiang81c84db2020-09-29 17:40:16 +0900461bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900462 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
463}
464
Jie Jiang81c84db2020-09-29 17:40:16 +0900465bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900466 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
467 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
468 dbus::MessageWriter writer(&method_call);
469
470 SetVpnIntentRequest request;
471 SetVpnIntentResponse response;
472 request.set_policy(policy);
473
474 if (!writer.AppendProtoAsArrayOfBytes(request)) {
475 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
476 return false;
477 }
478 writer.AppendFileDescriptor(socket);
479
Woody Chowdee3c8b2020-12-04 20:03:54 +0900480 std::unique_ptr<dbus::Response> dbus_response =
481 brillo::dbus_utils::CallDBusMethod(
482 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900483 if (!dbus_response) {
484 LOG(ERROR)
485 << "Failed to send SetVpnIntentRequest message to patchpanel service";
486 return false;
487 }
488
489 dbus::MessageReader reader(dbus_response.get());
490 if (!reader.PopArrayOfBytesAsProto(&response)) {
491 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
492 return false;
493 }
494
495 if (!response.success()) {
496 LOG(ERROR) << "SetVpnIntentRequest failed";
497 return false;
498 }
499 return true;
500}
501
Hugo Benichicc6850f2020-01-17 13:26:06 +0900502std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900503ClientImpl::ConnectNamespace(pid_t pid,
504 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900505 bool forward_user_traffic,
506 bool route_on_vpn,
507 TrafficCounter::Source traffic_source) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900508 // Prepare and serialize the request proto.
509 ConnectNamespaceRequest request;
510 request.set_pid(static_cast<int32_t>(pid));
511 request.set_outbound_physical_device(outbound_ifname);
512 request.set_allow_user_traffic(forward_user_traffic);
Garrick Evans58697022020-12-03 12:41:13 +0900513 request.set_route_on_vpn(route_on_vpn);
514 request.set_traffic_source(traffic_source);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900515
516 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
517 dbus::MessageWriter writer(&method_call);
518 if (!writer.AppendProtoAsArrayOfBytes(request)) {
519 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
520 return {};
521 }
522
523 // Prepare an fd pair and append one fd directly after the serialized request.
524 int pipe_fds[2] = {-1, -1};
525 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
526 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
527 return {};
528 }
529 base::ScopedFD fd_local(pipe_fds[0]);
530 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
531 // make sure the original fd is closed eventually.
532 base::ScopedFD fd_remote(pipe_fds[1]);
533 writer.AppendFileDescriptor(pipe_fds[1]);
534
Woody Chowdee3c8b2020-12-04 20:03:54 +0900535 std::unique_ptr<dbus::Response> dbus_response =
536 brillo::dbus_utils::CallDBusMethod(
537 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900538 if (!dbus_response) {
539 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
540 return {};
541 }
542
543 dbus::MessageReader reader(dbus_response.get());
544 ConnectNamespaceResponse response;
545 if (!reader.PopArrayOfBytesAsProto(&response)) {
546 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
547 return {};
548 }
549
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900550 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900551 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
552 return {};
553 }
554
Garrick Evans3388a032020-03-24 11:25:55 +0900555 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900556 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
557 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900558 << " succeeded: peer_ifname=" << response.peer_ifname()
559 << " peer_ipv4_address="
560 << IPv4AddressToString(response.peer_ipv4_address())
561 << " host_ifname=" << response.host_ifname()
562 << " host_ipv4_address="
563 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900564 << " subnet=" << subnet_info;
565
566 return std::make_pair(std::move(fd_local), std::move(response));
567}
568
Jie Jiang81c84db2020-09-29 17:40:16 +0900569void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
570 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900571 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
572 dbus::MessageWriter writer(&method_call);
573
574 TrafficCountersRequest request;
575 for (const auto& device : devices) {
576 request.add_devices(device);
577 }
578
579 if (!writer.AppendProtoAsArrayOfBytes(request)) {
580 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900581 std::move(callback).Run({});
582 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900583 }
584
Jie Jiang0a70acf2020-10-02 11:57:32 +0900585 proxy_->CallMethod(
586 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
587 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900588}
589
Jie Jiang81c84db2020-09-29 17:40:16 +0900590bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
591 ModifyPortRuleRequest::RuleType type,
592 ModifyPortRuleRequest::Protocol proto,
593 const std::string& input_ifname,
594 const std::string& input_dst_ip,
595 uint32_t input_dst_port,
596 const std::string& dst_ip,
597 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900598 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
599 dbus::MessageWriter writer(&method_call);
600
601 ModifyPortRuleRequest request;
602 ModifyPortRuleResponse response;
603
604 request.set_op(op);
605 request.set_type(type);
606 request.set_proto(proto);
607 request.set_input_ifname(input_ifname);
608 request.set_input_dst_ip(input_dst_ip);
609 request.set_input_dst_port(input_dst_port);
610 request.set_dst_ip(dst_ip);
611 request.set_dst_port(dst_port);
612
613 if (!writer.AppendProtoAsArrayOfBytes(request)) {
614 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
615 return false;
616 }
617
Woody Chowdee3c8b2020-12-04 20:03:54 +0900618 std::unique_ptr<dbus::Response> dbus_response =
619 brillo::dbus_utils::CallDBusMethod(
620 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900621 if (!dbus_response) {
622 LOG(ERROR)
623 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
624 << request;
625 return false;
626 }
627
628 dbus::MessageReader reader(dbus_response.get());
629 if (!reader.PopArrayOfBytesAsProto(&response)) {
630 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
631 return false;
632 }
633
634 if (!response.success()) {
635 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
636 return false;
637 }
638 return true;
639}
640
Garrick Evans9e637982020-11-30 11:59:27 +0900641std::vector<NetworkDevice> ClientImpl::GetDevices() {
642 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
643 dbus::MessageWriter writer(&method_call);
644
645 GetDevicesRequest request;
646 if (!writer.AppendProtoAsArrayOfBytes(request)) {
647 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
648 return {};
649 }
650
Woody Chowdee3c8b2020-12-04 20:03:54 +0900651 std::unique_ptr<dbus::Response> dbus_response =
652 brillo::dbus_utils::CallDBusMethod(
653 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans9e637982020-11-30 11:59:27 +0900654 if (!dbus_response) {
655 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
656 return {};
657 }
658
659 dbus::MessageReader reader(dbus_response.get());
660 GetDevicesResponse response;
661 if (!reader.PopArrayOfBytesAsProto(&response)) {
662 LOG(ERROR) << "Failed to parse response proto";
663 return {};
664 }
665
666 std::vector<NetworkDevice> devices;
667 for (const auto& d : response.devices()) {
668 devices.emplace_back(d);
669 }
670 return devices;
671}
672
Garrick Evansf04f0442020-12-01 12:36:44 +0900673void ClientImpl::RegisterNetworkDeviceChangedSignalHandler(
674 NetworkDeviceChangedSignalHandler handler) {
675 proxy_->ConnectToSignal(
676 kPatchPanelInterface, kNetworkDeviceChangedSignal,
677 base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
678 base::BindOnce(OnSignalConnectedCallback));
679}
680
Jie Jiang25c1b972020-11-12 15:42:53 +0900681void ClientImpl::RegisterNeighborReachabilityEventHandler(
682 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900683 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900684 kPatchPanelInterface, kNeighborReachabilityEventSignal,
685 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900686 base::BindOnce(OnSignalConnectedCallback));
687}
688
Woody Chowdee3c8b2020-12-04 20:03:54 +0900689dbus::ObjectProxy* GetProxy(const scoped_refptr<dbus::Bus>& bus) {
690 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
691 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
692 if (!proxy) {
693 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
694 }
695 return proxy;
696}
697
Jie Jiang81c84db2020-09-29 17:40:16 +0900698} // namespace
699
700// static
701std::unique_ptr<Client> Client::New() {
702 dbus::Bus::Options opts;
703 opts.bus_type = dbus::Bus::SYSTEM;
704 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
705
706 if (!bus->Connect()) {
707 LOG(ERROR) << "Failed to connect to system bus";
708 return nullptr;
709 }
710
Woody Chowdee3c8b2020-12-04 20:03:54 +0900711 dbus::ObjectProxy* proxy = GetProxy(bus);
712 if (!proxy)
Jie Jiang81c84db2020-09-29 17:40:16 +0900713 return nullptr;
Jie Jiang81c84db2020-09-29 17:40:16 +0900714
Woody Chowdee3c8b2020-12-04 20:03:54 +0900715 return std::make_unique<ClientImpl>(std::move(bus), proxy,
716 true /* owns_bus */);
717}
718
719std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus) {
720 dbus::ObjectProxy* proxy = GetProxy(bus);
721 if (!proxy)
722 return nullptr;
723
724 return std::make_unique<ClientImpl>(std::move(bus), proxy,
725 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900726}
727
728std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
729 dbus::ObjectProxy* proxy) {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900730 return std::make_unique<ClientImpl>(std::move(bus), proxy,
731 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900732}
733
Garrick Evans08843932019-09-17 14:41:08 +0900734} // namespace patchpanel