blob: d9f2fda0db2f21f88168181f1124d844cbc728d8 [file] [log] [blame]
Peter Qiu1810c012015-02-05 14:35:41 -08001// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "apmanager/firewall_manager.h"
6
7#include <base/bind.h>
8#include <chromeos/dbus/service_constants.h>
9#include <chromeos/errors/error.h>
10
11using std::string;
12
13namespace apmanager {
14
15namespace {
16
17const uint16_t kDhcpServerPort = 67;
18const int kInvalidFd = -1;
19
20} // namespace
21
22FirewallManager::FirewallManager()
23 : lifeline_read_fd_(kInvalidFd),
24 lifeline_write_fd_(kInvalidFd) {}
25
26FirewallManager::~FirewallManager() {
27 if (lifeline_read_fd_ != kInvalidFd) {
28 close(lifeline_read_fd_);
29 close(lifeline_write_fd_);
30 }
31}
32
33void FirewallManager::Start(const scoped_refptr<dbus::Bus>& bus) {
34 CHECK(!permission_broker_proxy_) << "Already started";
35
36 if (!SetupLifelinePipe()) {
37 return;
38 }
39
40 permission_broker_proxy_.reset(
41 new org::chromium::PermissionBrokerProxy(
42 bus,
43 permission_broker::kPermissionBrokerServiceName));
44
45 // This will connect the name owner changed signal in DBus object proxy,
46 // The callback will be invoked as soon as service is avalilable. and will
47 // be cleared after it is invoked. So this will be an one time callback.
48 permission_broker_proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
49 base::Bind(&FirewallManager::OnServiceAvailable, base::Unretained(this)));
50
51 // This will continuously monitor the name owner of the service. However,
52 // it does not connect the name owner changed signal in DBus object proxy
53 // for some reason. In order to connect the name owner changed signal,
54 // either WaitForServiceToBeAvaiable or ConnectToSignal need to be invoked.
55 // Since we're not interested in any signals from the proxy,
56 // WaitForServiceToBeAvailable is used.
57 permission_broker_proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
58 base::Bind(&FirewallManager::OnServiceNameChanged,
59 base::Unretained(this)));
60}
61
62bool FirewallManager::SetupLifelinePipe() {
63 if (lifeline_read_fd_ != kInvalidFd) {
64 LOG(ERROR) << "Lifeline pipe already created";
65 return false;
66 }
67
68 // Setup lifeline pipe.
69 int fds[2];
70 if (pipe(fds) != 0) {
71 PLOG(ERROR) << "Failed to create lifeline pipe";
72 return false;
73 }
74 lifeline_read_fd_ = fds[0];
75 lifeline_write_fd_ = fds[1];
76
77 return true;
78}
79
80void FirewallManager::OnServiceAvailable(bool service_available) {
81 LOG(INFO) << "FirewallManager::OnServiceAvailabe " << service_available;
82 // Nothing to be done if proxy service is not available.
83 if (!service_available) {
84 return;
85 }
86 AddFirewallRules();
87}
88
89void FirewallManager::OnServiceNameChanged(const string& old_owner,
90 const string& new_owner) {
91 LOG(INFO) << "FirewallManager::OnServiceNameChanged old " << old_owner
92 << " new " << new_owner;
93 // Nothing to be done if no owner is attached to the proxy service.
94 if (new_owner.empty()) {
95 return;
96 }
97 AddFirewallRules();
98}
99
100void FirewallManager::AddFirewallRules() {
101 AddUdpPortRule(kDhcpServerPort);
102}
103
104void FirewallManager::AddUdpPortRule(uint16_t port) {
105 bool allowed = false;
106 // Pass the read end of the pipe to permission_broker, for it to monitor this
107 // process.
108 dbus::FileDescriptor fd(lifeline_read_fd_);
109 fd.CheckValidity();
110 chromeos::ErrorPtr error;
111 if (!permission_broker_proxy_->RequestUdpPortAccess(port,
Jorge Lucangeli Obes02f60b32015-02-11 15:56:35 -0800112 "", /* interface */
Peter Qiu1810c012015-02-05 14:35:41 -0800113 fd,
114 &allowed,
115 &error)) {
116 LOG(ERROR) << "Failed request UDP port access: "
117 << error->GetCode() << " " << error->GetMessage();
118 return;
119 }
120 if (!allowed) {
121 LOG(ERROR) << "Access request for UDP port " << port << " is denied";
122 }
123 LOG(INFO) << "Added UDP port " << port;
124}
125
126} // namespace apmanager