blob: 521140053f450c7179e12c03bf6bf150afbe367d [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
Garrick Evans9e637982020-11-30 11:59:27 +0900161 std::vector<NetworkDevice> GetDevices() override;
162
Garrick Evansf04f0442020-12-01 12:36:44 +0900163 void RegisterNetworkDeviceChangedSignalHandler(
164 NetworkDeviceChangedSignalHandler handler) override;
165
Jie Jiang25c1b972020-11-12 15:42:53 +0900166 void RegisterNeighborReachabilityEventHandler(
167 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900168
169 private:
170 scoped_refptr<dbus::Bus> bus_;
Woody Chowdee3c8b2020-12-04 20:03:54 +0900171 dbus::ObjectProxy* proxy_ = nullptr; // owned by |bus_|
172 bool owns_bus_; // Yes if |bus_| is created by Client::New
Jie Jiang81c84db2020-09-29 17:40:16 +0900173
Garrick Evans6a062012021-02-15 09:25:44 +0900174 base::RepeatingCallback<void(bool)> owner_callback_;
175
176 void OnOwnerChanged(const std::string& old_owner,
177 const std::string& new_owner);
178
Jie Jiang81c84db2020-09-29 17:40:16 +0900179 bool SendSetVpnIntentRequest(int socket,
180 SetVpnIntentRequest::VpnRoutingPolicy policy);
Garrick Evans6a062012021-02-15 09:25:44 +0900181
182 base::WeakPtrFactory<ClientImpl> weak_factory_{this};
Jie Jiang81c84db2020-09-29 17:40:16 +0900183};
184
185ClientImpl::~ClientImpl() {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900186 if (bus_ && owns_bus_)
Garrick Evans93a83fc2020-03-31 15:16:55 +0900187 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900188}
189
Garrick Evansd0a646e2020-11-25 21:08:32 +0900190void ClientImpl::RegisterOnAvailableCallback(
191 base::RepeatingCallback<void(bool)> callback) {
192 if (!proxy_) {
193 LOG(ERROR) << "Cannot register callback - no proxy";
194 return;
195 }
196 proxy_->WaitForServiceToBeAvailable(callback);
197}
198
Garrick Evans6a062012021-02-15 09:25:44 +0900199void ClientImpl::RegisterProcessChangedCallback(
200 base::RepeatingCallback<void(bool)> callback) {
201 owner_callback_ = callback;
202 bus_->GetObjectProxy(kPatchPanelServiceName, dbus::ObjectPath{"/"})
203 ->SetNameOwnerChangedCallback(
204 base::Bind(&ClientImpl::OnOwnerChanged, weak_factory_.GetWeakPtr()));
205}
206
207void ClientImpl::OnOwnerChanged(const std::string& old_owner,
208 const std::string& new_owner) {
209 if (new_owner.empty()) {
210 LOG(INFO) << "Patchpanel lost";
211 if (!owner_callback_.is_null())
212 owner_callback_.Run(false);
213 return;
214 }
215
216 LOG(INFO) << "Patchpanel reset";
217 if (!owner_callback_.is_null())
218 owner_callback_.Run(true);
219}
220
Jie Jiang81c84db2020-09-29 17:40:16 +0900221bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900222 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
223 dbus::MessageWriter writer(&method_call);
224
225 ArcStartupRequest request;
226 request.set_pid(static_cast<uint32_t>(pid));
227
228 if (!writer.AppendProtoAsArrayOfBytes(request)) {
229 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
230 return false;
231 }
232
Woody Chowdee3c8b2020-12-04 20:03:54 +0900233 std::unique_ptr<dbus::Response> dbus_response =
234 brillo::dbus_utils::CallDBusMethod(
235 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900236 if (!dbus_response) {
237 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
238 return false;
239 }
240
241 dbus::MessageReader reader(dbus_response.get());
242 ArcStartupResponse response;
243 if (!reader.PopArrayOfBytesAsProto(&response)) {
244 LOG(ERROR) << "Failed to parse response proto";
245 return false;
246 }
247
248 return true;
249}
250
Jie Jiang81c84db2020-09-29 17:40:16 +0900251bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900252 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
253 dbus::MessageWriter writer(&method_call);
254
255 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900256 if (!writer.AppendProtoAsArrayOfBytes(request)) {
257 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
258 return false;
259 }
260
Woody Chowdee3c8b2020-12-04 20:03:54 +0900261 std::unique_ptr<dbus::Response> dbus_response =
262 brillo::dbus_utils::CallDBusMethod(
263 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900264 if (!dbus_response) {
265 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
266 return false;
267 }
268
269 dbus::MessageReader reader(dbus_response.get());
270 ArcShutdownResponse response;
271 if (!reader.PopArrayOfBytesAsProto(&response)) {
272 LOG(ERROR) << "Failed to parse response proto";
273 return false;
274 }
275
276 return true;
277}
278
Jie Jiang81c84db2020-09-29 17:40:16 +0900279std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900280 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
281 dbus::MessageWriter writer(&method_call);
282
283 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900284 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900285
286 if (!writer.AppendProtoAsArrayOfBytes(request)) {
287 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
288 return {};
289 }
290
Woody Chowdee3c8b2020-12-04 20:03:54 +0900291 std::unique_ptr<dbus::Response> dbus_response =
292 brillo::dbus_utils::CallDBusMethod(
293 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900294 if (!dbus_response) {
295 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
296 return {};
297 }
298
299 dbus::MessageReader reader(dbus_response.get());
300 ArcVmStartupResponse response;
301 if (!reader.PopArrayOfBytesAsProto(&response)) {
302 LOG(ERROR) << "Failed to parse response proto";
303 return {};
304 }
305
Garrick Evans3388a032020-03-24 11:25:55 +0900306 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900307 for (const auto& d : response.devices()) {
308 devices.emplace_back(d);
309 }
310 return devices;
311}
312
Jie Jiang81c84db2020-09-29 17:40:16 +0900313bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900314 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
315 dbus::MessageWriter writer(&method_call);
316
317 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900318 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900319
320 if (!writer.AppendProtoAsArrayOfBytes(request)) {
321 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
322 return false;
323 }
324
Woody Chowdee3c8b2020-12-04 20:03:54 +0900325 std::unique_ptr<dbus::Response> dbus_response =
326 brillo::dbus_utils::CallDBusMethod(
327 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans08843932019-09-17 14:41:08 +0900328 if (!dbus_response) {
329 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
330 return false;
331 }
332
333 dbus::MessageReader reader(dbus_response.get());
334 ArcVmShutdownResponse response;
335 if (!reader.PopArrayOfBytesAsProto(&response)) {
336 LOG(ERROR) << "Failed to parse response proto";
337 return false;
338 }
339
340 return true;
341}
342
Jie Jiang81c84db2020-09-29 17:40:16 +0900343bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
344 NetworkDevice* device,
345 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900346 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
347 dbus::MessageWriter writer(&method_call);
348
349 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900350 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900351
352 if (!writer.AppendProtoAsArrayOfBytes(request)) {
353 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
354 return false;
355 }
356
Woody Chowdee3c8b2020-12-04 20:03:54 +0900357 std::unique_ptr<dbus::Response> dbus_response =
358 brillo::dbus_utils::CallDBusMethod(
359 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans27b74032019-11-19 13:33:47 +0900360 if (!dbus_response) {
361 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
362 return false;
363 }
364
365 dbus::MessageReader reader(dbus_response.get());
366 TerminaVmStartupResponse response;
367 if (!reader.PopArrayOfBytesAsProto(&response)) {
368 LOG(ERROR) << "Failed to parse response proto";
369 return false;
370 }
371
372 if (!response.has_device()) {
373 LOG(ERROR) << "No device found";
374 return false;
375 }
376 *device = response.device();
377
378 if (response.has_container_subnet()) {
379 *container_subnet = response.container_subnet();
380 } else {
381 LOG(WARNING) << "No container subnet found";
382 }
383
384 return true;
385}
386
Jie Jiang81c84db2020-09-29 17:40:16 +0900387bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900388 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
389 dbus::MessageWriter writer(&method_call);
390
391 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900392 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900393
394 if (!writer.AppendProtoAsArrayOfBytes(request)) {
395 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest 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 Evans27b74032019-11-19 13:33:47 +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 TerminaVmShutdownResponse response;
409 if (!reader.PopArrayOfBytesAsProto(&response)) {
410 LOG(ERROR) << "Failed to parse response proto";
411 return false;
412 }
413
414 return true;
415}
416
Jie Jiang81c84db2020-09-29 17:40:16 +0900417bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
418 int subnet_index,
419 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900420 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
421 dbus::MessageWriter writer(&method_call);
422
423 PluginVmStartupRequest request;
424 request.set_id(vm_id);
425 request.set_subnet_index(subnet_index);
426
427 if (!writer.AppendProtoAsArrayOfBytes(request)) {
428 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
429 return false;
430 }
431
Woody Chowdee3c8b2020-12-04 20:03:54 +0900432 std::unique_ptr<dbus::Response> dbus_response =
433 brillo::dbus_utils::CallDBusMethod(
434 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900435 if (!dbus_response) {
436 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
437 return false;
438 }
439
440 dbus::MessageReader reader(dbus_response.get());
441 PluginVmStartupResponse response;
442 if (!reader.PopArrayOfBytesAsProto(&response)) {
443 LOG(ERROR) << "Failed to parse response proto";
444 return false;
445 }
446
447 if (!response.has_device()) {
448 LOG(ERROR) << "No device found";
449 return false;
450 }
451 *device = response.device();
452
453 return true;
454}
455
Jie Jiang81c84db2020-09-29 17:40:16 +0900456bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900457 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
458 dbus::MessageWriter writer(&method_call);
459
460 PluginVmShutdownRequest request;
461 request.set_id(vm_id);
462
463 if (!writer.AppendProtoAsArrayOfBytes(request)) {
464 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
465 return false;
466 }
467
Woody Chowdee3c8b2020-12-04 20:03:54 +0900468 std::unique_ptr<dbus::Response> dbus_response =
469 brillo::dbus_utils::CallDBusMethod(
470 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans376f0672020-01-07 15:31:50 +0900471 if (!dbus_response) {
472 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
473 return false;
474 }
475
476 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900477 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900478 if (!reader.PopArrayOfBytesAsProto(&response)) {
479 LOG(ERROR) << "Failed to parse response proto";
480 return false;
481 }
482
483 return true;
484}
485
Jie Jiang81c84db2020-09-29 17:40:16 +0900486bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900487 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
488}
489
Jie Jiang81c84db2020-09-29 17:40:16 +0900490bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900491 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
492}
493
Jie Jiang81c84db2020-09-29 17:40:16 +0900494bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900495 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
496}
497
Jie Jiang81c84db2020-09-29 17:40:16 +0900498bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900499 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
500 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
501 dbus::MessageWriter writer(&method_call);
502
503 SetVpnIntentRequest request;
504 SetVpnIntentResponse response;
505 request.set_policy(policy);
506
507 if (!writer.AppendProtoAsArrayOfBytes(request)) {
508 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
509 return false;
510 }
511 writer.AppendFileDescriptor(socket);
512
Woody Chowdee3c8b2020-12-04 20:03:54 +0900513 std::unique_ptr<dbus::Response> dbus_response =
514 brillo::dbus_utils::CallDBusMethod(
515 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900516 if (!dbus_response) {
517 LOG(ERROR)
518 << "Failed to send SetVpnIntentRequest message to patchpanel service";
519 return false;
520 }
521
522 dbus::MessageReader reader(dbus_response.get());
523 if (!reader.PopArrayOfBytesAsProto(&response)) {
524 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
525 return false;
526 }
527
528 if (!response.success()) {
529 LOG(ERROR) << "SetVpnIntentRequest failed";
530 return false;
531 }
532 return true;
533}
534
Hugo Benichicc6850f2020-01-17 13:26:06 +0900535std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900536ClientImpl::ConnectNamespace(pid_t pid,
537 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900538 bool forward_user_traffic,
539 bool route_on_vpn,
540 TrafficCounter::Source traffic_source) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900541 // Prepare and serialize the request proto.
542 ConnectNamespaceRequest request;
543 request.set_pid(static_cast<int32_t>(pid));
544 request.set_outbound_physical_device(outbound_ifname);
545 request.set_allow_user_traffic(forward_user_traffic);
Garrick Evans58697022020-12-03 12:41:13 +0900546 request.set_route_on_vpn(route_on_vpn);
547 request.set_traffic_source(traffic_source);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900548
549 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
550 dbus::MessageWriter writer(&method_call);
551 if (!writer.AppendProtoAsArrayOfBytes(request)) {
552 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
553 return {};
554 }
555
556 // Prepare an fd pair and append one fd directly after the serialized request.
557 int pipe_fds[2] = {-1, -1};
558 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
559 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
560 return {};
561 }
562 base::ScopedFD fd_local(pipe_fds[0]);
563 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
564 // make sure the original fd is closed eventually.
565 base::ScopedFD fd_remote(pipe_fds[1]);
566 writer.AppendFileDescriptor(pipe_fds[1]);
567
Woody Chowdee3c8b2020-12-04 20:03:54 +0900568 std::unique_ptr<dbus::Response> dbus_response =
569 brillo::dbus_utils::CallDBusMethod(
570 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900571 if (!dbus_response) {
572 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
573 return {};
574 }
575
576 dbus::MessageReader reader(dbus_response.get());
577 ConnectNamespaceResponse response;
578 if (!reader.PopArrayOfBytesAsProto(&response)) {
579 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
580 return {};
581 }
582
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900583 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900584 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
585 return {};
586 }
587
Garrick Evans3388a032020-03-24 11:25:55 +0900588 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900589 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
590 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900591 << " succeeded: peer_ifname=" << response.peer_ifname()
592 << " peer_ipv4_address="
593 << IPv4AddressToString(response.peer_ipv4_address())
594 << " host_ifname=" << response.host_ifname()
595 << " host_ipv4_address="
596 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900597 << " subnet=" << subnet_info;
598
599 return std::make_pair(std::move(fd_local), std::move(response));
600}
601
Jie Jiang81c84db2020-09-29 17:40:16 +0900602void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
603 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900604 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
605 dbus::MessageWriter writer(&method_call);
606
607 TrafficCountersRequest request;
608 for (const auto& device : devices) {
609 request.add_devices(device);
610 }
611
612 if (!writer.AppendProtoAsArrayOfBytes(request)) {
613 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900614 std::move(callback).Run({});
615 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900616 }
617
Jie Jiang0a70acf2020-10-02 11:57:32 +0900618 proxy_->CallMethod(
619 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
620 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900621}
622
Jie Jiang81c84db2020-09-29 17:40:16 +0900623bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
624 ModifyPortRuleRequest::RuleType type,
625 ModifyPortRuleRequest::Protocol proto,
626 const std::string& input_ifname,
627 const std::string& input_dst_ip,
628 uint32_t input_dst_port,
629 const std::string& dst_ip,
630 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900631 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
632 dbus::MessageWriter writer(&method_call);
633
634 ModifyPortRuleRequest request;
635 ModifyPortRuleResponse response;
636
637 request.set_op(op);
638 request.set_type(type);
639 request.set_proto(proto);
640 request.set_input_ifname(input_ifname);
641 request.set_input_dst_ip(input_dst_ip);
642 request.set_input_dst_port(input_dst_port);
643 request.set_dst_ip(dst_ip);
644 request.set_dst_port(dst_port);
645
646 if (!writer.AppendProtoAsArrayOfBytes(request)) {
647 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
648 return false;
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);
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900654 if (!dbus_response) {
655 LOG(ERROR)
656 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
657 << request;
658 return false;
659 }
660
661 dbus::MessageReader reader(dbus_response.get());
662 if (!reader.PopArrayOfBytesAsProto(&response)) {
663 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
664 return false;
665 }
666
667 if (!response.success()) {
668 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
669 return false;
670 }
671 return true;
672}
673
Garrick Evans9e637982020-11-30 11:59:27 +0900674std::vector<NetworkDevice> ClientImpl::GetDevices() {
675 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
676 dbus::MessageWriter writer(&method_call);
677
678 GetDevicesRequest request;
679 if (!writer.AppendProtoAsArrayOfBytes(request)) {
680 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
681 return {};
682 }
683
Woody Chowdee3c8b2020-12-04 20:03:54 +0900684 std::unique_ptr<dbus::Response> dbus_response =
685 brillo::dbus_utils::CallDBusMethod(
686 bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
Garrick Evans9e637982020-11-30 11:59:27 +0900687 if (!dbus_response) {
688 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
689 return {};
690 }
691
692 dbus::MessageReader reader(dbus_response.get());
693 GetDevicesResponse response;
694 if (!reader.PopArrayOfBytesAsProto(&response)) {
695 LOG(ERROR) << "Failed to parse response proto";
696 return {};
697 }
698
699 std::vector<NetworkDevice> devices;
700 for (const auto& d : response.devices()) {
701 devices.emplace_back(d);
702 }
703 return devices;
704}
705
Garrick Evansf04f0442020-12-01 12:36:44 +0900706void ClientImpl::RegisterNetworkDeviceChangedSignalHandler(
707 NetworkDeviceChangedSignalHandler handler) {
708 proxy_->ConnectToSignal(
709 kPatchPanelInterface, kNetworkDeviceChangedSignal,
710 base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
711 base::BindOnce(OnSignalConnectedCallback));
712}
713
Jie Jiang25c1b972020-11-12 15:42:53 +0900714void ClientImpl::RegisterNeighborReachabilityEventHandler(
715 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900716 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900717 kPatchPanelInterface, kNeighborReachabilityEventSignal,
718 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900719 base::BindOnce(OnSignalConnectedCallback));
720}
721
Woody Chowdee3c8b2020-12-04 20:03:54 +0900722dbus::ObjectProxy* GetProxy(const scoped_refptr<dbus::Bus>& bus) {
723 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
724 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
725 if (!proxy) {
726 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
727 }
728 return proxy;
729}
730
Jie Jiang81c84db2020-09-29 17:40:16 +0900731} // namespace
732
733// static
734std::unique_ptr<Client> Client::New() {
735 dbus::Bus::Options opts;
736 opts.bus_type = dbus::Bus::SYSTEM;
737 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
738
739 if (!bus->Connect()) {
740 LOG(ERROR) << "Failed to connect to system bus";
741 return nullptr;
742 }
743
Woody Chowdee3c8b2020-12-04 20:03:54 +0900744 dbus::ObjectProxy* proxy = GetProxy(bus);
745 if (!proxy)
Jie Jiang81c84db2020-09-29 17:40:16 +0900746 return nullptr;
Jie Jiang81c84db2020-09-29 17:40:16 +0900747
Woody Chowdee3c8b2020-12-04 20:03:54 +0900748 return std::make_unique<ClientImpl>(std::move(bus), proxy,
749 true /* owns_bus */);
750}
751
752std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus) {
753 dbus::ObjectProxy* proxy = GetProxy(bus);
754 if (!proxy)
755 return nullptr;
756
757 return std::make_unique<ClientImpl>(std::move(bus), proxy,
758 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900759}
760
761std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
762 dbus::ObjectProxy* proxy) {
Woody Chowdee3c8b2020-12-04 20:03:54 +0900763 return std::make_unique<ClientImpl>(std::move(bus), proxy,
764 false /* owns_bus */);
Jie Jiang81c84db2020-09-29 17:40:16 +0900765}
766
Garrick Evans08843932019-09-17 14:41:08 +0900767} // namespace patchpanel