File: crostini_port_forwarder.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (172 lines) | stat: -rw-r--r-- 6,457 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_CROSTINI_CROSTINI_PORT_FORWARDER_H_
#define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_PORT_FORWARDER_H_

#include <string>
#include <unordered_map>

#include "base/files/scoped_file.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "chrome/browser/ash/crostini/crostini_util.h"
#include "components/keyed_service/core/keyed_service.h"

class Profile;

namespace crostini {

extern const char kDefaultInterfaceToForward[];
extern const char kWlanInterface[];
extern const char kPortNumberKey[];
extern const char kPortProtocolKey[];
extern const char kPortInterfaceKey[];
extern const char kPortLabelKey[];
extern const char kPortVmNameKey[];
extern const char kPortContainerNameKey[];

class CrostiniPortForwarder : public KeyedService {
 public:
  class Observer : public base::CheckedObserver {
   public:
    // Called when a port's active state changes.
    virtual void OnActivePortsChanged(const base::Value::List& activePorts) = 0;
    virtual void OnActiveNetworkChanged(const base::Value& interface,
                                        const base::Value& ipAddress) = 0;
  };

  enum class Protocol {
    TCP = 0,
    UDP = 1,
  };

  struct PortRuleKey {
    uint16_t port_number;
    Protocol protocol_type;
    guest_os::GuestId container_id;

    bool operator==(const PortRuleKey& other) const {
      return port_number == other.port_number &&
             protocol_type == other.protocol_type;
    }
  };

  // Helper for using PortRuleKey as key entries in std::unordered_maps.
  struct PortRuleKeyHasher {
    std::size_t operator()(const PortRuleKey& k) const {
      return ((std::hash<uint16_t>()(k.port_number) ^
               (std::hash<Protocol>()(k.protocol_type) << 1)) >>
              1);
    }
  };

  using ResultCallback = base::OnceCallback<void(bool)>;

  void AddObserver(Observer* observer) { observers_.AddObserver(observer); }

  void RemoveObserver(Observer* observer) {
    observers_.RemoveObserver(observer);
  }

  // The result_callback will only be called with success=true IF all conditions
  // pass. This means a port setting has been successfully updated in the
  // iptables and the profile preference setting has also been successfully
  // updated.
  void ActivatePort(const guest_os::GuestId& container_id,
                    uint16_t port_number,
                    const Protocol& protocol_type,
                    ResultCallback result_callback);
  void AddPort(const guest_os::GuestId& container_id,
               uint16_t port_number,
               const Protocol& protocol_type,
               const std::string& label,
               ResultCallback result_callback);
  void DeactivatePort(const guest_os::GuestId& container_id,
                      uint16_t port_number,
                      const Protocol& protocol_type,
                      ResultCallback result_callback);
  void RemovePort(const guest_os::GuestId& container_id,
                  uint16_t port_number,
                  const Protocol& protocol_type,
                  ResultCallback result_callback);

  // TODO(matterchen): For the two following methods, implement callback
  // results.

  // Deactivate all ports belonging to the container_id and removes them from
  // the preferences.
  void RemoveAllPorts(const guest_os::GuestId& container_id);

  // Deactivate all active ports belonging to the container_id and set their
  // preference to inactive such that these ports will not be automatically
  // re-forwarded on re-startup. This is called on container shutdown.
  void DeactivateAllActivePorts(const guest_os::GuestId& container_id);

  base::Value::List GetActivePorts();
  base::Value::List GetActiveNetworkInfo();

  size_t GetNumberOfForwardedPortsForTesting();
  std::optional<base::Value> ReadPortPreferenceForTesting(
      const PortRuleKey& key);
  void ActiveNetworksChanged(const std::string& interface,
                             const std::string& ip_address);

  explicit CrostiniPortForwarder(Profile* profile);

  CrostiniPortForwarder(const CrostiniPortForwarder&) = delete;
  CrostiniPortForwarder& operator=(const CrostiniPortForwarder&) = delete;

  ~CrostiniPortForwarder() override;

 private:
  FRIEND_TEST_ALL_PREFIXES(CrostiniPortForwarderTest,
                           TryActivatePortPermissionBrokerClientFail);
  FRIEND_TEST_ALL_PREFIXES(CrostiniPortForwarderTest, GetActivePortsForUI);

  void SignalActivePortsChanged();
  bool MatchPortRuleDict(const base::Value& dict, const PortRuleKey& key);
  bool MatchPortRuleContainerId(const base::Value& dict,
                                const guest_os::GuestId& container_id);
  void AddNewPortPreference(const PortRuleKey& key, const std::string& label);
  bool RemovePortPreference(const PortRuleKey& key);
  std::optional<base::Value> ReadPortPreference(const PortRuleKey& key);

  void OnActivatePortCompleted(ResultCallback result_callback,
                               PortRuleKey key,
                               bool success);
  void OnRemoveOrDeactivatePortCompleted(ResultCallback result_callback,
                                         PortRuleKey key,
                                         bool success);
  void TryDeactivatePort(const PortRuleKey& key,
                         const guest_os::GuestId& container_id,
                         base::OnceCallback<void(bool)> result_callback);
  void TryActivatePort(const PortRuleKey& key,
                       const guest_os::GuestId& container_id,
                       base::OnceCallback<void(bool)> result_callback);
  void UpdateActivePortInterfaces();

  // For each port rule (protocol, port, interface), keep track of the fd which
  // requested it so we can release it on removal / deactivate.
  std::unordered_map<PortRuleKey, base::ScopedFD, PortRuleKeyHasher>
      forwarded_ports_;

  // Current interface to forward ports on.
  std::string current_interface_;
  std::string ip_address_;

  base::ObserverList<Observer> observers_;

  raw_ptr<Profile> profile_;

  base::WeakPtrFactory<CrostiniPortForwarder> weak_ptr_factory_{this};

};  // class

}  // namespace crostini

#endif  // CHROME_BROWSER_ASH_CROSTINI_CROSTINI_PORT_FORWARDER_H_