1a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak/*
2a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Copyright (C) 2014 The Android Open Source Project
3a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
4a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Licensed under the Apache License, Version 2.0 (the "License");
5a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * you may not use this file except in compliance with the License.
6a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * You may obtain a copy of the License at
7a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
8a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *      http://www.apache.org/licenses/LICENSE-2.0
9a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
10a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Unless required by applicable law or agreed to in writing, software
11a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * distributed under the License is distributed on an "AS IS" BASIS,
12a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * See the License for the specific language governing permissions and
14a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * limitations under the License.
15a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak */
16a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
1772604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// THREAD-SAFETY
1872604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// -------------
1972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// The methods in this file are called from multiple threads (from CommandListener, FwmarkServer
2072604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// and DnsProxyListener). So, all accesses to shared state are guarded by a lock.
2172604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//
2272604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// In some cases, a single non-const method acquires and releases the lock several times, like so:
2372604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     if (isValidNetwork(...)) {  // isValidNetwork() acquires and releases the lock.
2472604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//        setDefaultNetwork(...);  // setDefaultNetwork() also acquires and releases the lock.
2572604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//
2672604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// It might seem that this allows races where the state changes between the two statements, but in
2772604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// fact there are no races because:
2872604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     1. This pattern only occurs in non-const methods (i.e., those that mutate state).
2972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     2. Only CommandListener calls these non-const methods. The others call only const methods.
3072604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     3. CommandListener only processes one command at a time. I.e., it's serialized.
3172604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// Thus, no other mutation can occur in between the two statements above.
32a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
33a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak#include "NetworkController.h"
34a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
352d3a163433c435ff053402ae8965f8602c7ac6daErik Kline#define LOG_TAG "Netd"
362d3a163433c435ff053402ae8965f8602c7ac6daErik Kline#include "log/log.h"
372d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
382d3a163433c435ff053402ae8965f8602c7ac6daErik Kline#include "cutils/misc.h"
392d3a163433c435ff053402ae8965f8602c7ac6daErik Kline#include "resolv_netid.h"
402d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
413a272070fc318ef1a7a5a04e500483f1a7c629a8Pierre Imai#include "Controllers.h"
423667936aadcabddc708797ac38ce1ffb2f992cb3Lorenzo Colitti#include "DummyNetwork.h"
432d3a163433c435ff053402ae8965f8602c7ac6daErik Kline#include "DumpWriter.h"
441011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran#include "Fwmark.h"
456a773534e7f8541f221f27fb8063af079b1a5936Sreeram Ramachandran#include "LocalNetwork.h"
46f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran#include "PhysicalNetwork.h"
475c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include "RouteController.h"
484043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran#include "VirtualNetwork.h"
495c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
505c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandrannamespace {
515c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran// Keep these in sync with ConnectivityService.java.
53bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandranconst unsigned MIN_NET_ID = 100;
54f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranconst unsigned MAX_NET_ID = 65535;
555c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
565c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}  // namespace
575c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
58bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandranconst unsigned NetworkController::MIN_OEM_ID   =  1;
59bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandranconst unsigned NetworkController::MAX_OEM_ID   = 50;
603667936aadcabddc708797ac38ce1ffb2f992cb3Lorenzo Colitticonst unsigned NetworkController::DUMMY_NET_ID = 51;
613667936aadcabddc708797ac38ce1ffb2f992cb3Lorenzo Colitti// NetIds 52..98 are reserved for future use.
62bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandranconst unsigned NetworkController::LOCAL_NET_ID = 99;
63bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandran
6448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran// All calls to methods here are made while holding a write lock on mRWLock.
6548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranclass NetworkController::DelegateImpl : public PhysicalNetwork::Delegate {
6648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranpublic:
6748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    explicit DelegateImpl(NetworkController* networkController);
6848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    virtual ~DelegateImpl();
6948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int modifyFallthrough(unsigned vpnNetId, const std::string& physicalInterface,
7148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          Permission permission, bool add) WARN_UNUSED_RESULT;
7248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranprivate:
7448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int addFallthrough(const std::string& physicalInterface,
7548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                       Permission permission) override WARN_UNUSED_RESULT;
7648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int removeFallthrough(const std::string& physicalInterface,
7748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          Permission permission) override WARN_UNUSED_RESULT;
7848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int modifyFallthrough(const std::string& physicalInterface, Permission permission,
8048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          bool add) WARN_UNUSED_RESULT;
8148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
8248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    NetworkController* const mNetworkController;
8348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran};
8448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
8548e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::DelegateImpl::DelegateImpl(NetworkController* networkController) :
8648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        mNetworkController(networkController) {
8748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
8848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
8948e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::DelegateImpl::~DelegateImpl() {
9048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
9148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
9248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::modifyFallthrough(unsigned vpnNetId,
9348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       const std::string& physicalInterface,
9448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission, bool add) {
9548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (add) {
9648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = RouteController::addVirtualNetworkFallthrough(vpnNetId,
9748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                    physicalInterface.c_str(),
9848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                    permission)) {
9948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            ALOGE("failed to add fallthrough to %s for VPN netId %u", physicalInterface.c_str(),
10048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                  vpnNetId);
10148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
10248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
10348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    } else {
10448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = RouteController::removeVirtualNetworkFallthrough(vpnNetId,
10548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                       physicalInterface.c_str(),
10648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                       permission)) {
10748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            ALOGE("failed to remove fallthrough to %s for VPN netId %u", physicalInterface.c_str(),
10848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                  vpnNetId);
10948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
11048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
11148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
11248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
11348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
11448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
11548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::addFallthrough(const std::string& physicalInterface,
11648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                    Permission permission) {
11748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return modifyFallthrough(physicalInterface, permission, true);
11848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
11948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
12048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::removeFallthrough(const std::string& physicalInterface,
12148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission) {
12248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return modifyFallthrough(physicalInterface, permission, false);
12348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
12448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
12548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::modifyFallthrough(const std::string& physicalInterface,
12648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission, bool add) {
12748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    for (const auto& entry : mNetworkController->mNetworks) {
12848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (entry.second->getType() == Network::VIRTUAL) {
12948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            if (int ret = modifyFallthrough(entry.first, physicalInterface, permission, add)) {
13048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                return ret;
13148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            }
13248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
13348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
13448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
13548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
13648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
13748e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::NetworkController() :
1386be561952ca91e19bc1ba6195ec47e33b43ae7fdPierre Imai        mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET),
1396be561952ca91e19bc1ba6195ec47e33b43ae7fdPierre Imai        mProtectableUsers({AID_VPN}) {
14087475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
1413667936aadcabddc708797ac38ce1ffb2f992cb3Lorenzo Colitti    mNetworks[DUMMY_NET_ID] = new DummyNetwork(DUMMY_NET_ID);
142a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
143a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
144a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczakunsigned NetworkController::getDefaultNetwork() const {
1459c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
146a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    return mDefaultNetId;
147a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
148a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
149f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::setDefaultNetwork(unsigned netId) {
150f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
1519c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
152f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (netId == mDefaultNetId) {
153f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return 0;
1549c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1559c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
156f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (netId != NETID_UNSET) {
15736ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(netId);
158738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (!network) {
159738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("no such netId %u", netId);
160738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            return -ENONET;
161738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        }
162738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (network->getType() != Network::PHYSICAL) {
163738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("cannot set default to non-physical network with netId %u", netId);
164f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return -EINVAL;
165f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
16636ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->addAsDefault()) {
167f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
1689c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran        }
1699c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1709c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
171f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (mDefaultNetId != NETID_UNSET) {
17236ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(mDefaultNetId);
17336ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (!network || network->getType() != Network::PHYSICAL) {
174f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
175f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return -ESRCH;
176f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
17736ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
178f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
1799c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran        }
1809c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1819c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
182f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    mDefaultNetId = netId;
183f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return 0;
184a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
185a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
1861011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranuint32_t NetworkController::getNetworkForDns(unsigned* netId, uid_t uid) const {
1871011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
1881011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Fwmark fwmark;
1891011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.protectedFromVpn = true;
1901011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.permission = PERMISSION_SYSTEM;
191a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    if (checkUserNetworkAccessLocked(uid, *netId) == 0) {
1921011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // If a non-zero NetId was explicitly specified, and the user has permission for that
1931011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // network, use that network's DNS servers. Do not fall through to the default network even
194c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        // if the explicitly selected network is a split tunnel VPN: the explicitlySelected bit
195c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        // ensures that the VPN fallthrough rule does not match.
1961011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        fwmark.explicitlySelected = true;
197c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti
198c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        // If the network is a VPN and it doesn't have DNS servers, use the default network's DNS
199c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        // servers (through the default network). Otherwise, the query is guaranteed to fail.
200c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        // http://b/29498052
201c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        Network *network = getNetworkLocked(*netId);
202c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        if (network && network->getType() == Network::VIRTUAL &&
203c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti                !static_cast<VirtualNetwork *>(network)->getHasDns()) {
204c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti            *netId = mDefaultNetId;
205c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti        }
2061011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    } else {
2071011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // If the user is subject to a VPN and the VPN provides DNS servers, use those servers
2081011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // (possibly falling through to the default network if the VPN doesn't provide a route to
2091011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // them). Otherwise, use the default network's DNS servers.
2101011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
2111011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        if (virtualNetwork && virtualNetwork->getHasDns()) {
2121011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            *netId = virtualNetwork->getNetId();
2131011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        } else {
214c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti            // TODO: return an error instead of silently doing the DNS lookup on the wrong network.
215c63059c8a7423b13cecc8b65885d54c12aae0d10Lorenzo Colitti            // http://b/27560555
2161011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            *netId = mDefaultNetId;
2171011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        }
2181011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
2191011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.netId = *netId;
2201011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return fwmark.intValue;
2211011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
2221011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
2231011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// Returns the NetId that a given UID would use if no network is explicitly selected. Specifically,
2241011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// the VPN that applies to the UID if any; otherwise, the default network.
2251011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranunsigned NetworkController::getNetworkForUser(uid_t uid) const {
2261011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
2271011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid)) {
2281011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return virtualNetwork->getNetId();
2291011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
2301011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return mDefaultNetId;
2311011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
2321011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
2331011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// Returns the NetId that will be set when a socket connect()s. This is the bypassable VPN that
2341011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// applies to the user if any; otherwise, the default network.
2351011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran//
2361011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// In general, we prefer to always set the default network's NetId in connect(), so that if the VPN
2371011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// is a split-tunnel and disappears later, the socket continues working (since the default network's
2381011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// NetId is still valid). Secure VPNs will correctly grab the socket's traffic since they have a
2391011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// high-priority routing rule that doesn't care what NetId the socket has.
2401011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran//
2411011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// But bypassable VPNs have a very low priority rule, so we need to mark the socket with the
2421011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// bypassable VPN's NetId if we expect it to get any traffic at all. If the bypassable VPN is a
2431011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// split-tunnel, that's okay, because we have fallthrough rules that will direct the fallthrough
2441011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// traffic to the default network. But it does mean that if the bypassable VPN goes away (and thus
2451011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// the fallthrough rules also go away), the socket that used to fallthrough to the default network
2461011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// will stop working.
2471011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranunsigned NetworkController::getNetworkForConnect(uid_t uid) const {
248a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    android::RWLock::AutoRLock lock(mRWLock);
249e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
2501011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (virtualNetwork && !virtualNetwork->isSecure()) {
251e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        return virtualNetwork->getNetId();
252a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    }
2531011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return mDefaultNetId;
254a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
255a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
256cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Klinevoid NetworkController::getNetworkContext(
257cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline        unsigned netId, uid_t uid, struct android_net_context* netcontext) const {
258cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    struct android_net_context nc = {
259cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline            .app_netid = netId,
260cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline            .app_mark = MARK_UNSET,
261cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline            .dns_netid = netId,
262cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline            .dns_mark = MARK_UNSET,
263cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline            .uid = uid,
264cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    };
265cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline
266492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // |netId| comes directly (via dnsproxyd) from the value returned by netIdForResolv() in the
267492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // client process. This value is nonzero iff.:
268492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //
269492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // 1. The app specified a netid/nethandle to a DNS resolution method such as:
270492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //        - [Java] android.net.Network#getAllByName()
271492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //        - [C/++] android_getaddrinfofornetwork()
272492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // 2. The app specified a netid/nethandle to be used as a process default via:
273492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //        - [Java] android.net.ConnectivityManager#bindProcessToNetwork()
274492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //        - [C/++] android_setprocnetwork()
275492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // 3. The app called android.net.ConnectivityManager#startUsingNetworkFeature().
276492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    //
277492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // In all these cases (with the possible exception of #3), the right thing to do is to treat
278492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    // such cases as explicitlySelected.
279492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    const bool explicitlySelected = (nc.app_netid != NETID_UNSET);
280492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    if (!explicitlySelected) {
281cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline        nc.app_netid = getNetworkForConnect(uid);
282cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    }
283492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline
284cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    Fwmark fwmark;
285cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    fwmark.netId = nc.app_netid;
286492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    fwmark.explicitlySelected = explicitlySelected;
287492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    fwmark.protectedFromVpn = canProtect(uid);
288492ca5bca129186b53f203386ebe3e28f9143c9eErik Kline    fwmark.permission = getPermissionForUser(uid);
289cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    nc.app_mark = fwmark.intValue;
290cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline
291cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    nc.dns_mark = getNetworkForDns(&(nc.dns_netid), uid);
292cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline
293cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    if (netcontext) {
294cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline        *netcontext = nc;
295cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline    }
296cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline}
297cea2d3455eb7c0d9ad1430607cbe98cc09251c1fErik Kline
298e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranunsigned NetworkController::getNetworkForInterface(const char* interface) const {
299f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
30036ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    for (const auto& entry : mNetworks) {
3014043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        if (entry.second->hasInterface(interface)) {
3024043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran            return entry.first;
3034043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        }
3044043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
30535c77e32b27694a138e9a7877b9a5b474441c58bPaul Jensen    return NETID_UNSET;
306a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
307a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
308070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandranbool NetworkController::isVirtualNetwork(unsigned netId) const {
309070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
310070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
311070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    return network && network->getType() == Network::VIRTUAL;
312070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran}
313070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran
314e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranint NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
315bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandran    if (!((MIN_NET_ID <= netId && netId <= MAX_NET_ID) ||
316bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandran          (MIN_OEM_ID <= netId && netId <= MAX_OEM_ID))) {
317f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("invalid netId %u", netId);
31896f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return -EINVAL;
3195c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
3205c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
321f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (isValidNetwork(netId)) {
322f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("duplicate netId %u", netId);
323f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return -EEXIST;
3245c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
3255c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
32648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId, mDelegateImpl);
327f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (int ret = physicalNetwork->setPermission(permission)) {
328f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("inconceivable! setPermission cannot fail on an empty network");
329f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        delete physicalNetwork;
33096f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return ret;
331ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
332ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
333f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
33436ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    mNetworks[netId] = physicalNetwork;
33596f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti    return 0;
3365c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}
3375c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
33895684ba176a9fe5ea59207d7202e47fa12bbfdbeSreeram Ramachandranint NetworkController::createVirtualNetwork(unsigned netId, bool hasDns, bool secure) {
339bbdde9909b7b4fd31c5857156ceb00049bf4992dSreeram Ramachandran    if (!(MIN_NET_ID <= netId && netId <= MAX_NET_ID)) {
3404043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        ALOGE("invalid netId %u", netId);
3414043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        return -EINVAL;
3424043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
3434043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
3444043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    if (isValidNetwork(netId)) {
3454043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        ALOGE("duplicate netId %u", netId);
3464043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        return -EEXIST;
3474043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
3484043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
3494043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
35048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (int ret = modifyFallthroughLocked(netId, true)) {
35148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return ret;
35248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
35395684ba176a9fe5ea59207d7202e47fa12bbfdbeSreeram Ramachandran    mNetworks[netId] = new VirtualNetwork(netId, hasDns, secure);
3544043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    return 0;
3554043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran}
3564043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
357f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::destroyNetwork(unsigned netId) {
358738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (netId == LOCAL_NET_ID) {
359738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot destroy local network");
36096f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return -EINVAL;
361ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
362738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!isValidNetwork(netId)) {
363738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
364738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
365738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
366ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
367f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
36896f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti
369f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
370f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
37199286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti
37299286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti    // If we fail to destroy a network, things will get stuck badly. Therefore, unlike most of the
37399286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti    // other network code, ignore failures and attempt to clear out as much state as possible, even
37499286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti    // if we hit an error on the way. Return the first error that we see.
37599286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti    int ret = network->clearInterfaces();
37699286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti
377f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (mDefaultNetId == netId) {
37899286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti        if (int err = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
379f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            ALOGE("inconceivable! removeAsDefault cannot fail on an empty network");
38099286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti            if (!ret) {
38199286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti                ret = err;
38299286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti            }
383f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
384f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        mDefaultNetId = NETID_UNSET;
38548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    } else if (network->getType() == Network::VIRTUAL) {
38699286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti        if (int err = modifyFallthroughLocked(netId, false)) {
38799286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti            if (!ret) {
38899286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti                ret = err;
38999286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti            }
39048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
391f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    }
39236ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    mNetworks.erase(netId);
393f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    delete network;
394f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    _resolv_delete_cache_for_net(netId);
39599286fe1ef6fc325c28dd10b651b5adedd549495Lorenzo Colitti    return ret;
396f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
397ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
398f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
399f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (!isValidNetwork(netId)) {
400738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
401738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
402ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
403ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
404e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    unsigned existingNetId = getNetworkForInterface(interface);
405f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (existingNetId != NETID_UNSET && existingNetId != netId) {
406f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
407f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return -EBUSY;
408a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen    }
409a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen
410f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
411f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return getNetworkLocked(netId)->addInterface(interface);
412ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen}
413ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
414f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
41572604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran    if (!isValidNetwork(netId)) {
416738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
417738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
4185c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
4195c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
420f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
421f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return getNetworkLocked(netId)->removeInterface(interface);
422f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
4235c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
424f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram RamachandranPermission NetworkController::getPermissionForUser(uid_t uid) const {
425f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
426ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    return getPermissionForUserLocked(uid);
427f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
4285c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
429f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranvoid NetworkController::setPermissionForUsers(Permission permission,
430f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                              const std::vector<uid_t>& uids) {
431f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
432f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    for (uid_t uid : uids) {
433ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        mUsers[uid] = permission;
4345c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
4355c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}
4365c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
437a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colittiint NetworkController::checkUserNetworkAccess(uid_t uid, unsigned netId) const {
438f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
439a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    return checkUserNetworkAccessLocked(uid, netId);
440379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran}
441379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
442f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::setPermissionForNetworks(Permission permission,
443f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                                const std::vector<unsigned>& netIds) {
444f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
445f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    for (unsigned netId : netIds) {
44636ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(netId);
447738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (!network) {
448738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("no such netId %u", netId);
449738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            return -ENONET;
450738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        }
451738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (network->getType() != Network::PHYSICAL) {
452738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("cannot set permissions on non-physical network with netId %u", netId);
45396f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti            return -EINVAL;
454379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran        }
455379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
456f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        // TODO: ioctl(SIOCKILLADDR, ...) to kill socets on the network that don't have permission.
457379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
45836ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->setPermission(permission)) {
459f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
460379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran        }
461379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran    }
46296f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti    return 0;
463379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran}
464379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
465b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandranint NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
466b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
46736ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
468738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
469738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
470738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
471738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
472738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::VIRTUAL) {
473738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot add users to non-virtual network with netId %u", netId);
474b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return -EINVAL;
475b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
476fff4bd31ff2bad0acfd8f2439eccf7df70e9695fLorenzo Colitti    if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges, mProtectableUsers)) {
477b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return ret;
478b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
479b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    return 0;
480b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran}
481b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran
482b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandranint NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
483b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
48436ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
485738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
486738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
487738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
488738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
489738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::VIRTUAL) {
490738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot remove users from non-virtual network with netId %u", netId);
491b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return -EINVAL;
492b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
493fff4bd31ff2bad0acfd8f2439eccf7df70e9695fLorenzo Colitti    if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges,
494fff4bd31ff2bad0acfd8f2439eccf7df70e9695fLorenzo Colitti                                                                     mProtectableUsers)) {
495b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return ret;
496b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
497b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    return 0;
498b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran}
499b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran
500f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
501f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                const char* nexthop, bool legacy, uid_t uid) {
50238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
5037619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
5047619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
505f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
506f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                   const char* nexthop, bool legacy, uid_t uid) {
50738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
5087619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
5097619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
510e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranbool NetworkController::canProtect(uid_t uid) const {
511e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
512e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return ((getPermissionForUserLocked(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) ||
513e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran           mProtectableUsers.find(uid) != mProtectableUsers.end();
514e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
515e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
51689dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandranvoid NetworkController::allowProtect(const std::vector<uid_t>& uids) {
51789dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
51889dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    mProtectableUsers.insert(uids.begin(), uids.end());
51989dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran}
52089dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran
52189dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandranvoid NetworkController::denyProtect(const std::vector<uid_t>& uids) {
52289dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
52389dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    for (uid_t uid : uids) {
52489dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran        mProtectableUsers.erase(uid);
52589dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    }
52689dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran}
52789dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran
5282d3a163433c435ff053402ae8965f8602c7ac6daErik Klinevoid NetworkController::dump(DumpWriter& dw) {
5292d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    android::RWLock::AutoRLock lock(mRWLock);
5302d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
5312d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.incIndent();
5322d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.println("NetworkController");
5332d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
5342d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.incIndent();
5352d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.println("Default network: %u", mDefaultNetId);
5362d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
5372d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.blankline();
5382d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.println("Networks:");
5392d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.incIndent();
5402d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    for (const auto& i : mNetworks) {
5412d3a163433c435ff053402ae8965f8602c7ac6daErik Kline        dw.println(i.second->toString().c_str());
5423a272070fc318ef1a7a5a04e500483f1a7c629a8Pierre Imai        android::net::gCtls->resolverCtrl.dump(dw, i.first);
5433a272070fc318ef1a7a5a04e500483f1a7c629a8Pierre Imai        dw.blankline();
5442d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    }
5452d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.decIndent();
5462d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
5472d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.decIndent();
5482d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
5492d3a163433c435ff053402ae8965f8602c7ac6daErik Kline    dw.decIndent();
5502d3a163433c435ff053402ae8965f8602c7ac6daErik Kline}
5512d3a163433c435ff053402ae8965f8602c7ac6daErik Kline
552e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranbool NetworkController::isValidNetwork(unsigned netId) const {
553e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
554e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return getNetworkLocked(netId);
555e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
556e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
557f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram RamachandranNetwork* NetworkController::getNetworkLocked(unsigned netId) const {
55836ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    auto iter = mNetworks.find(netId);
55936ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    return iter == mNetworks.end() ? NULL : iter->second;
5607619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
5617619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
562e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram RamachandranVirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
563e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    for (const auto& entry : mNetworks) {
564e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        if (entry.second->getType() == Network::VIRTUAL) {
565e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            VirtualNetwork* virtualNetwork = static_cast<VirtualNetwork*>(entry.second);
566e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            if (virtualNetwork->appliesToUser(uid)) {
567e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran                return virtualNetwork;
568e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            }
569e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        }
570e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    }
571e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return NULL;
572e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
573e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
574ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram RamachandranPermission NetworkController::getPermissionForUserLocked(uid_t uid) const {
575ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    auto iter = mUsers.find(uid);
576ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    if (iter != mUsers.end()) {
577ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        return iter->second;
578ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    }
579ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    return uid < FIRST_APPLICATION_UID ? PERMISSION_SYSTEM : PERMISSION_NONE;
580ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran}
581ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran
582a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colittiint NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) const {
5831011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
584a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    if (!network) {
585a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti        return -ENONET;
586a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    }
587a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti
5881011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    // If uid is INVALID_UID, this likely means that we were unable to retrieve the UID of the peer
5891011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    // (using SO_PEERCRED). Be safe and deny access to the network, even if it's valid.
590a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    if (uid == INVALID_UID) {
591a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti        return -EREMOTEIO;
5921011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
5931011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Permission userPermission = getPermissionForUserLocked(uid);
5941011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if ((userPermission & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
595a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti        return 0;
5961011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
5971011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (network->getType() == Network::VIRTUAL) {
598a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti        return static_cast<VirtualNetwork*>(network)->appliesToUser(uid) ? 0 : -EPERM;
5991011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
6001011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
6011011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (virtualNetwork && virtualNetwork->isSecure() &&
6021011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            mProtectableUsers.find(uid) == mProtectableUsers.end()) {
603a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti        return -EPERM;
6041011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
6051011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
606a1067c8d2b2165f1058a3a8216bed4efacfa1c80Lorenzo Colitti    return ((userPermission & networkPermission) == networkPermission) ? 0 : -EACCES;
6071011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
6081011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
609f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
610f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                   const char* nexthop, bool add, bool legacy, uid_t uid) {
611738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!isValidNetwork(netId)) {
612738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
613738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
614738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
615e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    unsigned existingNetId = getNetworkForInterface(interface);
616738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (existingNetId == NETID_UNSET) {
617738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("interface %s not assigned to any netId", interface);
618738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENODEV;
619738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
620738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (existingNetId != netId) {
621f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("interface %s assigned to netId %u, not %u", interface, existingNetId, netId);
622f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti        return -ENOENT;
6237619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran    }
6247619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
62538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    RouteController::TableType tableType;
62687475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    if (netId == LOCAL_NET_ID) {
62787475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran        tableType = RouteController::LOCAL_NETWORK;
62887475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    } else if (legacy) {
629ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        if ((getPermissionForUser(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
6305009d5ef3fbcdc69d772b528fd22184b7d605afaSreeram Ramachandran            tableType = RouteController::LEGACY_SYSTEM;
63138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        } else {
6325009d5ef3fbcdc69d772b528fd22184b7d605afaSreeram Ramachandran            tableType = RouteController::LEGACY_NETWORK;
63338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        }
63438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    } else {
63538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        tableType = RouteController::INTERFACE;
63638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    }
63738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran
638eb27b7ec10faf47a93fbc2863092cc667b05e252Sreeram Ramachandran    return add ? RouteController::addRoute(interface, destination, nexthop, tableType) :
639eb27b7ec10faf47a93fbc2863092cc667b05e252Sreeram Ramachandran                 RouteController::removeRoute(interface, destination, nexthop, tableType);
6407619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
64148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
64248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::modifyFallthroughLocked(unsigned vpnNetId, bool add) {
64348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (mDefaultNetId == NETID_UNSET) {
64448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return 0;
64548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
64648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    Network* network = getNetworkLocked(mDefaultNetId);
647738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
64848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
64948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return -ESRCH;
65048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
651738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::PHYSICAL) {
652738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("inconceivable! default network must be a physical network");
653738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -EINVAL;
654738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
65548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    Permission permission = static_cast<PhysicalNetwork*>(network)->getPermission();
65648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    for (const auto& physicalInterface : network->getInterfaces()) {
65748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = mDelegateImpl->modifyFallthrough(vpnNetId, physicalInterface, permission,
65848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       add)) {
65948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
66048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
66148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
66248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
66348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
664