blob: 7fe90cda4fb4725a83350edea958d4e780bc1582 [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) {
67 auto iter = mPhysicalNetworks.find(netId);
68 if (iter == mPhysicalNetworks.end()) {
69 ALOGE("invalid netId %u", netId);
70 return -EINVAL;
71 }
72 if (int ret = iter->second->addAsDefault()) {
73 return ret;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -070074 }
75 }
76
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -070077 if (mDefaultNetId != NETID_UNSET) {
78 auto iter = mPhysicalNetworks.find(mDefaultNetId);
79 if (iter == mPhysicalNetworks.end()) {
80 ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
81 return -ESRCH;
82 }
83 if (int ret = iter->second->removeAsDefault()) {
84 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);
144 for (const auto& entry : mPhysicalNetworks) {
145 if (entry.second->hasInterface(interface)) {
146 return entry.first;
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700147 }
148 }
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700149 for (const auto& entry : mVirtualNetworks) {
150 if (entry.second->hasInterface(interface)) {
151 return entry.first;
152 }
153 }
Paul Jensen35c77e32014-04-10 14:57:54 -0400154 return NETID_UNSET;
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500155}
156
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700157bool NetworkController::isValidNetwork(unsigned netId) const {
158 android::RWLock::AutoRLock lock(mRWLock);
159 return getNetworkLocked(netId);
160}
161
162int NetworkController::createNetwork(unsigned netId, Permission permission) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700163 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
Paul Jensenae37e8a2014-04-28 10:35:51 -0400164 ALOGE("invalid netId %u", netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900165 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700166 }
167
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700168 if (isValidNetwork(netId)) {
169 ALOGE("duplicate netId %u", netId);
170 return -EEXIST;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700171 }
172
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700173 PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId);
174 if (int ret = physicalNetwork->setPermission(permission)) {
175 ALOGE("inconceivable! setPermission cannot fail on an empty network");
176 delete physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900177 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700178 }
179
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700180 android::RWLock::AutoWLock lock(mRWLock);
181 mPhysicalNetworks[netId] = physicalNetwork;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900182 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700183}
184
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700185int NetworkController::createVpn(unsigned netId, uid_t ownerUid) {
186 if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
187 ALOGE("invalid netId %u", netId);
188 return -EINVAL;
189 }
190
191 if (isValidNetwork(netId)) {
192 ALOGE("duplicate netId %u", netId);
193 return -EEXIST;
194 }
195
196 android::RWLock::AutoWLock lock(mRWLock);
197 mVirtualNetworks[netId] = new VirtualNetwork(netId, ownerUid);
198 return 0;
199}
200
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700201int NetworkController::destroyNetwork(unsigned netId) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700202 if (!isValidNetwork(netId)) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700203 ALOGE("invalid netId %u", netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700204 return -EINVAL;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700205 }
206
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700207 // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700208
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700209 android::RWLock::AutoWLock lock(mRWLock);
210 Network* network = getNetworkLocked(netId);
211 if (int ret = network->clearInterfaces()) {
212 return ret;
213 }
214 if (mDefaultNetId == netId) {
215 PhysicalNetwork* physicalNetwork = static_cast<PhysicalNetwork*>(network);
216 if (int ret = physicalNetwork->removeAsDefault()) {
217 ALOGE("inconceivable! removeAsDefault cannot fail on an empty network");
218 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700219 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700220 mDefaultNetId = NETID_UNSET;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700221 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700222 mPhysicalNetworks.erase(netId);
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700223 mVirtualNetworks.erase(netId);
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700224 delete network;
Sreeram Ramachandran3ced0692014-04-18 09:49:13 -0700225 _resolv_delete_cache_for_net(netId);
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900226 return 0;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700227}
228
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700229int NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
Sreeram Ramachandran72604072014-05-21 13:19:43 -0700230 if (!isValidNetwork(netId)) {
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700231 ALOGE("invalid netId %u", netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900232 return -EINVAL;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700233 }
234
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700235 unsigned existingNetId = getNetworkId(interface);
236 if (existingNetId != NETID_UNSET && existingNetId != netId) {
237 ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
238 return -EBUSY;
239 }
240
241 android::RWLock::AutoWLock lock(mRWLock);
242 return getNetworkLocked(netId)->addInterface(interface);
243}
244
245int NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
246 if (!isValidNetwork(netId)) {
247 ALOGE("invalid netId %u", netId);
248 return -EINVAL;
249 }
250
251 android::RWLock::AutoWLock lock(mRWLock);
252 return getNetworkLocked(netId)->removeInterface(interface);
253}
254
255Permission NetworkController::getPermissionForUser(uid_t uid) const {
256 android::RWLock::AutoRLock lock(mRWLock);
257 auto iter = mUsers.find(uid);
258 return iter != mUsers.end() ? iter->second : PERMISSION_NONE;
259}
260
261void NetworkController::setPermissionForUsers(Permission permission,
262 const std::vector<uid_t>& uids) {
263 android::RWLock::AutoWLock lock(mRWLock);
264 for (uid_t uid : uids) {
265 if (permission == PERMISSION_NONE) {
266 mUsers.erase(uid);
267 } else {
268 mUsers[uid] = permission;
269 }
270 }
271}
272
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700273// TODO: Handle VPNs.
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700274bool NetworkController::isUserPermittedOnNetwork(uid_t uid, unsigned netId) const {
275 android::RWLock::AutoRLock lock(mRWLock);
276 auto userIter = mUsers.find(uid);
277 Permission userPermission = (userIter != mUsers.end() ? userIter->second : PERMISSION_NONE);
278 auto networkIter = mPhysicalNetworks.find(netId);
279 if (networkIter == mPhysicalNetworks.end()) {
280 return false;
281 }
282 Permission networkPermission = networkIter->second->getPermission();
283 return (userPermission & networkPermission) == networkPermission;
284}
285
286int NetworkController::setPermissionForNetworks(Permission permission,
287 const std::vector<unsigned>& netIds) {
288 android::RWLock::AutoWLock lock(mRWLock);
289 for (unsigned netId : netIds) {
290 auto iter = mPhysicalNetworks.find(netId);
291 if (iter == mPhysicalNetworks.end()) {
292 ALOGE("invalid netId %u", netId);
293 return -EINVAL;
294 }
295
296 // TODO: ioctl(SIOCKILLADDR, ...) to kill socets on the network that don't have permission.
297
298 if (int ret = iter->second->setPermission(permission)) {
299 return ret;
300 }
301 }
302 return 0;
303}
304
Sreeram Ramachandranb1425cc2014-06-23 18:54:27 -0700305int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
306 android::RWLock::AutoWLock lock(mRWLock);
307 auto iter = mVirtualNetworks.find(netId);
308 if (iter == mVirtualNetworks.end()) {
309 ALOGE("invalid netId %u", netId);
310 return -EINVAL;
311 }
312 if (int ret = iter->second->addUsers(uidRanges)) {
313 return ret;
314 }
315 return 0;
316}
317
318int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
319 android::RWLock::AutoWLock lock(mRWLock);
320 auto iter = mVirtualNetworks.find(netId);
321 if (iter == mVirtualNetworks.end()) {
322 ALOGE("invalid netId %u", netId);
323 return -EINVAL;
324 }
325 if (int ret = iter->second->removeUsers(uidRanges)) {
326 return ret;
327 }
328 return 0;
329}
330
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700331int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
332 const char* nexthop, bool legacy, uid_t uid) {
333 return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
334}
335
336int NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
337 const char* nexthop, bool legacy, uid_t uid) {
338 return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
339}
340
341Network* NetworkController::getNetworkLocked(unsigned netId) const {
342 auto physicalNetworkIter = mPhysicalNetworks.find(netId);
343 if (physicalNetworkIter != mPhysicalNetworks.end()) {
344 return physicalNetworkIter->second;
345 }
Sreeram Ramachandran4043f012014-06-23 12:41:37 -0700346 {
347 auto iter = mVirtualNetworks.find(netId);
348 if (iter != mVirtualNetworks.end()) {
349 return iter->second;
350 }
351 }
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700352 return NULL;
353}
354
355int NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
356 const char* nexthop, bool add, bool legacy, uid_t uid) {
357 unsigned existingNetId = getNetworkId(interface);
358 if (netId == NETID_UNSET || existingNetId != netId) {
359 ALOGE("interface %s assigned to netId %u, not %u", interface, existingNetId, netId);
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900360 return -ENOENT;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700361 }
362
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700363 RouteController::TableType tableType;
364 if (legacy) {
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700365 if (getPermissionForUser(uid) & PERMISSION_CONNECTIVITY_INTERNAL) {
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700366 tableType = RouteController::PRIVILEGED_LEGACY;
367 } else {
368 tableType = RouteController::LEGACY;
369 }
370 } else {
371 tableType = RouteController::INTERFACE;
372 }
373
Sreeram Ramachandraneb27b7e2014-07-01 14:30:30 -0700374 return add ? RouteController::addRoute(interface, destination, nexthop, tableType) :
375 RouteController::removeRoute(interface, destination, nexthop, tableType);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700376}
377
Sreeram Ramachandranf4f6c8d2014-06-23 09:54:06 -0700378NetworkController::UidEntry::UidEntry(uid_t uidStart, uid_t uidEnd, unsigned netId,
379 bool forwardDns) :
380 uidStart(uidStart), uidEnd(uidEnd), netId(netId), forwardDns(forwardDns) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500381}