blob: 102a44b9425b7bf74115cf4ccc078563b1ee4fd2 [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>
11#include <chromeos/dbus/service_constants.h>
12#include <dbus/message.h>
13#include <dbus/object_path.h>
14
Garrick Evans3388a032020-03-24 11:25:55 +090015#include "patchpanel/net_util.h"
Hugo Benichicc6850f2020-01-17 13:26:06 +090016
Garrick Evans08843932019-09-17 14:41:08 +090017namespace patchpanel {
18
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090019namespace {
20
21std::ostream& operator<<(std::ostream& stream,
22 const ModifyPortRuleRequest& request) {
23 stream << "{ operation: "
24 << ModifyPortRuleRequest::Operation_Name(request.op())
25 << ", rule type: "
26 << ModifyPortRuleRequest::RuleType_Name(request.type())
27 << ", protocol: "
28 << ModifyPortRuleRequest::Protocol_Name(request.proto());
29 if (!request.input_ifname().empty()) {
30 stream << ", input interface name: " << request.input_ifname();
31 }
32 if (!request.input_dst_ip().empty()) {
33 stream << ", input destination IP: " << request.input_dst_ip();
34 }
35 stream << ", input destination port: " << request.input_dst_port();
36 if (!request.dst_ip().empty()) {
37 stream << ", destination IP: " << request.dst_ip();
38 }
39 if (request.dst_port() != 0) {
40 stream << ", destination port: " << request.dst_port();
41 }
42 stream << " }";
43 return stream;
44}
45
Jie Jiang0a70acf2020-10-02 11:57:32 +090046void OnGetTrafficCountersDBusResponse(
47 Client::GetTrafficCountersCallback callback,
48 dbus::Response* dbus_response) {
49 if (!dbus_response) {
50 LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
51 "service";
52 std::move(callback).Run({});
53 return;
54 }
55
56 TrafficCountersResponse response;
57 dbus::MessageReader reader(dbus_response);
58 if (!reader.PopArrayOfBytesAsProto(&response)) {
59 LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
60 std::move(callback).Run({});
61 return;
62 }
63
64 std::move(callback).Run(
65 {response.counters().begin(), response.counters().end()});
66}
67
Garrick Evansf04f0442020-12-01 12:36:44 +090068void OnNetworkDeviceChangedSignal(
69 const Client::NetworkDeviceChangedSignalHandler& handler,
70 dbus::Signal* signal) {
71 dbus::MessageReader reader(signal);
72 NetworkDeviceChangedSignal proto;
73 if (!reader.PopArrayOfBytesAsProto(&proto)) {
74 LOG(ERROR) << "Failed to parse NetworkDeviceChangedSignal proto";
75 return;
76 }
77
78 handler.Run(proto);
79}
80
Jie Jiang25c1b972020-11-12 15:42:53 +090081void OnNeighborReachabilityEventSignal(
82 const Client::NeighborReachabilityEventHandler& handler,
Jie Jiange2e4c0b2020-09-16 18:48:43 +090083 dbus::Signal* signal) {
84 dbus::MessageReader reader(signal);
Jie Jiang25c1b972020-11-12 15:42:53 +090085 NeighborReachabilityEventSignal proto;
Jie Jiange2e4c0b2020-09-16 18:48:43 +090086 if (!reader.PopArrayOfBytesAsProto(&proto)) {
87 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
88 return;
89 }
90
91 handler.Run(proto);
92}
93
94void OnSignalConnectedCallback(const std::string& interface_name,
95 const std::string& signal_name,
96 bool success) {
97 if (!success)
98 LOG(ERROR) << "Failed to connect to " << signal_name;
99}
100
Jie Jiang81c84db2020-09-29 17:40:16 +0900101class ClientImpl : public Client {
102 public:
103 ClientImpl(const scoped_refptr<dbus::Bus>& bus, dbus::ObjectProxy* proxy)
104 : bus_(std::move(bus)), proxy_(proxy) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900105 ClientImpl(const ClientImpl&) = delete;
106 ClientImpl& operator=(const ClientImpl&) = delete;
107
Jie Jiang81c84db2020-09-29 17:40:16 +0900108 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900109
Jie Jiang81c84db2020-09-29 17:40:16 +0900110 bool NotifyArcStartup(pid_t pid) override;
111 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +0900112
Jie Jiang81c84db2020-09-29 17:40:16 +0900113 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
114 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900115
Jie Jiang81c84db2020-09-29 17:40:16 +0900116 bool NotifyTerminaVmStartup(uint32_t cid,
117 NetworkDevice* device,
118 IPv4Subnet* container_subnet) override;
119 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900120
Jie Jiang81c84db2020-09-29 17:40:16 +0900121 bool NotifyPluginVmStartup(uint64_t vm_id,
122 int subnet_index,
123 NetworkDevice* device) override;
124 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900125
Jie Jiang81c84db2020-09-29 17:40:16 +0900126 bool DefaultVpnRouting(int socket) override;
127
128 bool RouteOnVpn(int socket) override;
129
130 bool BypassVpn(int socket) override;
131
132 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
133 ConnectNamespace(pid_t pid,
134 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900135 bool forward_user_traffic,
136 bool route_on_vpn,
137 TrafficCounter::Source traffic_source) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900138
139 void GetTrafficCounters(const std::set<std::string>& devices,
140 GetTrafficCountersCallback callback) override;
141
142 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
143 patchpanel::ModifyPortRuleRequest::RuleType type,
144 patchpanel::ModifyPortRuleRequest::Protocol proto,
145 const std::string& input_ifname,
146 const std::string& input_dst_ip,
147 uint32_t input_dst_port,
148 const std::string& dst_ip,
149 uint32_t dst_port) override;
150
Garrick Evans9e637982020-11-30 11:59:27 +0900151 std::vector<NetworkDevice> GetDevices() override;
152
Garrick Evansf04f0442020-12-01 12:36:44 +0900153 void RegisterNetworkDeviceChangedSignalHandler(
154 NetworkDeviceChangedSignalHandler handler) override;
155
Jie Jiang25c1b972020-11-12 15:42:53 +0900156 void RegisterNeighborReachabilityEventHandler(
157 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900158
159 private:
160 scoped_refptr<dbus::Bus> bus_;
161 dbus::ObjectProxy* proxy_ = nullptr; // owned by bus_
162
163 bool SendSetVpnIntentRequest(int socket,
164 SetVpnIntentRequest::VpnRoutingPolicy policy);
Jie Jiang81c84db2020-09-29 17:40:16 +0900165};
166
167ClientImpl::~ClientImpl() {
Garrick Evans93a83fc2020-03-31 15:16:55 +0900168 if (bus_)
169 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900170}
171
Jie Jiang81c84db2020-09-29 17:40:16 +0900172bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900173 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
174 dbus::MessageWriter writer(&method_call);
175
176 ArcStartupRequest request;
177 request.set_pid(static_cast<uint32_t>(pid));
178
179 if (!writer.AppendProtoAsArrayOfBytes(request)) {
180 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
181 return false;
182 }
183
184 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
185 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
186 if (!dbus_response) {
187 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
188 return false;
189 }
190
191 dbus::MessageReader reader(dbus_response.get());
192 ArcStartupResponse response;
193 if (!reader.PopArrayOfBytesAsProto(&response)) {
194 LOG(ERROR) << "Failed to parse response proto";
195 return false;
196 }
197
198 return true;
199}
200
Jie Jiang81c84db2020-09-29 17:40:16 +0900201bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900202 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
203 dbus::MessageWriter writer(&method_call);
204
205 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900206 if (!writer.AppendProtoAsArrayOfBytes(request)) {
207 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
208 return false;
209 }
210
211 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
212 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
213 if (!dbus_response) {
214 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
215 return false;
216 }
217
218 dbus::MessageReader reader(dbus_response.get());
219 ArcShutdownResponse response;
220 if (!reader.PopArrayOfBytesAsProto(&response)) {
221 LOG(ERROR) << "Failed to parse response proto";
222 return false;
223 }
224
225 return true;
226}
227
Jie Jiang81c84db2020-09-29 17:40:16 +0900228std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900229 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
230 dbus::MessageWriter writer(&method_call);
231
232 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900233 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900234
235 if (!writer.AppendProtoAsArrayOfBytes(request)) {
236 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
237 return {};
238 }
239
240 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
241 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
242 if (!dbus_response) {
243 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
244 return {};
245 }
246
247 dbus::MessageReader reader(dbus_response.get());
248 ArcVmStartupResponse response;
249 if (!reader.PopArrayOfBytesAsProto(&response)) {
250 LOG(ERROR) << "Failed to parse response proto";
251 return {};
252 }
253
Garrick Evans3388a032020-03-24 11:25:55 +0900254 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900255 for (const auto& d : response.devices()) {
256 devices.emplace_back(d);
257 }
258 return devices;
259}
260
Jie Jiang81c84db2020-09-29 17:40:16 +0900261bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900262 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
263 dbus::MessageWriter writer(&method_call);
264
265 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900266 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900267
268 if (!writer.AppendProtoAsArrayOfBytes(request)) {
269 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
270 return false;
271 }
272
273 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
274 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
275 if (!dbus_response) {
276 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
277 return false;
278 }
279
280 dbus::MessageReader reader(dbus_response.get());
281 ArcVmShutdownResponse response;
282 if (!reader.PopArrayOfBytesAsProto(&response)) {
283 LOG(ERROR) << "Failed to parse response proto";
284 return false;
285 }
286
287 return true;
288}
289
Jie Jiang81c84db2020-09-29 17:40:16 +0900290bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
291 NetworkDevice* device,
292 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900293 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
294 dbus::MessageWriter writer(&method_call);
295
296 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900297 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900298
299 if (!writer.AppendProtoAsArrayOfBytes(request)) {
300 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
301 return false;
302 }
303
304 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
305 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
306 if (!dbus_response) {
307 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
308 return false;
309 }
310
311 dbus::MessageReader reader(dbus_response.get());
312 TerminaVmStartupResponse response;
313 if (!reader.PopArrayOfBytesAsProto(&response)) {
314 LOG(ERROR) << "Failed to parse response proto";
315 return false;
316 }
317
318 if (!response.has_device()) {
319 LOG(ERROR) << "No device found";
320 return false;
321 }
322 *device = response.device();
323
324 if (response.has_container_subnet()) {
325 *container_subnet = response.container_subnet();
326 } else {
327 LOG(WARNING) << "No container subnet found";
328 }
329
330 return true;
331}
332
Jie Jiang81c84db2020-09-29 17:40:16 +0900333bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900334 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
335 dbus::MessageWriter writer(&method_call);
336
337 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900338 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900339
340 if (!writer.AppendProtoAsArrayOfBytes(request)) {
341 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
342 return false;
343 }
344
345 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
346 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
347 if (!dbus_response) {
348 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
349 return false;
350 }
351
352 dbus::MessageReader reader(dbus_response.get());
353 TerminaVmShutdownResponse response;
354 if (!reader.PopArrayOfBytesAsProto(&response)) {
355 LOG(ERROR) << "Failed to parse response proto";
356 return false;
357 }
358
359 return true;
360}
361
Jie Jiang81c84db2020-09-29 17:40:16 +0900362bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
363 int subnet_index,
364 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900365 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
366 dbus::MessageWriter writer(&method_call);
367
368 PluginVmStartupRequest request;
369 request.set_id(vm_id);
370 request.set_subnet_index(subnet_index);
371
372 if (!writer.AppendProtoAsArrayOfBytes(request)) {
373 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
374 return false;
375 }
376
377 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
378 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
379 if (!dbus_response) {
380 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
381 return false;
382 }
383
384 dbus::MessageReader reader(dbus_response.get());
385 PluginVmStartupResponse response;
386 if (!reader.PopArrayOfBytesAsProto(&response)) {
387 LOG(ERROR) << "Failed to parse response proto";
388 return false;
389 }
390
391 if (!response.has_device()) {
392 LOG(ERROR) << "No device found";
393 return false;
394 }
395 *device = response.device();
396
397 return true;
398}
399
Jie Jiang81c84db2020-09-29 17:40:16 +0900400bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900401 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
402 dbus::MessageWriter writer(&method_call);
403
404 PluginVmShutdownRequest request;
405 request.set_id(vm_id);
406
407 if (!writer.AppendProtoAsArrayOfBytes(request)) {
408 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
409 return false;
410 }
411
412 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
413 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
414 if (!dbus_response) {
415 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
416 return false;
417 }
418
419 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900420 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900421 if (!reader.PopArrayOfBytesAsProto(&response)) {
422 LOG(ERROR) << "Failed to parse response proto";
423 return false;
424 }
425
426 return true;
427}
428
Jie Jiang81c84db2020-09-29 17:40:16 +0900429bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900430 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
431}
432
Jie Jiang81c84db2020-09-29 17:40:16 +0900433bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900434 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
435}
436
Jie Jiang81c84db2020-09-29 17:40:16 +0900437bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900438 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
439}
440
Jie Jiang81c84db2020-09-29 17:40:16 +0900441bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900442 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
443 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
444 dbus::MessageWriter writer(&method_call);
445
446 SetVpnIntentRequest request;
447 SetVpnIntentResponse response;
448 request.set_policy(policy);
449
450 if (!writer.AppendProtoAsArrayOfBytes(request)) {
451 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
452 return false;
453 }
454 writer.AppendFileDescriptor(socket);
455
456 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
457 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
458 if (!dbus_response) {
459 LOG(ERROR)
460 << "Failed to send SetVpnIntentRequest message to patchpanel service";
461 return false;
462 }
463
464 dbus::MessageReader reader(dbus_response.get());
465 if (!reader.PopArrayOfBytesAsProto(&response)) {
466 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
467 return false;
468 }
469
470 if (!response.success()) {
471 LOG(ERROR) << "SetVpnIntentRequest failed";
472 return false;
473 }
474 return true;
475}
476
Hugo Benichicc6850f2020-01-17 13:26:06 +0900477std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900478ClientImpl::ConnectNamespace(pid_t pid,
479 const std::string& outbound_ifname,
Garrick Evans58697022020-12-03 12:41:13 +0900480 bool forward_user_traffic,
481 bool route_on_vpn,
482 TrafficCounter::Source traffic_source) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900483 // Prepare and serialize the request proto.
484 ConnectNamespaceRequest request;
485 request.set_pid(static_cast<int32_t>(pid));
486 request.set_outbound_physical_device(outbound_ifname);
487 request.set_allow_user_traffic(forward_user_traffic);
Garrick Evans58697022020-12-03 12:41:13 +0900488 request.set_route_on_vpn(route_on_vpn);
489 request.set_traffic_source(traffic_source);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900490
491 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
492 dbus::MessageWriter writer(&method_call);
493 if (!writer.AppendProtoAsArrayOfBytes(request)) {
494 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
495 return {};
496 }
497
498 // Prepare an fd pair and append one fd directly after the serialized request.
499 int pipe_fds[2] = {-1, -1};
500 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
501 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
502 return {};
503 }
504 base::ScopedFD fd_local(pipe_fds[0]);
505 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
506 // make sure the original fd is closed eventually.
507 base::ScopedFD fd_remote(pipe_fds[1]);
508 writer.AppendFileDescriptor(pipe_fds[1]);
509
510 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
511 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
512 if (!dbus_response) {
513 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
514 return {};
515 }
516
517 dbus::MessageReader reader(dbus_response.get());
518 ConnectNamespaceResponse response;
519 if (!reader.PopArrayOfBytesAsProto(&response)) {
520 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
521 return {};
522 }
523
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900524 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900525 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
526 return {};
527 }
528
Garrick Evans3388a032020-03-24 11:25:55 +0900529 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900530 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
531 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900532 << " succeeded: peer_ifname=" << response.peer_ifname()
533 << " peer_ipv4_address="
534 << IPv4AddressToString(response.peer_ipv4_address())
535 << " host_ifname=" << response.host_ifname()
536 << " host_ipv4_address="
537 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900538 << " subnet=" << subnet_info;
539
540 return std::make_pair(std::move(fd_local), std::move(response));
541}
542
Jie Jiang81c84db2020-09-29 17:40:16 +0900543void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
544 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900545 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
546 dbus::MessageWriter writer(&method_call);
547
548 TrafficCountersRequest request;
549 for (const auto& device : devices) {
550 request.add_devices(device);
551 }
552
553 if (!writer.AppendProtoAsArrayOfBytes(request)) {
554 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900555 std::move(callback).Run({});
556 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900557 }
558
Jie Jiang0a70acf2020-10-02 11:57:32 +0900559 proxy_->CallMethod(
560 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
561 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900562}
563
Jie Jiang81c84db2020-09-29 17:40:16 +0900564bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
565 ModifyPortRuleRequest::RuleType type,
566 ModifyPortRuleRequest::Protocol proto,
567 const std::string& input_ifname,
568 const std::string& input_dst_ip,
569 uint32_t input_dst_port,
570 const std::string& dst_ip,
571 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900572 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
573 dbus::MessageWriter writer(&method_call);
574
575 ModifyPortRuleRequest request;
576 ModifyPortRuleResponse response;
577
578 request.set_op(op);
579 request.set_type(type);
580 request.set_proto(proto);
581 request.set_input_ifname(input_ifname);
582 request.set_input_dst_ip(input_dst_ip);
583 request.set_input_dst_port(input_dst_port);
584 request.set_dst_ip(dst_ip);
585 request.set_dst_port(dst_port);
586
587 if (!writer.AppendProtoAsArrayOfBytes(request)) {
588 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
589 return false;
590 }
591
592 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
593 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
594 if (!dbus_response) {
595 LOG(ERROR)
596 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
597 << request;
598 return false;
599 }
600
601 dbus::MessageReader reader(dbus_response.get());
602 if (!reader.PopArrayOfBytesAsProto(&response)) {
603 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
604 return false;
605 }
606
607 if (!response.success()) {
608 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
609 return false;
610 }
611 return true;
612}
613
Garrick Evans9e637982020-11-30 11:59:27 +0900614std::vector<NetworkDevice> ClientImpl::GetDevices() {
615 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
616 dbus::MessageWriter writer(&method_call);
617
618 GetDevicesRequest request;
619 if (!writer.AppendProtoAsArrayOfBytes(request)) {
620 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
621 return {};
622 }
623
624 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
625 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
626 if (!dbus_response) {
627 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
628 return {};
629 }
630
631 dbus::MessageReader reader(dbus_response.get());
632 GetDevicesResponse response;
633 if (!reader.PopArrayOfBytesAsProto(&response)) {
634 LOG(ERROR) << "Failed to parse response proto";
635 return {};
636 }
637
638 std::vector<NetworkDevice> devices;
639 for (const auto& d : response.devices()) {
640 devices.emplace_back(d);
641 }
642 return devices;
643}
644
Garrick Evansf04f0442020-12-01 12:36:44 +0900645void ClientImpl::RegisterNetworkDeviceChangedSignalHandler(
646 NetworkDeviceChangedSignalHandler handler) {
647 proxy_->ConnectToSignal(
648 kPatchPanelInterface, kNetworkDeviceChangedSignal,
649 base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
650 base::BindOnce(OnSignalConnectedCallback));
651}
652
Jie Jiang25c1b972020-11-12 15:42:53 +0900653void ClientImpl::RegisterNeighborReachabilityEventHandler(
654 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900655 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900656 kPatchPanelInterface, kNeighborReachabilityEventSignal,
657 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900658 base::BindOnce(OnSignalConnectedCallback));
659}
660
Jie Jiang81c84db2020-09-29 17:40:16 +0900661} // namespace
662
663// static
664std::unique_ptr<Client> Client::New() {
665 dbus::Bus::Options opts;
666 opts.bus_type = dbus::Bus::SYSTEM;
667 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
668
669 if (!bus->Connect()) {
670 LOG(ERROR) << "Failed to connect to system bus";
671 return nullptr;
672 }
673
674 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
675 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
676 if (!proxy) {
677 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
678 return nullptr;
679 }
680
681 return std::make_unique<ClientImpl>(std::move(bus), proxy);
682}
683
684std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
685 dbus::ObjectProxy* proxy) {
686 return std::make_unique<ClientImpl>(std::move(bus), proxy);
687}
688
Garrick Evans08843932019-09-17 14:41:08 +0900689} // namespace patchpanel