summaryrefslogtreecommitdiff
path: root/server/RouteController.h
blob: ff41678d55101931f8f75834543bb2890a3327e4 (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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
 * 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 "InterfaceController.h"  // getParameter
#include "NetdConstants.h"        // IptablesTarget
#include "Network.h"              // UidRangeMap
#include "Permission.h"

#include <android-base/thread_annotations.h>

#include <linux/netlink.h>
#include <sys/types.h>
#include <map>
#include <mutex>

namespace android::net {

// clang-format off
constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM               = 10000;
constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_OIF                  = 11000;
constexpr int32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL               = 12000;
constexpr int32_t RULE_PRIORITY_SECURE_VPN                        = 13000;
constexpr int32_t RULE_PRIORITY_PROHIBIT_NON_VPN                  = 14000;
// Rules used when applications explicitly select a network that they have permission to use only
// because they are in the list of UID ranges for that network.
//
// Sockets from these UIDs will not match RULE_PRIORITY_EXPLICIT_NETWORK rules because they will
// not have the necessary permission bits in the fwmark. We cannot just give any socket on any of
// these networks the permission bits, because if the UID that created the socket loses access to
// the network, then the socket must not match any rule that selects that network.
constexpr int32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK              = 15000;
constexpr int32_t RULE_PRIORITY_EXPLICIT_NETWORK                  = 16000;
constexpr int32_t RULE_PRIORITY_OUTPUT_INTERFACE                  = 17000;
constexpr int32_t RULE_PRIORITY_LEGACY_SYSTEM                     = 18000;
constexpr int32_t RULE_PRIORITY_LEGACY_NETWORK                    = 19000;
constexpr int32_t RULE_PRIORITY_LOCAL_NETWORK                     = 20000;
constexpr int32_t RULE_PRIORITY_TETHERING                         = 21000;
// Implicit rules for sockets that connected on a given network because the network was the default
// network for the UID.
constexpr int32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK              = 22000;
constexpr int32_t RULE_PRIORITY_IMPLICIT_NETWORK                  = 23000;
constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION = 24000;
// Sets of rules used for excluding local routes from the VPN. Look up tables
// that contain directly-connected local routes taken from the default network.
// The first set is used for apps that have a per-UID default network. The rule
// UID ranges match those of the per-UID default network rule for that network.
// The second set has no UID ranges and is used for apps whose default network
// is the system default network network.
constexpr int32_t RULE_PRIORITY_UID_LOCAL_ROUTES                  = 25000;
constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES                      = 26000;
constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION    = 27000;
constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH                   = 28000;
constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK               = 29000;
// Rule used when framework wants to disable default network from specified applications. There will
// be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and
// UID_DEFAULT_NETWORK when framework is switching user preferences.
//
// framework --> netd
// step 1: set uid to unreachable network
// step 2: remove uid from OEM-paid network list
// or
// step 1: add uid to OEM-paid network list
// step 2: remove uid from unreachable network
//
// The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by
// ConnectivityService that it has a network in step 1 of the second case. But if it tries to use
// the network, it will not work. That will potentially cause a user-visible error.
constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE           = 30000;
constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK                   = 31000;
constexpr int32_t RULE_PRIORITY_UNREACHABLE                       = 32000;
// clang-format on

class UidRanges;

class RouteController {
public:
    // How the routing table number is determined for route modification requests.
    enum TableType {
        INTERFACE,       // Compute the table number based on the interface index.
        LOCAL_NETWORK,   // A fixed table used for routes to directly-connected clients/peers.
        LEGACY_NETWORK,  // Use a fixed table that's used to override the default network.
        LEGACY_SYSTEM,   // A fixed table, only modifiable by system apps; overrides VPNs too.
    };

    static const int ROUTE_TABLE_OFFSET_FROM_INDEX = 1000;
    // Offset for the table of virtual local network created from the physical interface.
    static const int ROUTE_TABLE_OFFSET_FROM_INDEX_FOR_LOCAL = 1000000000;

    static constexpr const char* INTERFACE_LOCAL_SUFFIX = "_local";
    static constexpr const char* RT_TABLES_PATH = "/data/misc/net/rt_tables";
    static const char* const LOCAL_MANGLE_INPUT;

    [[nodiscard]] static int Init(unsigned localNetId);

    // Returns an ifindex given the interface name, by looking up in sInterfaceToTable.
    // This is currently only used by NetworkController::addInterfaceToNetwork
    // and should probabaly be changed to passing the ifindex into RouteController instead.
    // We do this instead of calling if_nametoindex because the same interface name can
    // correspond to different interface indices over time. This way, even if the interface
    // index has changed, we can still free any map entries indexed by the ifindex that was
    // used to add them.
    static uint32_t getIfIndex(const char* interface) EXCLUDES(sInterfaceToTableLock);

    [[nodiscard]] static int addInterfaceToLocalNetwork(unsigned netId, const char* interface);
    [[nodiscard]] static int removeInterfaceFromLocalNetwork(unsigned netId, const char* interface);

    [[nodiscard]] static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
                                                           Permission permission,
                                                           const UidRangeMap& uidRangeMap);
    [[nodiscard]] static int removeInterfaceFromPhysicalNetwork(unsigned netId,
                                                                const char* interface,
                                                                Permission permission,
                                                                const UidRangeMap& uidRangeMap);

    [[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
                                                          bool secure,
                                                          const UidRangeMap& uidRangeMap,
                                                          bool excludeLocalRoutes);
    [[nodiscard]] static int removeInterfaceFromVirtualNetwork(unsigned netId,
                                                               const char* interface, bool secure,
                                                               const UidRangeMap& uidRangeMap,
                                                               bool excludeLocalRoutes);

    [[nodiscard]] static int modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
                                                             Permission oldPermission,
                                                             Permission newPermission);

    [[nodiscard]] static int addUsersToVirtualNetwork(unsigned netId, const char* interface,
                                                      bool secure, const UidRangeMap& uidRangeMap,
                                                      bool excludeLocalRoutes);
    [[nodiscard]] static int removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
                                                           bool secure,
                                                           const UidRangeMap& uidRangeMap,
                                                           bool excludeLocalRoutes);

    [[nodiscard]] static int addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges);
    [[nodiscard]] static int removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges);

    [[nodiscard]] static int addInterfaceToDefaultNetwork(const char* interface,
                                                          Permission permission);
    [[nodiscard]] static int removeInterfaceFromDefaultNetwork(const char* interface,
                                                               Permission permission);

    // |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.
    [[nodiscard]] static int addRoute(const char* interface, const char* destination,
                                      const char* nexthop, TableType tableType, int mtu,
                                      int priority);
    [[nodiscard]] static int removeRoute(const char* interface, const char* destination,
                                         const char* nexthop, TableType tableType, int priority);
    [[nodiscard]] static int updateRoute(const char* interface, const char* destination,
                                         const char* nexthop, TableType tableType, int mtu);

    [[nodiscard]] static int enableTethering(const char* inputInterface,
                                             const char* outputInterface);
    [[nodiscard]] static int disableTethering(const char* inputInterface,
                                              const char* outputInterface);

    [[nodiscard]] static int addVirtualNetworkFallthrough(unsigned vpnNetId,
                                                          const char* physicalInterface,
                                                          Permission permission);
    [[nodiscard]] static int removeVirtualNetworkFallthrough(unsigned vpnNetId,
                                                             const char* physicalInterface,
                                                             Permission permission);

    [[nodiscard]] static int addUsersToPhysicalNetwork(unsigned netId, const char* interface,
                                                       const UidRangeMap& uidRangeMap);

    [[nodiscard]] static int removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
                                                            const UidRangeMap& uidRangeMap);

    [[nodiscard]] static int addUsersToUnreachableNetwork(unsigned netId,
                                                          const UidRangeMap& uidRangeMap);

    [[nodiscard]] static int removeUsersFromUnreachableNetwork(unsigned netId,
                                                               const UidRangeMap& uidRangeMap);

    // For testing.
    static int (*iptablesRestoreCommandFunction)(IptablesTarget, const std::string&,
                                                 const std::string&, std::string *);
    static uint32_t (*ifNameToIndexFunction)(const char*);

  private:
    friend class RouteControllerTest;

    static std::mutex sInterfaceToTableLock;
    static std::map<std::string, uint32_t> sInterfaceToTable GUARDED_BY(sInterfaceToTableLock);

    static int configureDummyNetwork();
    [[nodiscard]] static int flushRoutes(const char* interface) EXCLUDES(sInterfaceToTableLock);
    [[nodiscard]] static int flushRoutes(const char* interface, bool local)
            EXCLUDES(sInterfaceToTableLock);
    [[nodiscard]] static int flushRoutes(uint32_t table);
    static uint32_t getRouteTableForInterfaceLocked(const char* interface, bool local)
            REQUIRES(sInterfaceToTableLock);
    static uint32_t getRouteTableForInterface(const char* interface, bool local)
            EXCLUDES(sInterfaceToTableLock);
    static int modifyDefaultNetwork(uint16_t action, const char* interface, Permission permission);
    static int modifyPhysicalNetwork(unsigned netId, const char* interface,
                                     const UidRangeMap& uidRangeMap, Permission permission,
                                     bool add, bool modifyNonUidBasedRules);
    static int modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap, bool add);
    static int modifyRoute(uint16_t action, uint16_t flags, const char* interface,
                           const char* destination, const char* nexthop, TableType tableType,
                           int mtu, int priority, bool isLocal);
    static int modifyTetheredNetwork(uint16_t action, const char* inputInterface,
                                     const char* outputInterface);
    static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
                                        const char* physicalInterface, Permission permission);
    static int modifyVirtualNetwork(unsigned netId, const char* interface,
                                    const UidRangeMap& uidRangeMap, bool secure, bool add,
                                    bool modifyNonUidBasedRules, bool excludeLocalRoutes);
    static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock);
    static int modifyVpnLocalExclusionRule(bool add, const char* physicalInterface);

    static int modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd,
                                         bool add);
    static bool isLocalAddress(TableType tableType, const char* destination, const char* nexthop);
    static bool isTargetV4LocalRange(const char* addrstr);
};

// Public because they are called by by RouteControllerTest.cpp.
// TODO: come up with a scheme of unit testing this code that does not rely on making all its
// functions public.
[[nodiscard]] int modifyIpRoute(uint16_t action, uint16_t flags, uint32_t table,
                                const char* interface, const char* destination, const char* nexthop,
                                uint32_t mtu, uint32_t priority);
uint32_t getRulePriority(const nlmsghdr *nlh);
[[nodiscard]] int modifyIncomingPacketMark(unsigned netId, const char* interface,
                                           Permission permission, bool add);

}  // namespace android::net