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