blob: f062dcf29726ee2c0fcea0e0846642e513e48f42 [file] [log] [blame]
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -05001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Sreeram Ramachandran72604072014-05-21 13:19:43 -070017// THREAD-SAFETY
18// -------------
19// The methods in this file are called from multiple threads (from CommandListener, FwmarkServer
20// and DnsProxyListener). So, all accesses to shared state are guarded by a lock.
21//
22// In some cases, a single non-const method acquires and releases the lock several times, like so:
23// if (isValidNetwork(...)) { // isValidNetwork() acquires and releases the lock.
24// setDefaultNetwork(...); // setDefaultNetwork() also acquires and releases the lock.
25//
26// It might seem that this allows races where the state changes between the two statements, but in
27// fact there are no races because:
28// 1. This pattern only occurs in non-const methods (i.e., those that mutate state).
29// 2. Only CommandListener calls these non-const methods. The others call only const methods.
30// 3. CommandListener only processes one command at a time. I.e., it's serialized.
31// Thus, no other mutation can occur in between the two statements above.
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050032
33#include "NetworkController.h"
34
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070035#include "PhysicalNetwork.h"
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070036#include "RouteController.h"
Sreeram Ramachandran4043f012014-06-23 12:41:37 -070037#include "VirtualNetwork.h"
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070038
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070039#define LOG_TAG "Netd"
40#include "log/log.h"
Sreeram Ramachandran72604072014-05-21 13:19:43 -070041#include "resolv_netid.h"
42
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070043namespace {
44
45// Keep these in sync with ConnectivityService.java.
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070046const unsigned MIN_NET_ID = 10;
47const unsigned MAX_NET_ID = 65535;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070048
49} // namespace
50
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070051NetworkController::NetworkController() : mDefaultNetId(NETID_UNSET) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050052}
53
54unsigned NetworkController::getDefaultNetwork() const {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070055 android::RWLock::AutoRLock lock(mRWLock);
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050056 return mDefaultNetId;
57}
58
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070059int NetworkController::setDefaultNetwork(unsigned netId) {
60 android::RWLock::AutoWLock lock(mRWLock);
61
62 if (netId == mDefaultNetId) {
63 return 0;
Sreeram Ramachandran72604072014-05-21 13:19:43 -070064 }
65
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070066 if (netId != NETID_UNSET) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070067 Network* network = getNetworkLocked(netId);
68 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070069 ALOGE("invalid netId %u", netId);
70 return -EINVAL;
71 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070072 if (int ret = static_cast<PhysicalNetwork*>(network)->addAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070073 return ret;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070074 }
75 }
76
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070077 if (mDefaultNetId != NETID_UNSET) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070078 Network* network = getNetworkLocked(mDefaultNetId);
79 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070080 ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
81 return -ESRCH;
82 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -070083 if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070084 return ret;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070085 }
86 }
87
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070088 mDefaultNetId = netId;
89 return 0;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050090}
91
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070092bool NetworkController::setNetworkForUidRange(uid_t uidStart, uid_t uidEnd, unsigned netId,
93 bool forwardDns) {
94 if (uidStart > uidEnd || !isValidNetwork(netId)) {
Lorenzo Colittice8f5832014-05-29 12:20:55 +090095 errno = EINVAL;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050096 return false;
Lorenzo Colittice8f5832014-05-29 12:20:55 +090097 }
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050098
Sreeram Ramachandran72604072014-05-21 13:19:43 -070099 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700100 for (UidEntry& entry : mUidMap) {
101 if (entry.uidStart == uidStart && entry.uidEnd == uidEnd && entry.netId == netId) {
102 entry.forwardDns = forwardDns;
103 return true;
104 }
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500105 }
106
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700107 mUidMap.push_front(UidEntry(uidStart, uidEnd, netId, forwardDns));
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500108 return true;
109}
110
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700111bool NetworkController::clearNetworkForUidRange(uid_t uidStart, uid_t uidEnd, unsigned netId) {
112 if (uidStart > uidEnd || !isValidNetwork(netId)) {
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900113 errno = EINVAL;
Paul Jensen5b49ab92014-04-03 19:06:00 -0400114 return false;
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900115 }
Paul Jensen5b49ab92014-04-03 19:06:00 -0400116
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700117 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700118 for (auto iter = mUidMap.begin(); iter != mUidMap.end(); ++iter) {
119 if (iter->uidStart == uidStart && iter->uidEnd == uidEnd && iter->netId == netId) {
120 mUidMap.erase(iter);
121 return true;
122 }
Paul Jensen5b49ab92014-04-03 19:06:00 -0400123 }
Lorenzo Colittice8f5832014-05-29 12:20:55 +0900124
125 errno = ENOENT;
Paul Jensen5b49ab92014-04-03 19:06:00 -0400126 return false;
127}
128
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700129unsigned NetworkController::getNetwork(uid_t uid, unsigned requestedNetId, bool forDns) const {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500130 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700131 for (const UidEntry& entry : mUidMap) {
132 if (entry.uidStart <= uid && uid <= entry.uidEnd) {
133 if (forDns && !entry.forwardDns) {
134 break;
135 }
136 return entry.netId;
137 }
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500138 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700139 return getNetworkLocked(requestedNetId) ? requestedNetId : mDefaultNetId;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500140}
141
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700142unsigned NetworkController::getNetworkId(const char* interface) const {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700143 android::RWLock::AutoRLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700144 for (const auto& entry : mNetworks) {
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700145 if (entry.second->hasInterface(interface)) {
146 return entry.first;
147 }
148 }
Paul Jensen35c77e32014-04-10 14:57:54 -0400149 return NETID_UNSET;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500150}
151
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700152bool NetworkController::isValidNetwork(unsigned netId) const {
153 android::RWLock::AutoRLock lock(mRWLock);
154 return getNetworkLocked(netId);
155}
156
157int NetworkController::createNetwork(unsigned netId, Permission permission) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700158 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
Paul Jensenae37e8a2014-04-28 10:35:51 -0400159 ALOGE("invalid netId %u", netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900160 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700161 }
162
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700163 if (isValidNetwork(netId)) {
164 ALOGE("duplicate netId %u", netId);
165 return -EEXIST;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700166 }
167
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700168 PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId);
169 if (int ret = physicalNetwork->setPermission(permission)) {
170 ALOGE("inconceivable! setPermission cannot fail on an empty network");
171 delete physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900172 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700173 }
174
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700175 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700176 mNetworks[netId] = physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900177 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700178}
179
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700180int NetworkController::createVpn(unsigned netId, uid_t ownerUid) {
181 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
182 ALOGE("invalid netId %u", netId);
183 return -EINVAL;
184 }
185
186 if (isValidNetwork(netId)) {
187 ALOGE("duplicate netId %u", netId);
188 return -EEXIST;
189 }
190
191 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700192 mNetworks[netId] = new VirtualNetwork(netId, ownerUid);
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700193 return 0;
194}
195
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700196int NetworkController::destroyNetwork(unsigned netId) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700197 if (!isValidNetwork(netId)) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700198 ALOGE("invalid netId %u", netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700199 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700200 }
201
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700202 // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700203
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700204 android::RWLock::AutoWLock lock(mRWLock);
205 Network* network = getNetworkLocked(netId);
206 if (int ret = network->clearInterfaces()) {
207 return ret;
208 }
209 if (mDefaultNetId == netId) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700210 if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700211 ALOGE("inconceivable! removeAsDefault cannot fail on an empty network");
212 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700213 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700214 mDefaultNetId = NETID_UNSET;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700215 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700216 mNetworks.erase(netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700217 delete network;
Sreeram Ramachandran3ced0692014-04-18 09:49:13 -0700218 _resolv_delete_cache_for_net(netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900219 return 0;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700220}
221
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700222int NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700223 if (!isValidNetwork(netId)) {
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700224 ALOGE("invalid netId %u", netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900225 return -EINVAL;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700226 }
227
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700228 unsigned existingNetId = getNetworkId(interface);
229 if (existingNetId != NETID_UNSET && existingNetId != netId) {
230 ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
231 return -EBUSY;
232 }
233
234 android::RWLock::AutoWLock lock(mRWLock);
235 return getNetworkLocked(netId)->addInterface(interface);
236}
237
238int NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
239 if (!isValidNetwork(netId)) {
240 ALOGE("invalid netId %u", netId);
241 return -EINVAL;
242 }
243
244 android::RWLock::AutoWLock lock(mRWLock);
245 return getNetworkLocked(netId)->removeInterface(interface);
246}
247
248Permission NetworkController::getPermissionForUser(uid_t uid) const {
249 android::RWLock::AutoRLock lock(mRWLock);
250 auto iter = mUsers.find(uid);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700251 return iter == mUsers.end() ? PERMISSION_NONE : iter->second;
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700252}
253
254void NetworkController::setPermissionForUsers(Permission permission,
255 const std::vector<uid_t>& uids) {
256 android::RWLock::AutoWLock lock(mRWLock);
257 for (uid_t uid : uids) {
258 if (permission == PERMISSION_NONE) {
259 mUsers.erase(uid);
260 } else {
261 mUsers[uid] = permission;
262 }
263 }
264}
265
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700266// TODO: Handle VPNs.
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700267bool NetworkController::isUserPermittedOnNetwork(uid_t uid, unsigned netId) const {
268 android::RWLock::AutoRLock lock(mRWLock);
269 auto userIter = mUsers.find(uid);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700270 Permission userPermission = (userIter == mUsers.end() ? PERMISSION_NONE : userIter->second);
271 Network* network = getNetworkLocked(netId);
272 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700273 return false;
274 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700275 Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700276 return (userPermission & networkPermission) == networkPermission;
277}
278
279int NetworkController::setPermissionForNetworks(Permission permission,
280 const std::vector<unsigned>& netIds) {
281 android::RWLock::AutoWLock lock(mRWLock);
282 for (unsigned netId : netIds) {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700283 Network* network = getNetworkLocked(netId);
284 if (!network || network->getType() != Network::PHYSICAL) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700285 ALOGE("invalid netId %u", netId);
286 return -EINVAL;
287 }
288
289 // TODO: ioctl(SIOCKILLADDR, ...) to kill socets on the network that don't have permission.
290
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700291 if (int ret = static_cast<PhysicalNetwork*>(network)->setPermission(permission)) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700292 return ret;
293 }
294 }
295 return 0;
296}
297
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700298int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
299 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700300 Network* network = getNetworkLocked(netId);
301 if (!network || network->getType() != Network::VIRTUAL) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700302 ALOGE("invalid netId %u", netId);
303 return -EINVAL;
304 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700305 if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges)) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700306 return ret;
307 }
308 return 0;
309}
310
311int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
312 android::RWLock::AutoWLock lock(mRWLock);
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700313 Network* network = getNetworkLocked(netId);
314 if (!network || network->getType() != Network::VIRTUAL) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700315 ALOGE("invalid netId %u", netId);
316 return -EINVAL;
317 }
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700318 if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges)) {
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700319 return ret;
320 }
321 return 0;
322}
323
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700324int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
325 const char* nexthop, bool legacy, uid_t uid) {
326 return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
327}
328
329int NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
330 const char* nexthop, bool legacy, uid_t uid) {
331 return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
332}
333
334Network* NetworkController::getNetworkLocked(unsigned netId) const {
Sreeram Ramachandran36ed53e2014-07-01 19:01:56 -0700335 auto iter = mNetworks.find(netId);
336 return iter == mNetworks.end() ? NULL : iter->second;
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700337}
338
339int NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
340 const char* nexthop, bool add, bool legacy, uid_t uid) {
341 unsigned existingNetId = getNetworkId(interface);
342 if (netId == NETID_UNSET || existingNetId != netId) {
343 ALOGE("interface %s assigned to netId %u, not %u", interface, existingNetId, netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900344 return -ENOENT;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700345 }
346
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700347 RouteController::TableType tableType;
348 if (legacy) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700349 if (getPermissionForUser(uid) & PERMISSION_CONNECTIVITY_INTERNAL) {
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700350 tableType = RouteController::PRIVILEGED_LEGACY;
351 } else {
352 tableType = RouteController::LEGACY;
353 }
354 } else {
355 tableType = RouteController::INTERFACE;
356 }
357
Sreeram Ramachandraneb27b7e2014-07-01 14:30:30 -0700358 return add ? RouteController::addRoute(interface, destination, nexthop, tableType) :
359 RouteController::removeRoute(interface, destination, nexthop, tableType);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700360}
361
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700362NetworkController::UidEntry::UidEntry(uid_t uidStart, uid_t uidEnd, unsigned netId,
363 bool forwardDns) :
364 uidStart(uidStart), uidEnd(uidEnd), netId(netId), forwardDns(forwardDns) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500365}