1 // Copyright 2020 The Chromium 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 #ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PORT_FORWARDER_H_ 6 #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PORT_FORWARDER_H_ 7 8 #include <string> 9 10 #include "base/files/scoped_file.h" 11 #include "base/memory/weak_ptr.h" 12 #include "base/observer_list.h" 13 #include "base/values.h" 14 #include "chrome/browser/chromeos/crostini/crostini_util.h" 15 #include "components/keyed_service/core/keyed_service.h" 16 17 class Profile; 18 19 namespace crostini { 20 21 extern const char kDefaultInterfaceToForward[]; 22 extern const char kWlanInterface[]; 23 extern const char kPortNumberKey[]; 24 extern const char kPortProtocolKey[]; 25 extern const char kPortInterfaceKey[]; 26 extern const char kPortLabelKey[]; 27 extern const char kPortVmNameKey[]; 28 extern const char kPortContainerNameKey[]; 29 30 class CrostiniPortForwarder : public KeyedService { 31 public: 32 class Observer : public base::CheckedObserver { 33 public: 34 // Called when a port's active state changes. 35 virtual void OnActivePortsChanged(const base::ListValue& activePorts) = 0; 36 }; 37 38 enum class Protocol { 39 TCP = 0, 40 UDP = 1, 41 }; 42 43 struct PortRuleKey { 44 uint16_t port_number; 45 Protocol protocol_type; 46 ContainerId container_id; 47 48 bool operator==(const PortRuleKey& other) const { 49 return port_number == other.port_number && 50 protocol_type == other.protocol_type; 51 } 52 }; 53 54 // Helper for using PortRuleKey as key entries in std::unordered_maps. 55 struct PortRuleKeyHasher { operatorPortRuleKeyHasher56 std::size_t operator()(const PortRuleKey& k) const { 57 return ((std::hash<uint16_t>()(k.port_number) ^ 58 (std::hash<Protocol>()(k.protocol_type) << 1)) >> 59 1); 60 } 61 }; 62 63 using ResultCallback = base::OnceCallback<void(bool)>; 64 AddObserver(Observer * observer)65 void AddObserver(Observer* observer) { observers_.AddObserver(observer); } 66 RemoveObserver(Observer * observer)67 void RemoveObserver(Observer* observer) { 68 observers_.RemoveObserver(observer); 69 } 70 71 // The result_callback will only be called with success=true IF all conditions 72 // pass. This means a port setting has been successfully updated in the 73 // iptables and the profile preference setting has also been successfully 74 // updated. 75 void ActivatePort(const ContainerId& container_id, 76 uint16_t port_number, 77 const Protocol& protocol_type, 78 ResultCallback result_callback); 79 void AddPort(const ContainerId& container_id, 80 uint16_t port_number, 81 const Protocol& protocol_type, 82 const std::string& label, 83 ResultCallback result_callback); 84 void DeactivatePort(const ContainerId& container_id, 85 uint16_t port_number, 86 const Protocol& protocol_type, 87 ResultCallback result_callback); 88 void RemovePort(const ContainerId& container_id, 89 uint16_t port_number, 90 const Protocol& protocol_type, 91 ResultCallback result_callback); 92 93 // TODO(matterchen): For the two following methods, implement callback 94 // results. 95 96 // Deactivate all ports belonging to the container_id and removes them from 97 // the preferences. 98 void RemoveAllPorts(const ContainerId& container_id); 99 100 // Deactivate all active ports belonging to the container_id and set their 101 // preference to inactive such that these ports will not be automatically 102 // re-forwarded on re-startup. This is called on container shutdown. 103 void DeactivateAllActivePorts(const ContainerId& container_id); 104 105 base::ListValue GetActivePorts(); 106 107 size_t GetNumberOfForwardedPortsForTesting(); 108 base::Optional<base::Value> ReadPortPreferenceForTesting( 109 const PortRuleKey& key); 110 void ActiveNetworksChanged(const std::string& interface); 111 112 static CrostiniPortForwarder* GetForProfile(Profile* profile); 113 114 explicit CrostiniPortForwarder(Profile* profile); 115 ~CrostiniPortForwarder() override; 116 117 private: 118 FRIEND_TEST_ALL_PREFIXES(CrostiniPortForwarderTest, 119 TryActivatePortPermissionBrokerClientFail); 120 FRIEND_TEST_ALL_PREFIXES(CrostiniPortForwarderTest, GetActivePortsForUI); 121 122 void SignalActivePortsChanged(); 123 bool MatchPortRuleDict(const base::Value& dict, const PortRuleKey& key); 124 bool MatchPortRuleContainerId(const base::Value& dict, 125 const ContainerId& container_id); 126 void AddNewPortPreference(const PortRuleKey& key, const std::string& label); 127 bool RemovePortPreference(const PortRuleKey& key); 128 base::Optional<base::Value> ReadPortPreference(const PortRuleKey& key); 129 130 void OnActivatePortCompleted(ResultCallback result_callback, 131 PortRuleKey key, 132 bool success); 133 void OnRemoveOrDeactivatePortCompleted(ResultCallback result_callback, 134 PortRuleKey key, 135 bool success); 136 void TryDeactivatePort(const PortRuleKey& key, 137 const ContainerId& container_id, 138 base::OnceCallback<void(bool)> result_callback); 139 void TryActivatePort(const PortRuleKey& key, 140 const ContainerId& container_id, 141 base::OnceCallback<void(bool)> result_callback); 142 void UpdateActivePortInterfaces(); 143 144 // For each port rule (protocol, port, interface), keep track of the fd which 145 // requested it so we can release it on removal / deactivate. 146 std::unordered_map<PortRuleKey, base::ScopedFD, PortRuleKeyHasher> 147 forwarded_ports_; 148 149 // Current interface to forward ports on. 150 std::string current_interface_; 151 152 base::ObserverList<Observer> observers_; 153 154 Profile* profile_; 155 156 base::WeakPtrFactory<CrostiniPortForwarder> weak_ptr_factory_{this}; 157 158 DISALLOW_COPY_AND_ASSIGN(CrostiniPortForwarder); 159 160 }; // class 161 162 } // namespace crostini 163 164 #endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PORT_FORWARDER_H_ 165