blob: 28c34e205c66917a2779864190b8c941080f0766 [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PERMISSION_BROKER_PORT_TRACKER_H_
#define PERMISSION_BROKER_PORT_TRACKER_H_
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/macros.h>
#include <base/sequenced_task_runner.h>
#include <patchpanel/proto_bindings/patchpanel_service.pb.h>
namespace permission_broker {
using patchpanel::ModifyPortRuleRequest;
using Operation = patchpanel::ModifyPortRuleRequest::Operation;
using Protocol = patchpanel::ModifyPortRuleRequest::Protocol;
using RuleType = patchpanel::ModifyPortRuleRequest::RuleType;
class PortTracker {
public:
struct PortRuleKey {
Protocol proto;
uint16_t input_dst_port;
std::string input_ifname;
bool operator==(const PortRuleKey& other) const {
return proto == other.proto && input_dst_port == other.input_dst_port &&
input_ifname == other.input_ifname;
}
};
// Helper for using PortRuleKey as key entries in std::unordered_maps.
struct PortRuleKeyHasher {
std::size_t operator()(const PortRuleKey& k) const {
return ((std::hash<int>()(k.proto) ^
(std::hash<uint16_t>()(k.input_dst_port) << 1)) >>
1) ^
(std::hash<std::string>()(k.input_ifname) << 1);
}
};
// The different types of port rules supported.
enum PortRuleType : uint8_t {
// Forces default PortRuleType zero values to be different from any valid
// port rule type.
kUnknownRule = 0,
// Rule for opening ingress traffic on a destination port.
kAccessRule = 1,
// Rule for closing a destination port to locally originated traffic.
kLockdownRule = 2,
// Rule for forwarding ingress traffic on a destination port.
kForwardingRule = 3,
// Guard value used by FuzzedDataProvider. The name must remain unchanged.
kMaxValue = kForwardingRule
};
struct PortRule {
int lifeline_fd;
PortRuleType type;
Protocol proto;
std::string input_dst_ip;
uint16_t input_dst_port;
std::string input_ifname;
std::string dst_ip;
uint16_t dst_port;
};
PortTracker();
virtual ~PortTracker();
bool AllowTcpPortAccess(uint16_t port, const std::string& iface, int dbus_fd);
bool AllowUdpPortAccess(uint16_t port, const std::string& iface, int dbus_fd);
bool RevokeTcpPortAccess(uint16_t port, const std::string& iface);
bool RevokeUdpPortAccess(uint16_t port, const std::string& iface);
bool LockDownLoopbackTcpPort(uint16_t port, int dbus_fd);
bool ReleaseLoopbackTcpPort(uint16_t port);
bool StartTcpPortForwarding(uint16_t input_dst_port,
const std::string& input_ifname,
const std::string& dst_ip,
uint16_t dst_port,
int dbus_fd);
bool StartUdpPortForwarding(uint16_t input_dst_port,
const std::string& input_ifname,
const std::string& dst_ip,
uint16_t dst_port,
int dbus_fd);
bool StopTcpPortForwarding(uint16_t input_dst_port,
const std::string& input_ifname);
bool StopUdpPortForwarding(uint16_t input_dst_port,
const std::string& input_ifname);
bool HasActiveRules();
// Close all outstanding firewall holes, revoke all forwarding rules, and
// unblock all loopback ports.
void RevokeAllPortRules();
protected:
explicit PortTracker(scoped_refptr<base::SequencedTaskRunner> task_runner);
PortTracker(const PortTracker&) = delete;
PortTracker& operator=(const PortTracker&) = delete;
private:
// Call patchpanel's DBus API to create or remove firewall rule.
virtual bool ModifyPortRule(Operation op, const PortRule& rule);
// Callback to call when a lifeline file descriptor is triggered.
virtual void OnFileDescriptorReadable(int fd);
// Helper functions for process lifetime tracking.
virtual int AddLifelineFd(int dbus_fd);
virtual bool DeleteLifelineFd(int fd);
bool AddPortRule(const PortRule& rule, int dbus_fd);
bool ValidatePortRule(const PortRule& rule);
// Revoke port rule keyed by |key|. Create a copy of |key| to prevent
// accidentally deleting |key| through |lifeline_fds_| or |port_rules_|.
bool RevokePortRule(const PortRuleKey key);
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// For each port rule (protocol, port, interface), keep track of which fd
// requested it. We need this for Release{Tcp|Udp}Port(), to avoid
// traversing |lifeline_fds_| each time.
std::unordered_map<PortRuleKey, PortRule, PortRuleKeyHasher> port_rules_;
// For each fd (process), keep track of which rule (protocol, port, interface)
// it requested.
std::map<int, PortRuleKey> lifeline_fds_;
// For each fd (process), keep track of the FileDescriptorWatcher::Controller
// object associated with it.
std::map<int, std::unique_ptr<base::FileDescriptorWatcher::Controller>>
lifeline_fd_controllers_;
};
} // namespace permission_broker
#endif // PERMISSION_BROKER_PORT_TRACKER_H_