summaryrefslogtreecommitdiff
path: root/server/NetworkController.h
blob: a61ac39f244d4492199d1c027890d3a2e47cdb52 (plain)
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <android-base/thread_annotations.h>
#include <android/multinetwork.h>


#include "NetdConstants.h"
#include "Permission.h"
#include "PhysicalNetwork.h"
#include "UnreachableNetwork.h"
#include "android/net/INetd.h"
#include "netdutils/DumpWriter.h"

#include <sys/types.h>
#include <list>
#include <map>
#include <set>
#include <shared_mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>

struct android_net_context;

namespace android::net {

typedef std::shared_lock<std::shared_mutex> ScopedRLock;
typedef std::lock_guard<std::shared_mutex> ScopedWLock;

constexpr uint32_t kHandleMagic = 0xcafed00d;

// Utility to convert from netId to net_handle_t. Doing this here as opposed to exporting
// from net.c as it may have NDK implications. Besides no conversion available in net.c for
// obtaining handle given netId.
// TODO: Use getnetidfromhandle() in net.c.
static inline unsigned netHandleToNetId(net_handle_t fromNetHandle) {
    const uint32_t k32BitMask = 0xffffffff;
    // This value MUST be kept in sync with the corresponding value in
    // the android.net.Network#getNetworkHandle() implementation.

    // Check for minimum acceptable version of the API in the low bits.
    if (fromNetHandle != NETWORK_UNSPECIFIED &&
        (fromNetHandle & k32BitMask) != kHandleMagic) {
        return 0;
    }

    return ((fromNetHandle >> (CHAR_BIT * sizeof(k32BitMask))) & k32BitMask);
}

// Utility to convert from nethandle to netid, keep in sync with getNetworkHandle
// in Network.java.
static inline net_handle_t netIdToNetHandle(unsigned fromNetId) {
    if (!fromNetId) {
        return NETWORK_UNSPECIFIED;
    }
    return (((net_handle_t)fromNetId << 32) | kHandleMagic);
}

class Network;
class UidRanges;
class VirtualNetwork;

/*
 * Keeps track of default, per-pid, and per-uid-range network selection, as
 * well as the mark associated with each network. Networks are identified
 * by netid. In all set* commands netid == 0 means "unspecified" and is
 * equivalent to clearing the mapping.
 */
class NetworkController {
public:
    // NetIds 53..98 are reserved for future use.
    static constexpr int MIN_OEM_ID = 1;
    static constexpr int MAX_OEM_ID = 50;
    static constexpr int LOCAL_NET_ID = INetd::LOCAL_NET_ID;
    static constexpr int DUMMY_NET_ID = INetd::DUMMY_NET_ID;
    static constexpr int UNREACHABLE_NET_ID = INetd::UNREACHABLE_NET_ID;

    // Route mode for modify route
    enum RouteOperation { ROUTE_ADD, ROUTE_UPDATE, ROUTE_REMOVE };

    NetworkController();

    unsigned getDefaultNetwork() const;
    [[nodiscard]] int setDefaultNetwork(unsigned netId);

    unsigned getNetworkForUser(uid_t uid) const;
    unsigned getNetworkForConnect(uid_t uid) const;
    void getNetworkContext(unsigned netId, uid_t uid, struct android_net_context* netcontext) const;
    unsigned getNetworkForInterface(const char* interface) const;
    bool isVirtualNetwork(unsigned netId) const;

    [[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission);
    [[nodiscard]] int createPhysicalOemNetwork(Permission permission, unsigned* netId);
    [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType);
    [[nodiscard]] int destroyNetwork(unsigned netId);

    [[nodiscard]] int addInterfaceToNetwork(unsigned netId, const char* interface);
    [[nodiscard]] int removeInterfaceFromNetwork(unsigned netId, const char* interface);

    Permission getPermissionForUser(uid_t uid) const;
    void setPermissionForUsers(Permission permission, const std::vector<uid_t>& uids);
    int checkUserNetworkAccess(uid_t uid, unsigned netId) const;
    [[nodiscard]] int setPermissionForNetworks(Permission permission,
                                               const std::vector<unsigned>& netIds);

    [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
                                        uint32_t subPriority);
    [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
                                             uint32_t subPriority);

    // |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
    // route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
    //
    // Routes are added to tables determined by the interface, so only |interface| is actually used.
    // |netId| is given only to sanity check that the interface has the correct netId.
    [[nodiscard]] int addRoute(unsigned netId, const char* interface, const char* destination,
                               const char* nexthop, bool legacy, uid_t uid, int mtu);
    [[nodiscard]] int updateRoute(unsigned netId, const char* interface, const char* destination,
                                  const char* nexthop, bool legacy, uid_t uid, int mtu);
    [[nodiscard]] int removeRoute(unsigned netId, const char* interface, const char* destination,
                                  const char* nexthop, bool legacy, uid_t uid);

    // Notes that the specified address has appeared on the specified interface.
    void addInterfaceAddress(unsigned ifIndex, const char* address);
    // Notes that the specified address has been removed from the specified interface.
    // Returns true if we should destroy sockets on this address.
    bool removeInterfaceAddress(unsigned ifIndex, const char* address);

    bool canProtect(uid_t uid) const;
    void allowProtect(const std::vector<uid_t>& uids);
    void denyProtect(const std::vector<uid_t>& uids);

    void dump(netdutils::DumpWriter& dw);

  private:
    bool isValidNetworkLocked(unsigned netId) const;
    Network* getNetworkLocked(unsigned netId) const;

    // Sets |*netId| to an appropriate NetId to use for DNS for the given user. Call with |*netId|
    // set to a non-NETID_UNSET value if the user already has indicated a preference. Returns the
    // fwmark value to set on the socket when performing the DNS request.
    uint32_t getNetworkForDnsLocked(unsigned* netId, uid_t uid) const;
    unsigned getNetworkForConnectLocked(uid_t uid) const;
    unsigned getNetworkForInterfaceLocked(const char* interface) const;
    bool canProtectLocked(uid_t uid) const;
    bool isVirtualNetworkLocked(unsigned netId) const;
    VirtualNetwork* getVirtualNetworkForUserLocked(uid_t uid) const;
    Network* getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const;
    Permission getPermissionForUserLocked(uid_t uid) const;
    int checkUserNetworkAccessLocked(uid_t uid, unsigned netId) const;
    [[nodiscard]] int createPhysicalNetworkLocked(unsigned netId, Permission permission);

    [[nodiscard]] int modifyRoute(unsigned netId, const char* interface, const char* destination,
                                  const char* nexthop, RouteOperation op, bool legacy, uid_t uid,
                                  int mtu);
    [[nodiscard]] int modifyFallthroughLocked(unsigned vpnNetId, bool add);
    void updateTcpSocketMonitorPolling();

    class DelegateImpl;
    DelegateImpl* const mDelegateImpl;

    // mRWLock guards all accesses to mDefaultNetId, mNetworks, mUsers, mProtectableUsers,
    // mIfindexToLastNetId and mAddressToIfindices.
    mutable std::shared_mutex mRWLock;
    unsigned mDefaultNetId;
    std::map<unsigned, Network*> mNetworks;  // Map keys are NetIds.
    std::map<uid_t, Permission> mUsers;
    std::set<uid_t> mProtectableUsers;
    // Map interface (ifIndex) to its current NetId, or the last NetId if the interface was removed
    // from the network and not added to another network. This state facilitates the interface to
    // NetId lookup during RTM_DELADDR (NetworkController::removeInterfaceAddress), when the
    // interface in question might already have been removed from the network.
    // An interface is added to this map when it is added to a network and removed from this map
    // when its network is destroyed.
    std::unordered_map<unsigned, unsigned> mIfindexToLastNetId;
    // Map IP address to the list of active interfaces (ifIndex) that have that address.
    // Also contains IP addresses configured on interfaces that have not been added to any network.
    // TODO: Does not track IP addresses present when netd is started or restarts after a crash.
    // This is not a problem for its intended use (tracking IP addresses on VPN interfaces), but
    // we should fix it.
    std::unordered_map<std::string, std::unordered_set<unsigned>> mAddressToIfindices;

};

}  // namespace android::net