/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "FwmarkServer.h"

#include <netinet/in.h>
#include <selinux/selinux.h>
#include <sys/socket.h>
#include <unistd.h>
#include <utils/String16.h>

#include <android-base/cmsg.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <binder/IServiceManager.h>
#include <netd_resolv/resolv.h>  // NETID_UNSET

#include "Fwmark.h"
#include "FwmarkCommand.h"
#include "NetdConstants.h"
#include "NetworkController.h"
#include "TrafficController.h"

using android::String16;
using android::base::ReceiveFileDescriptorVector;
using android::base::unique_fd;
using android::net::metrics::INetdEventListener;

namespace android {
namespace net {

constexpr const char *SYSTEM_SERVER_CONTEXT = "u:r:system_server:s0";

bool isSystemServer(SocketClient* client) {
    if (client->getUid() != AID_SYSTEM) {
        return false;
    }

    char *context;
    if (getpeercon(client->getSocket(), &context)) {
        return false;
    }

    // We can't use context_new and context_type_get as they're private to libselinux. So just do
    // a string match instead.
    bool ret = !strcmp(context, SYSTEM_SERVER_CONTEXT);
    freecon(context);

    return ret;
}

FwmarkServer::FwmarkServer(NetworkController* networkController, EventReporter* eventReporter,
                           TrafficController* trafficCtrl)
    : SocketListener(SOCKET_NAME, true),
      mNetworkController(networkController),
      mEventReporter(eventReporter),
      mTrafficCtrl(trafficCtrl),
      mRedirectSocketCalls(
              android::base::GetBoolProperty("ro.vendor.redirect_socket_calls", false)) {}

bool FwmarkServer::onDataAvailable(SocketClient* client) {
    int socketFd = -1;
    int error = processClient(client, &socketFd);
    if (socketFd >= 0) {
        close(socketFd);
    }

    // Always send a response even if there were connection errors or read errors, so that we don't
    // inadvertently cause the client to hang (which always waits for a response).
    client->sendData(&error, sizeof(error));

    // Always close the client connection (by returning false). This prevents a DoS attack where
    // the client issues multiple commands on the same connection, never reading the responses,
    // causing its receive buffer to fill up, and thus causing our client->sendData() to block.
    return false;
}

static bool hasDestinationAddress(FwmarkCommand::CmdId cmdId, bool redirectSocketCalls) {
    if (redirectSocketCalls) {
        return (cmdId == FwmarkCommand::ON_SENDTO || cmdId == FwmarkCommand::ON_CONNECT ||
                cmdId == FwmarkCommand::ON_SENDMSG || cmdId == FwmarkCommand::ON_SENDMMSG ||
                cmdId == FwmarkCommand::ON_CONNECT_COMPLETE);
    } else {
        return (cmdId == FwmarkCommand::ON_CONNECT_COMPLETE);
    }
}

int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
    FwmarkCommand command;
    FwmarkConnectInfo connectInfo;

    char buf[sizeof(command) + sizeof(connectInfo)];
    std::vector<unique_fd> received_fds;
    ssize_t messageLength =
            ReceiveFileDescriptorVector(client->getSocket(), buf, sizeof(buf), 1, &received_fds);

    if (messageLength < 0) {
        return -errno;
    } else if (messageLength == 0) {
        return -ESHUTDOWN;
    }

    memcpy(&command, buf, sizeof(command));
    memcpy(&connectInfo, buf + sizeof(command), sizeof(connectInfo));

    size_t expectedLen = sizeof(command);
    if (hasDestinationAddress(command.cmdId, mRedirectSocketCalls)) {
        expectedLen += sizeof(connectInfo);
    }

    if (messageLength != static_cast<ssize_t>(expectedLen)) {
        return -EBADMSG;
    }

    Permission permission = mNetworkController->getPermissionForUser(client->getUid());

    if (command.cmdId == FwmarkCommand::QUERY_USER_ACCESS) {
        if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
            return -EPERM;
        }
        return mNetworkController->checkUserNetworkAccess(command.uid, command.netId);
    }

    if (command.cmdId == FwmarkCommand::SET_COUNTERSET) {
        return mTrafficCtrl->setCounterSet(command.trafficCtrlInfo, command.uid, client->getUid());
    }

    if (command.cmdId == FwmarkCommand::DELETE_TAGDATA) {
        return mTrafficCtrl->deleteTagData(command.trafficCtrlInfo, command.uid, client->getUid());
    }

    if (received_fds.size() != 1) {
        LOG(ERROR) << "FwmarkServer received " << received_fds.size() << " fds from client?";
        return -EBADF;
    } else if (received_fds[0] < 0) {
        LOG(ERROR) << "FwmarkServer received fd -1 from ReceiveFileDescriptorVector?";
        return -EBADF;
    }

    *socketFd = received_fds[0].release();

    int family;
    socklen_t familyLen = sizeof(family);
    if (getsockopt(*socketFd, SOL_SOCKET, SO_DOMAIN, &family, &familyLen) == -1) {
        return -errno;
    }
    if (!FwmarkCommand::isSupportedFamily(family)) {
        return -EAFNOSUPPORT;
    }

    Fwmark fwmark;
    socklen_t fwmarkLen = sizeof(fwmark.intValue);
    if (getsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue, &fwmarkLen) == -1) {
        return -errno;
    }

    switch (command.cmdId) {
        case FwmarkCommand::ON_ACCEPT: {
            // Called after a socket accept(). The kernel would've marked the NetId and necessary
            // permissions bits, so we just add the rest of the user's permissions here.
            permission = static_cast<Permission>(permission | fwmark.permission);
            break;
        }

        case FwmarkCommand::ON_CONNECT: {
            // Called before a socket connect() happens. Set an appropriate NetId into the fwmark so
            // that the socket routes consistently over that network. Do this even if the socket
            // already has a NetId, so that calling connect() multiple times still works.
            //
            // But if the explicit bit was set, the existing NetId was explicitly preferred (and not
            // a case of connect() being called multiple times). Don't reset the NetId in that case.
            //
            // An "appropriate" NetId is the NetId of a bypassable VPN that applies to the user, or
            // failing that, the default network. We'll never set the NetId of a secure VPN here.
            // See the comments in the implementation of getNetworkForConnect() for more details.
            //
            // If the protect bit is set, this could be either a system proxy (e.g.: the dns proxy
            // or the download manager) acting on behalf of another user, or a VPN provider. If it's
            // a proxy, we shouldn't reset the NetId. If it's a VPN provider, we should set the
            // default network's NetId.
            //
            // There's no easy way to tell the difference between a proxy and a VPN app. We can't
            // use PERMISSION_SYSTEM to identify the proxy because a VPN app may also have those
            // permissions. So we use the following heuristic:
            //
            // If it's a proxy, but the existing NetId is not a VPN, that means the user (that the
            // proxy is acting on behalf of) is not subject to a VPN, so the proxy must have picked
            // the default network's NetId. So, it's okay to replace that with the current default
            // network's NetId (which in all likelihood is the same).
            //
            // Conversely, if it's a VPN provider, the existing NetId cannot be a VPN. The only time
            // we set a VPN's NetId into a socket without setting the explicit bit is here, in
            // ON_CONNECT, but we won't do that if the socket has the protect bit set. If the VPN
            // provider connect()ed (and got the VPN NetId set) and then called protect(), we
            // would've unset the NetId in PROTECT_FROM_VPN below.
            //
            // So, overall (when the explicit bit is not set but the protect bit is set), if the
            // existing NetId is a VPN, don't reset it. Else, set the default network's NetId.
            if (!fwmark.explicitlySelected) {
                if (!fwmark.protectedFromVpn) {
                    fwmark.netId = mNetworkController->getNetworkForConnect(client->getUid());
                } else if (!mNetworkController->isVirtualNetwork(fwmark.netId)) {
                    fwmark.netId = mNetworkController->getDefaultNetwork();
                }
            }
            break;
        }

        case FwmarkCommand::ON_CONNECT_COMPLETE: {
            // Called after a socket connect() completes.
            // This reports connect event including netId, destination IP address, destination port,
            // uid, connect latency, and connect errno if any.

            // Skip reporting if connect() happened on a UDP socket.
            int socketProto;
            socklen_t intSize = sizeof(socketProto);
            const int ret = getsockopt(*socketFd, SOL_SOCKET, SO_PROTOCOL, &socketProto, &intSize);
            if ((ret != 0) || (socketProto == IPPROTO_UDP)) {
                break;
            }

            android::sp<android::net::metrics::INetdEventListener> netdEventListener =
                    mEventReporter->getNetdEventListener();

            if (netdEventListener != nullptr) {
                char addrstr[INET6_ADDRSTRLEN];
                char portstr[sizeof("65536")];
                const int ret = getnameinfo((sockaddr*) &connectInfo.addr, sizeof(connectInfo.addr),
                        addrstr, sizeof(addrstr), portstr, sizeof(portstr),
                        NI_NUMERICHOST | NI_NUMERICSERV);

                netdEventListener->onConnectEvent(fwmark.netId, connectInfo.error,
                        connectInfo.latencyMs,
                        (ret == 0) ? String16(addrstr) : String16(""),
                        (ret == 0) ? strtoul(portstr, nullptr, 10) : 0, client->getUid());
            }
            break;
        }

        case FwmarkCommand::ON_SENDMMSG:
        case FwmarkCommand::ON_SENDMSG:
        case FwmarkCommand::ON_SENDTO: {
            return 0;
        }

        case FwmarkCommand::SELECT_NETWORK: {
            fwmark.netId = command.netId;
            if (command.netId == NETID_UNSET) {
                fwmark.explicitlySelected = false;
                fwmark.protectedFromVpn = false;
                permission = PERMISSION_NONE;
            } else {
                if (int ret = mNetworkController->checkUserNetworkAccess(client->getUid(),
                                                                         command.netId)) {
                    return ret;
                }
                fwmark.explicitlySelected = true;
                fwmark.protectedFromVpn = mNetworkController->canProtect(client->getUid());
            }
            break;
        }

        case FwmarkCommand::PROTECT_FROM_VPN: {
            if (!mNetworkController->canProtect(client->getUid())) {
                return -EPERM;
            }
            // If a bypassable VPN's provider app calls connect() and then protect(), it will end up
            // with a socket that looks like that of a system proxy but is not (see comments for
            // ON_CONNECT above). So, reset the NetId.
            //
            // In any case, it's appropriate that if the socket has an implicit VPN NetId mark, the
            // PROTECT_FROM_VPN command should unset it.
            if (!fwmark.explicitlySelected && mNetworkController->isVirtualNetwork(fwmark.netId)) {
                fwmark.netId = mNetworkController->getDefaultNetwork();
            }
            fwmark.protectedFromVpn = true;
            permission = static_cast<Permission>(permission | fwmark.permission);
            break;
        }

        case FwmarkCommand::SELECT_FOR_USER: {
            if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
                return -EPERM;
            }
            fwmark.netId = mNetworkController->getNetworkForUser(command.uid);
            fwmark.protectedFromVpn = true;
            break;
        }

        case FwmarkCommand::TAG_SOCKET: {
            // If the UID is -1, tag as the caller's UID:
            //  - TrafficStats and NetworkManagementSocketTagger use -1 to indicate "use the
            //    caller's UID".
            //  - xt_qtaguid will see -1 on the command line, fail to parse it as a uint32_t, and
            //    fall back to current_fsuid().
            if (static_cast<int>(command.uid) == -1) {
                command.uid = client->getUid();
            }
            return mTrafficCtrl->tagSocket(*socketFd, command.trafficCtrlInfo, command.uid,
                                           client->getUid());
        }

        case FwmarkCommand::UNTAG_SOCKET: {
            // Any process can untag a socket it has an fd for.
            return mTrafficCtrl->untagSocket(*socketFd);
        }

        default: {
            // unknown command
            return -EPROTO;
        }
    }

    fwmark.permission = permission;

    if (setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue,
                   sizeof(fwmark.intValue)) == -1) {
        return -errno;
    }

    return 0;
}

}  // namespace net
}  // namespace android
