From 5b54d7cd973851c1bf08bd31e52144345ba8b0ed Mon Sep 17 00:00:00 2001 From: pengxiaochuan Date: Sat, 25 Oct 2025 11:55:39 +0800 Subject: [PATCH] support ndc resolver setnetdns command --- aosp/system/netd/server/NdcDispatcher.cpp | 1306 +++++++++++++++++++++ aosp/system/netd/server/NdcDispatcher.h | 188 +++ 2 files changed, 1494 insertions(+) create mode 100644 aosp/system/netd/server/NdcDispatcher.cpp create mode 100644 aosp/system/netd/server/NdcDispatcher.h diff --git a/aosp/system/netd/server/NdcDispatcher.cpp b/aosp/system/netd/server/NdcDispatcher.cpp new file mode 100644 index 000000000..f8c717be5 --- /dev/null +++ b/aosp/system/netd/server/NdcDispatcher.cpp @@ -0,0 +1,1306 @@ +/* + * Copyright (C) 2019 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 "NdcDispatcher.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "NetdConstants.h" +#include "NetworkController.h" +#include "Permission.h" +#include "UidRanges.h" +#include "netid_client.h" + +using android::base::Join; +using android::base::StringPrintf; +using android::binder::Status; + +#define PARSE_INT_RETURN_IF_FAIL(cli, label, intLabel, errMsg, addErrno) \ + do { \ + if (!android::base::ParseInt((label), &(intLabel))) { \ + errno = EINVAL; \ + (cli)->sendMsg(ResponseCode::OperationFailed, (errMsg), (addErrno)); \ + return 0; \ + } \ + } while (0) + +#define PARSE_UINT_RETURN_IF_FAIL(cli, label, intLabel, errMsg, addErrno) \ + do { \ + if (!android::base::ParseUint((label), &(intLabel))) { \ + errno = EINVAL; \ + (cli)->sendMsg(ResponseCode::OperationFailed, (errMsg), (addErrno)); \ + return 0; \ + } \ + } while (0) + +namespace android { + +using netdutils::ResponseCode; + +namespace net { +namespace { + +const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1; + +unsigned stringToNetId(const char* arg) { + if (!strcmp(arg, "local")) { + return NetworkController::LOCAL_NET_ID; + } + // OEM NetIds are "oem1", "oem2", .., "oem50". + if (!strncmp(arg, "oem", 3)) { + unsigned n = strtoul(arg + 3, nullptr, 0); + if (1 <= n && n <= NUM_OEM_IDS) { + return NetworkController::MIN_OEM_ID + n; + } + return NETID_UNSET; + } else if (!strncmp(arg, "handle", 6)) { + unsigned n = netHandleToNetId((net_handle_t)strtoull(arg + 6, nullptr, 10)); + if (NetworkController::MIN_OEM_ID <= n && n <= NetworkController::MAX_OEM_ID) { + return n; + } + return NETID_UNSET; + } + // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId. + return strtoul(arg, nullptr, 0); +} + +std::string toStdString(const String16& s) { + return std::string(String8(s.c_str())); +} + +int stringToINetdPermission(const char* arg) { + if (!strcmp(arg, "NETWORK")) { + return INetd::PERMISSION_NETWORK; + } + if (!strcmp(arg, "SYSTEM")) { + return INetd::PERMISSION_SYSTEM; + } + return INetd::PERMISSION_NONE; +} + +} // namespace + +sp NdcDispatcher::mNetd; +sp NdcDispatcher::mDnsResolver; + +NdcDispatcher::NdcDispatcher() { + sp sm = defaultServiceManager(); + sp binderNetd = sm->getService(String16("netd")); + sp binderDnsResolver = sm->getService(String16("dnsresolver")); + if ((binderNetd != nullptr) && (binderDnsResolver != nullptr)) { + NdcDispatcher::mNetd = interface_cast(binderNetd); + NdcDispatcher::mDnsResolver = interface_cast(binderDnsResolver); + } else { + LOG(LOGLEVEL) << "Unable to get binder service"; + exit(1); + } + registerCmd(new InterfaceCmd()); + registerCmd(new IpFwdCmd()); + registerCmd(new TetherCmd()); + registerCmd(new NatCmd()); + registerCmd(new BandwidthControlCmd()); + registerCmd(new IdletimerControlCmd()); + registerCmd(new FirewallCmd()); + registerCmd(new NetworkCommand()); + registerCmd(new StrictCmd()); + registerCmd(new ResolveCommand()); +} + +void NdcDispatcher::registerCmd(NdcNetdCommand* cmd) { + mCommands.push_back(cmd); +} + +int NdcDispatcher::dispatchCommand(int argc, char** argv) { + if (argc >= CMD_ARGS_MAX) { + mNdc.sendMsg(500, "Command too long", false); + } + + for (const auto* c : mCommands) { + if (c->getCommand() == argv[0]) { + if (c->runCommand(&mNdc, argc, argv)) { + mNdc.sendMsg(500, "Handler error", true); + } + return 0; + } + } + mNdc.sendMsg(500, "Command not recognized", false); + return 0; +} + +NdcDispatcher::InterfaceCmd::InterfaceCmd() : NdcNetdCommand("interface") {} + +int NdcDispatcher::InterfaceCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + if (!strcmp(argv[1], "list")) { + std::vector interfaceGetList; + Status status = mNetd->interfaceGetList(&interfaceGetList); + + if (!status.isOk()) { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to get interface list", true); + return 0; + } + for (const auto& iface : interfaceGetList) { + cli->sendMsg(ResponseCode::InterfaceListResult, iface.c_str(), false); + } + + cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false); + return 0; + } else { + /* + * These commands take a minimum of 3 arguments + */ + if (argc < 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + if (!strcmp(argv[1], "getcfg")) { + InterfaceConfigurationParcel interfaceCfgResult; + Status status = mNetd->interfaceGetCfg(std::string(argv[2]), &interfaceCfgResult); + + if (!status.isOk()) { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); + return 0; + } + + std::string flags = Join(interfaceCfgResult.flags, " "); + + std::string msg = StringPrintf("%s %s %d %s", interfaceCfgResult.hwAddr.c_str(), + interfaceCfgResult.ipv4Addr.c_str(), + interfaceCfgResult.prefixLength, flags.c_str()); + + cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg.c_str(), false); + + return 0; + } else if (!strcmp(argv[1], "setcfg")) { + // arglist: iface [addr prefixLength] flags + if (argc < 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + LOG(LOGLEVEL) << "Setting iface cfg"; + + struct in_addr addr; + int index = 5; + InterfaceConfigurationParcel interfaceCfg; + interfaceCfg.ifName = argv[2]; + interfaceCfg.hwAddr = ""; + + if (!inet_aton(argv[3], &addr)) { + // Handle flags only case + index = 3; + interfaceCfg.ipv4Addr = ""; + interfaceCfg.prefixLength = 0; + } else { + if (addr.s_addr != 0) { + interfaceCfg.ipv4Addr = argv[3]; + PARSE_INT_RETURN_IF_FAIL(cli, argv[4], interfaceCfg.prefixLength, + "Failed to set address", true); + Status status = mNetd->interfaceSetCfg(interfaceCfg); + if (!status.isOk()) { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true); + return 0; + } + } + } + + /* Process flags */ + for (int i = index; i < argc; i++) { + char* flag = argv[i]; + if (!strcmp(flag, "up")) { + LOG(LOGLEVEL) << "Trying to bring up " << argv[2]; + interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_UP())); + Status status = mNetd->interfaceSetCfg(interfaceCfg); + if (!status.isOk()) { + LOG(LOGLEVEL) << "Error upping interface"; + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true); + ifc_close(); + return 0; + } + } else if (!strcmp(flag, "down")) { + LOG(LOGLEVEL) << "Trying to bring down " << argv[2]; + interfaceCfg.flags.push_back(toStdString(INetd::IF_STATE_DOWN())); + Status status = mNetd->interfaceSetCfg(interfaceCfg); + if (!status.isOk()) { + LOG(LOGLEVEL) << "Error downing interface"; + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", + true); + return 0; + } + } else if (!strcmp(flag, "broadcast") || !strcmp(flag, "multicast") || + !strcmp(flag, "running") || !strcmp(flag, "loopback") || + !strcmp(flag, "point-to-point")) { + // currently ignored + } else { + cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false); + return 0; + } + } + + cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false); + return 0; + } else if (!strcmp(argv[1], "clearaddrs")) { + // arglist: iface + LOG(LOGLEVEL) << "Clearing all IP addresses on " << argv[2]; + + mNetd->interfaceClearAddrs(std::string(argv[2])); + + cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false); + return 0; + } else if (!strcmp(argv[1], "ipv6privacyextensions")) { + if (argc != 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: interface ipv6privacyextensions ", + false); + return 0; + } + int enable = !strcmp(argv[3], "enable"); + Status status = mNetd->interfaceSetIPv6PrivacyExtensions(std::string(argv[2]), enable); + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to set ipv6 privacy extensions", + true); + } + return 0; + } else if (!strcmp(argv[1], "ipv6")) { + if (argc != 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: interface ipv6 ", false); + return 0; + } + + int enable = !strcmp(argv[3], "enable"); + Status status = mNetd->interfaceSetEnableIPv6(std::string(argv[2]), enable); + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to change IPv6 state", true); + } + return 0; + } else if (!strcmp(argv[1], "setmtu")) { + if (argc != 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: interface setmtu ", false); + return 0; + } + + int mtuValue = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[3], mtuValue, "Failed to set MTU", true); + Status status = mNetd->interfaceSetMtu(std::string(argv[2]), mtuValue); + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Failed to set MTU", true); + } + return 0; + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); + return 0; + } + } + return 0; +} + +NdcDispatcher::IpFwdCmd::IpFwdCmd() : NdcNetdCommand("ipfwd") {} + +int NdcDispatcher::IpFwdCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + bool matched = false; + Status status; + + if (argc == 2) { + // 0 1 + // ipfwd status + if (!strcmp(argv[1], "status")) { + bool ipfwdEnabled; + mNetd->ipfwdEnabled(&ipfwdEnabled); + std::string msg = StringPrintf("Forwarding %s", ipfwdEnabled ? "enabled" : "disabled"); + cli->sendMsg(ResponseCode::IpFwdStatusResult, msg.c_str(), false); + return 0; + } + } else if (argc == 3) { + // 0 1 2 + // ipfwd enable + // ipfwd disable + if (!strcmp(argv[1], "enable")) { + matched = true; + status = mNetd->ipfwdEnableForwarding(argv[2]); + } else if (!strcmp(argv[1], "disable")) { + matched = true; + status = mNetd->ipfwdDisableForwarding(argv[2]); + } + } else if (argc == 4) { + // 0 1 2 3 + // ipfwd add wlan0 dummy0 + // ipfwd remove wlan0 dummy0 + if (!strcmp(argv[1], "add")) { + matched = true; + status = mNetd->ipfwdAddInterfaceForward(argv[2], argv[3]); + } else if (!strcmp(argv[1], "remove")) { + matched = true; + status = mNetd->ipfwdRemoveInterfaceForward(argv[2], argv[3]); + } + } + + if (!matched) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false); + return 0; + } + + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true); + } + return 0; +} + +NdcDispatcher::TetherCmd::TetherCmd() : NdcNetdCommand("tether") {} + +int NdcDispatcher::TetherCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + Status status; + + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + if (!strcmp(argv[1], "stop")) { + status = mNetd->tetherStop(); + } else if (!strcmp(argv[1], "status")) { + bool tetherEnabled; + mNetd->tetherIsEnabled(&tetherEnabled); + std::string msg = + StringPrintf("Tethering services %s", tetherEnabled ? "started" : "stopped"); + cli->sendMsg(ResponseCode::TetherStatusResult, msg.c_str(), false); + return 0; + } else if (argc == 3) { + if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) { + std::vector ifList; + mNetd->tetherInterfaceList(&ifList); + for (const auto& ifname : ifList) { + cli->sendMsg(ResponseCode::TetherInterfaceListResult, ifname.c_str(), false); + } + } + } else if (!strcmp(argv[1], "start")) { + if (argc % 2 == 1) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false); + return 0; + } + + std::vector dhcpRanges; + // We do the checking of the pairs & addr invalidation in binderService/tetherController. + for (int arg_index = 2; arg_index < argc; arg_index++) { + dhcpRanges.push_back(argv[arg_index]); + } + + status = mNetd->tetherStart(dhcpRanges); + } else { + /* + * These commands take a minimum of 4 arguments + */ + if (argc < 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + if (!strcmp(argv[1], "interface")) { + if (!strcmp(argv[2], "add")) { + status = mNetd->tetherInterfaceAdd(argv[3]); + } else if (!strcmp(argv[2], "remove")) { + status = mNetd->tetherInterfaceRemove(argv[3]); + /* else if (!strcmp(argv[2], "list")) handled above */ + } else { + cli->sendMsg(ResponseCode::CommandParameterError, + "Unknown tether interface operation", false); + return 0; + } + } else if (!strcmp(argv[1], "dns")) { + if (!strcmp(argv[2], "set")) { + if (argc < 5) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + std::vector tetherDnsAddrs; + unsigned netId = stringToNetId(argv[3]); + for (int arg_index = 4; arg_index < argc; arg_index++) { + tetherDnsAddrs.push_back(argv[arg_index]); + } + status = mNetd->tetherDnsSet(netId, tetherDnsAddrs); + /* else if (!strcmp(argv[2], "list")) handled above */ + } else { + cli->sendMsg(ResponseCode::CommandParameterError, + "Unknown tether interface operation", false); + return 0; + } + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false); + return 0; + } + } + + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true); + } + + return 0; +} + +NdcDispatcher::NatCmd::NatCmd() : NdcNetdCommand("nat") {} + +int NdcDispatcher::NatCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + Status status; + + if (argc < 5) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + // 0 1 2 3 + // nat enable intiface extiface + // nat disable intiface extiface + if (!strcmp(argv[1], "enable") && argc >= 4) { + status = mNetd->tetherAddForward(argv[2], argv[3]); + } else if (!strcmp(argv[1], "disable") && argc >= 4) { + status = mNetd->tetherRemoveForward(argv[2], argv[3]); + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false); + return 0; + } + + if (status.isOk()) { + cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false); + } else { + errno = status.serviceSpecificErrorCode(); + cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true); + } + + return 0; +} + +NdcDispatcher::BandwidthControlCmd::BandwidthControlCmd() : NdcNetdCommand("bandwidth") {} + +void NdcDispatcher::BandwidthControlCmd::sendGenericSyntaxError(NdcClient* cli, + const char* usageMsg) const { + char* msg; + asprintf(&msg, "Usage: bandwidth %s", usageMsg); + cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false); + free(msg); +} + +void NdcDispatcher::BandwidthControlCmd::sendGenericOkFail(NdcClient* cli, int cond) const { + if (!cond) { + cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false); + } +} + +void NdcDispatcher::BandwidthControlCmd::sendGenericOpFailed(NdcClient* cli, + const char* errMsg) const { + cli->sendMsg(ResponseCode::OperationFailed, errMsg, false); +} + +int NdcDispatcher::BandwidthControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + if (argc < 2) { + sendGenericSyntaxError(cli, " "); + return 0; + } + + LOG(LOGLEVEL) << StringPrintf("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str(); + + if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) { + if (argc != 3) { + sendGenericSyntaxError(cli, "removeiquota "); + return 0; + } + int rc = !mNetd->bandwidthRemoveInterfaceQuota(argv[2]).isOk(); + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) { + if (argc != 4) { + sendGenericSyntaxError(cli, "setiquota "); + return 0; + } + int64_t bytes = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false); + int rc = !mNetd->bandwidthSetInterfaceQuota(argv[2], bytes).isOk(); + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) { + if (argc < 3) { + sendGenericSyntaxError(cli, "addnaughtyapps ..."); + return 0; + } + int rc = 0; + for (int arg_index = 2; arg_index < argc; arg_index++) { + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false); + rc = !mNetd->bandwidthAddNaughtyApp(uid).isOk(); + if (rc) break; + } + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) { + if (argc < 3) { + sendGenericSyntaxError(cli, "removenaughtyapps ..."); + return 0; + } + int rc = 0; + for (int arg_index = 2; arg_index < argc; arg_index++) { + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false); + rc = !mNetd->bandwidthRemoveNaughtyApp(uid).isOk(); + if (rc) break; + } + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) { + if (argc < 3) { + sendGenericSyntaxError(cli, "addniceapps ..."); + return 0; + } + int rc = 0; + for (int arg_index = 2; arg_index < argc; arg_index++) { + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false); + rc = !mNetd->bandwidthAddNiceApp(uid).isOk(); + if (rc) break; + } + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) { + if (argc < 3) { + sendGenericSyntaxError(cli, "removeniceapps ..."); + return 0; + } + int rc = 0; + for (int arg_index = 2; arg_index < argc; arg_index++) { + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[arg_index], uid, "Bandwidth command failed", false); + rc = !mNetd->bandwidthRemoveNiceApp(uid).isOk(); + if (rc) break; + } + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) { + if (argc != 3) { + sendGenericSyntaxError(cli, "setglobalalert "); + return 0; + } + int64_t bytes = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[2], bytes, "Bandwidth command failed", false); + int rc = !mNetd->bandwidthSetGlobalAlert(bytes).isOk(); + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) { + if (argc != 4) { + sendGenericSyntaxError(cli, "setinterfacealert "); + return 0; + } + int64_t bytes = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[3], bytes, "Bandwidth command failed", false); + int rc = !mNetd->bandwidthSetInterfaceAlert(argv[2], bytes).isOk(); + sendGenericOkFail(cli, rc); + return 0; + } + if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) { + if (argc != 3) { + sendGenericSyntaxError(cli, "removeinterfacealert "); + return 0; + } + int rc = !mNetd->bandwidthRemoveInterfaceAlert(argv[2]).isOk(); + sendGenericOkFail(cli, rc); + return 0; + } + + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false); + return 0; +} + +NdcDispatcher::IdletimerControlCmd::IdletimerControlCmd() : NdcNetdCommand("idletimer") {} + +int NdcDispatcher::IdletimerControlCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + // TODO(ashish): Change the error statements + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + LOG(LOGLEVEL) + << StringPrintf("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]).c_str(); + + if (!strcmp(argv[1], "add")) { + if (argc != 5) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + + int timeout = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to add interface", false); + Status status = mNetd->idletimerAddInterface(argv[2], timeout, argv[4]); + if (!status.isOk()) { + cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false); + } else { + cli->sendMsg(ResponseCode::CommandOkay, "Add success", false); + } + return 0; + } + if (!strcmp(argv[1], "remove")) { + if (argc != 5) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); + return 0; + } + int timeout = 0; + PARSE_INT_RETURN_IF_FAIL(cli, argv[3], timeout, "Failed to remove interface", false); + Status status = mNetd->idletimerRemoveInterface(argv[2], timeout, argv[4]); + if (!status.isOk()) { + cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false); + } else { + cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false); + } + return 0; + } + + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false); + return 0; +} + +NdcDispatcher::FirewallCmd::FirewallCmd() : NdcNetdCommand("firewall") {} + +int NdcDispatcher::FirewallCmd::sendGenericOkFail(NdcClient* cli, int cond) const { + if (!cond) { + cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false); + } + return 0; +} + +int NdcDispatcher::FirewallCmd::parseRule(const char* arg) { + if (!strcmp(arg, "allow")) { + return INetd::FIREWALL_RULE_ALLOW; + } else if (!strcmp(arg, "deny")) { + return INetd::FIREWALL_RULE_DENY; + } else { + LOG(LOGLEVEL) << "failed to parse uid rule " << arg; + return INetd::FIREWALL_RULE_ALLOW; + } +} + +int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) { + if (!strcmp(arg, "allowlist")) { + return INetd::FIREWALL_ALLOWLIST; + } else if (!strcmp(arg, "denylist")) { + return INetd::FIREWALL_DENYLIST; + } else { + LOG(LOGLEVEL) << "failed to parse firewall type " << arg; + return INetd::FIREWALL_DENYLIST; + } +} + +int NdcDispatcher::FirewallCmd::parseChildChain(const char* arg) { + if (!strcmp(arg, "dozable")) { + return INetd::FIREWALL_CHAIN_DOZABLE; + } else if (!strcmp(arg, "standby")) { + return INetd::FIREWALL_CHAIN_STANDBY; + } else if (!strcmp(arg, "powersave")) { + return INetd::FIREWALL_CHAIN_POWERSAVE; + } else if (!strcmp(arg, "restricted")) { + return INetd::FIREWALL_CHAIN_RESTRICTED; + } else if (!strcmp(arg, "none")) { + return INetd::FIREWALL_CHAIN_NONE; + } else { + LOG(LOGLEVEL) << "failed to parse child firewall chain " << arg; + return -1; + } +} + +int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false); + return 0; + } + + if (!strcmp(argv[1], "enable")) { + if (argc != 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: firewall enable ", false); + return 0; + } + int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk(); + return sendGenericOkFail(cli, res); + } + + if (!strcmp(argv[1], "set_interface_rule")) { + if (argc != 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: firewall set_interface_rule ", false); + return 0; + } + int res = !mNetd->firewallSetInterfaceRule(argv[2], parseRule(argv[3])).isOk(); + return sendGenericOkFail(cli, res); + } + + if (!strcmp(argv[1], "set_uid_rule")) { + if (argc != 5) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: firewall set_uid_rule <1000> ", + false); + return 0; + } + + int childChain = parseChildChain(argv[2]); + if (childChain == -1) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Invalid chain name. Valid names are: ", false); + return 0; + } + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[3], uid, "Firewall command failed", false); + int res = !mNetd->firewallSetUidRule(childChain, uid, parseRule(argv[4])).isOk(); + return sendGenericOkFail(cli, res); + } + + if (!strcmp(argv[1], "enable_chain")) { + if (argc != 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: firewall enable_chain ", false); + return 0; + } + int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), true).isOk(); + return sendGenericOkFail(cli, res); + } + + if (!strcmp(argv[1], "disable_chain")) { + if (argc != 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: firewall disable_chain ", false); + return 0; + } + int res = !mNetd->firewallEnableChildChain(parseChildChain(argv[2]), false).isOk(); + return sendGenericOkFail(cli, res); + } + + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false); + return 0; +} + +NdcDispatcher::StrictCmd::StrictCmd() : NdcNetdCommand("strict") {} + +int NdcDispatcher::StrictCmd::sendGenericOkFail(NdcClient* cli, int cond) const { + if (!cond) { + cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false); + } else { + cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false); + } + return 0; +} + +int NdcDispatcher::StrictCmd::parsePenalty(const char* arg) { + if (!strcmp(arg, "reject")) { + return INetd::PENALTY_POLICY_REJECT; + } else if (!strcmp(arg, "log")) { + return INetd::PENALTY_POLICY_LOG; + } else if (!strcmp(arg, "accept")) { + return INetd::PENALTY_POLICY_ACCEPT; + } else { + return -1; + } +} + +int NdcDispatcher::StrictCmd::runCommand(NdcClient* cli, int argc, char** argv) const { + if (argc < 2) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false); + return 0; + } + + if (!strcmp(argv[1], "set_uid_cleartext_policy")) { + if (argc != 4) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Usage: strict set_uid_cleartext_policy ", false); + return 0; + } + + errno = 0; + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[2], uid, "Invalid UID", false); + if (uid > UID_MAX) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false); + return 0; + } + + int penalty = parsePenalty(argv[3]); + if (penalty == -1) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false); + return 0; + } + + int res = !mNetd->strictUidCleartextPenalty(uid, penalty).isOk(); + return sendGenericOkFail(cli, res); + } + + cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false); + return 0; +} + +NdcDispatcher::NetworkCommand::NetworkCommand() : NdcNetdCommand("network") {} + +int NdcDispatcher::NetworkCommand::syntaxError(NdcClient* cli, const char* message) const { + cli->sendMsg(ResponseCode::CommandSyntaxError, message, false); + return 0; +} + +int NdcDispatcher::NetworkCommand::operationError(NdcClient* cli, const char* message, + int ret) const { + errno = ret; + cli->sendMsg(ResponseCode::OperationFailed, message, true); + return 0; +} + +int NdcDispatcher::NetworkCommand::success(NdcClient* cli) const { + cli->sendMsg(ResponseCode::CommandOkay, "success", false); + return 0; +} + +int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** argv) const { + if (argc < 2) { + return syntaxError(cli, "Missing argument"); + } + + // 0 1 2 3 4 5 6 7 8 + // network route [legacy ] add [nexthop] + // network route [legacy ] remove [nexthop] + // + // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw". + if (!strcmp(argv[1], "route")) { + if (argc < 6 || argc > 9) { + return syntaxError(cli, "Incorrect number of arguments"); + } + + int nextArg = 2; + bool legacy = false; + uid_t uid = 0; + if (!strcmp(argv[nextArg], "legacy")) { + ++nextArg; + legacy = true; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[nextArg++], uid, "Unknown argument", false); + } + + bool add = false; + if (!strcmp(argv[nextArg], "add")) { + add = true; + } else if (strcmp(argv[nextArg], "remove") != 0) { + return syntaxError(cli, "Unknown argument"); + } + ++nextArg; + + if (argc < nextArg + 3 || argc > nextArg + 4) { + return syntaxError(cli, "Incorrect number of arguments"); + } + + unsigned netId = stringToNetId(argv[nextArg++]); + const char* interface = argv[nextArg++]; + const char* destination = argv[nextArg++]; + const char* nexthop = argc > nextArg ? argv[nextArg] : ""; + + Status status; + if (legacy) { + status = add ? mNetd->networkAddLegacyRoute(netId, interface, destination, nexthop, uid) + + : mNetd->networkRemoveLegacyRoute(netId, interface, destination, nexthop, + uid); + } else { + status = add ? mNetd->networkAddRoute(netId, interface, destination, nexthop) + : mNetd->networkRemoveRoute(netId, interface, destination, nexthop); + } + + if (!status.isOk()) { + return operationError(cli, add ? "addRoute() failed" : "removeRoute() failed", + status.serviceSpecificErrorCode()); + } + + return success(cli); + } + + // 0 1 2 3 4 + // network interface add + // network interface remove + if (!strcmp(argv[1], "interface")) { + if (argc != 5) { + return syntaxError(cli, "Missing argument"); + } + unsigned netId = stringToNetId(argv[3]); + if (!strcmp(argv[2], "add")) { + if (Status status = mNetd->networkAddInterface(netId, argv[4]); !status.isOk()) { + return operationError(cli, "addInterfaceToNetwork() failed", + status.serviceSpecificErrorCode()); + } + } else if (!strcmp(argv[2], "remove")) { + if (Status status = mNetd->networkRemoveInterface(netId, argv[4]); !status.isOk()) { + return operationError(cli, "removeInterfaceFromNetwork() failed", + status.serviceSpecificErrorCode()); + } + } else { + return syntaxError(cli, "Unknown argument"); + } + return success(cli); + } + + // 0 1 2 3 + // network create [permission] + // + // 0 1 2 3 4 + // network create vpn + if (!strcmp(argv[1], "create")) { + if (argc < 3) { + return syntaxError(cli, "Missing argument"); + } + unsigned netId = stringToNetId(argv[2]); + if (argc == 5 && !strcmp(argv[3], "vpn")) { + bool secure = strtol(argv[4], nullptr, 2); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) { +#pragma clang diagnostic pop + return operationError(cli, "createVirtualNetwork() failed", + status.serviceSpecificErrorCode()); + } + } else if (argc > 4) { + return syntaxError(cli, "Unknown trailing argument(s)"); + } else { + int permission = INetd::PERMISSION_NONE; + if (argc == 4) { + permission = stringToINetdPermission(argv[3]); + if (permission == INetd::PERMISSION_NONE) { + return syntaxError(cli, "Unknown permission"); + } + } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) { +#pragma clang diagnostic pop + return operationError(cli, "createPhysicalNetwork() failed", + status.serviceSpecificErrorCode()); + } + } + return success(cli); + } + + // 0 1 2 + // network destroy + if (!strcmp(argv[1], "destroy")) { + if (argc != 3) { + return syntaxError(cli, "Incorrect number of arguments"); + } + unsigned netId = stringToNetId(argv[2]); + // Both of these functions manage their own locking internally. + if (Status status = mNetd->networkDestroy(netId); !status.isOk()) { + return operationError(cli, "destroyNetwork() failed", + status.serviceSpecificErrorCode()); + } + mDnsResolver->destroyNetworkCache(netId); + return success(cli); + } + + // 0 1 2 3 + // network default set + // network default clear + if (!strcmp(argv[1], "default")) { + if (argc < 3) { + return syntaxError(cli, "Missing argument"); + } + unsigned netId = NETID_UNSET; + if (!strcmp(argv[2], "set")) { + if (argc < 4) { + return syntaxError(cli, "Missing netId"); + } + netId = stringToNetId(argv[3]); + } else if (strcmp(argv[2], "clear") != 0) { + return syntaxError(cli, "Unknown argument"); + } + if (Status status = mNetd->networkSetDefault(netId); !status.isOk()) { + return operationError(cli, "setDefaultNetwork() failed", + status.serviceSpecificErrorCode()); + } + return success(cli); + } + + // 0 1 2 3 4 5 + // network permission user set ... + // network permission user clear ... + // network permission network set ... + // network permission network clear ... + if (!strcmp(argv[1], "permission")) { + if (argc < 5) { + return syntaxError(cli, "Missing argument"); + } + int nextArg = 4; + int permission = INetd::PERMISSION_NONE; + if (!strcmp(argv[3], "set")) { + permission = stringToINetdPermission(argv[4]); + if (permission == INetd::PERMISSION_NONE) { + return syntaxError(cli, "Unknown permission"); + } + nextArg = 5; + } else if (strcmp(argv[3], "clear") != 0) { + return syntaxError(cli, "Unknown argument"); + } + if (nextArg == argc) { + return syntaxError(cli, "Missing id"); + } + + bool userPermissions = !strcmp(argv[2], "user"); + bool networkPermissions = !strcmp(argv[2], "network"); + if (!userPermissions && !networkPermissions) { + return syntaxError(cli, "Unknown argument"); + } + + std::vector ids; + for (; nextArg < argc; ++nextArg) { + if (userPermissions) { + char* endPtr; + unsigned id = strtoul(argv[nextArg], &endPtr, 0); + if (!*argv[nextArg] || *endPtr) { + return syntaxError(cli, "Invalid id"); + } + ids.push_back(id); + } else { + // networkPermissions + ids.push_back(stringToNetId(argv[nextArg])); + } + } + if (userPermissions) { + mNetd->networkSetPermissionForUser(permission, ids); + } else { + // networkPermissions + for (auto netId : ids) { + Status status = mNetd->networkSetPermissionForNetwork(netId, permission); + if (!status.isOk()) + return operationError(cli, "setPermissionForNetworks() failed", + status.serviceSpecificErrorCode()); + } + } + + return success(cli); + } + + // 0 1 2 3 4 + // network users add [[-]] ... + // network users remove [[-]] ... + if (!strcmp(argv[1], "users")) { + if (argc < 4) { + return syntaxError(cli, "Missing argument"); + } + unsigned netId = stringToNetId(argv[3]); + UidRanges uidRanges; + if (!uidRanges.parseFrom(argc - 4, argv + 4)) { + return syntaxError(cli, "Invalid UIDs"); + } + if (!strcmp(argv[2], "add")) { + if (Status status = mNetd->networkAddUidRanges(netId, uidRanges.getRanges()); + !status.isOk()) { + return operationError(cli, "addUsersToNetwork() failed", + status.serviceSpecificErrorCode()); + } + } else if (!strcmp(argv[2], "remove")) { + if (Status status = mNetd->networkRemoveUidRanges(netId, uidRanges.getRanges()); + !status.isOk()) { + return operationError(cli, "removeUsersFromNetwork() failed", + status.serviceSpecificErrorCode()); + } + } else { + return syntaxError(cli, "Unknown argument"); + } + return success(cli); + } + + // 0 1 2 3 + // network protect allow ... + // network protect deny ... + if (!strcmp(argv[1], "protect")) { + if (argc < 4) { + return syntaxError(cli, "Missing argument"); + } + std::vector uids; + for (int i = 3; i < argc; ++i) { + uid_t uid = 0; + PARSE_UINT_RETURN_IF_FAIL(cli, argv[i], uid, "Unknown argument", false); + uids.push_back(uid); + } + if (!strcmp(argv[2], "allow")) { + for (auto uid : uids) { + mNetd->networkSetProtectAllow(uid); + } + } else if (!strcmp(argv[2], "deny")) { + for (auto uid : uids) { + mNetd->networkSetProtectDeny(uid); + } + } else { + return syntaxError(cli, "Unknown argument"); + } + return success(cli); + } + + return syntaxError(cli, "Unknown argument"); +} + +NdcDispatcher::ResolveCommand::ResolveCommand() : NdcNetdCommand("resolver") {} + +int NdcDispatcher::ResolveCommand::runCommand(NdcClient *cli, int argc, char** argv) const { + if (argc < 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false); + return 0; + } + + if (!strcmp(argv[1], "setnetdns")) { + struct ResolverParams params; + params.netId = stringToNetId(argv[2]); + if (!parseParams(argc, argv, params) || !setNetDns(params)) { + cli->sendMsg(ResponseCode::CommandSyntaxError, + "Wrong number of or invalid arguments to resolver setnetdns", false); + return 0; + } + } else { + cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false); + return 0; + } + + cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false); + return 0; +} + +bool NdcDispatcher::ResolveCommand::parseParams(int argc, char** argv, + struct ResolverParams& params) const { + // "resolver setnetdns [ ...] [--params ]" + if (argc < 5) { + return false; + } + + // Parse domains, eg: "example.com test.org ." + const char* domainsStr = argv[3]; + if (domainsStr != nullptr) { + std::string domain; + for (int i = 0; domainsStr[i] != '\0'; ++i) { + char c = domainsStr[i]; + if (std::isspace(static_cast(c))) { + if (!domain.empty()) { + params.domains.push_back(domain); + domain.clear(); + } + } else { + domain += c; + } + } + if (!domain.empty()) { + params.domains.push_back(domain); + } + } + + // Without resolver params by default + params.sampleValidity = -1; + + // Parse other params + for (int index = 4, end = argc - 1; index <= end; index++) { + // Parse resolver params, eg: --params "1800 25 8 64" + if (strcmp(argv[index], "--params") == 0) { + if (end - index != 1 || + sscanf(argv[end], "%u %u %u %u", ¶ms.sampleValidity, + ¶ms.successThreshold, ¶ms.minSamples, ¶ms.maxSamples) != 4) { + return false; + } + break; + } + + // Parse dns servers, eg: [ ...] + params.servers.push_back(argv[index]); + } + + return params.servers.size() > 0 && params.servers.size() <= 4; +} + +bool NdcDispatcher::ResolveCommand::setNetDns(const struct ResolverParams& params) const { + ResolverParamsParcel paramsParcel; + paramsParcel.netId = params.netId; + if (params.sampleValidity != -1) { + paramsParcel.sampleValiditySeconds = params.sampleValidity; + paramsParcel.successThreshold = params.successThreshold; + paramsParcel.minSamples = params.minSamples; + paramsParcel.maxSamples = params.maxSamples; + } else { + // Set default resolver configuration, @see DefaultSettings.cpp + paramsParcel.sampleValiditySeconds = 1800; + paramsParcel.successThreshold = 25; + paramsParcel.minSamples = 8; + paramsParcel.maxSamples = 64; + } + paramsParcel.baseTimeoutMsec = 1000; + paramsParcel.retryCount = 2; + paramsParcel.domains = params.domains; + paramsParcel.servers = params.servers; + + mDnsResolver->flushNetworkCache(params.netId); + + return mDnsResolver->setResolverConfiguration(paramsParcel).isOk(); +} + +} // namespace net +} // namespace android diff --git a/aosp/system/netd/server/NdcDispatcher.h b/aosp/system/netd/server/NdcDispatcher.h new file mode 100644 index 000000000..d7f2bcb07 --- /dev/null +++ b/aosp/system/netd/server/NdcDispatcher.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef _NDC_DISPATCHER_H__ +#define _NDC_DISPATCHER_H__ + +#include + +#include +#include +#include +#include "binder/IServiceManager.h" + +#include "NetdConstants.h" + +namespace android { +namespace net { + +class NdcClient { + public: + NdcClient() = default; + ~NdcClient() = default; + + int sendMsg(int code, const char* msg, bool addErrno) { + if (addErrno) { + printf("%d 0 %s (%s)\n", code, msg, strerror(errno)); + } else { + printf("%d 0 %s\n", code, msg); + } + return 0; + } +}; + +class NdcNetdCommand { + public: + NdcNetdCommand(std::string cmd) : mCommand(std::move(cmd)) {} + virtual ~NdcNetdCommand() {} + + virtual int runCommand(NdcClient* c, int argc, char** argv) const = 0; + + const std::string& getCommand() const { return mCommand; } + + private: + std::string mCommand; +}; + +class NdcDispatcher { + public: + // Matches the restrictions previously imposed by CommandListener.cpp. + static const int CMD_ARGS_MAX = 26; + // Default log level is set to minimum one. + static const android::base::LogSeverity LOGLEVEL = android::base::VERBOSE; + + NdcDispatcher(); + ~NdcDispatcher() = default; + + static sp mNetd; + static sp mDnsResolver; + NdcClient mNdc; + + int dispatchCommand(int argc, char** argv); + void registerCmd(NdcNetdCommand* cmd); + + private: + std::vector mCommands; + + class InterfaceCmd : public NdcNetdCommand { + public: + InterfaceCmd(); + virtual ~InterfaceCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + }; + + class IpFwdCmd : public NdcNetdCommand { + public: + IpFwdCmd(); + virtual ~IpFwdCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + }; + + class TetherCmd : public NdcNetdCommand { + public: + TetherCmd(); + virtual ~TetherCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + }; + + class NatCmd : public NdcNetdCommand { + public: + NatCmd(); + virtual ~NatCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + }; + + class BandwidthControlCmd : public NdcNetdCommand { + public: + BandwidthControlCmd(); + virtual ~BandwidthControlCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + + protected: + void sendGenericOkFail(NdcClient* cli, int cond) const; + void sendGenericOpFailed(NdcClient* cli, const char* errMsg) const; + void sendGenericSyntaxError(NdcClient* cli, const char* usageMsg) const; + }; + + class IdletimerControlCmd : public NdcNetdCommand { + public: + IdletimerControlCmd(); + virtual ~IdletimerControlCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + }; + + class FirewallCmd : public NdcNetdCommand { + public: + FirewallCmd(); + virtual ~FirewallCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + + protected: + int sendGenericOkFail(NdcClient* cli, int cond) const; + static int parseRule(const char* arg); + static int parseFirewallType(const char* arg); + static int parseChildChain(const char* arg); + }; + + class StrictCmd : public NdcNetdCommand { + public: + StrictCmd(); + virtual ~StrictCmd() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + + protected: + int sendGenericOkFail(NdcClient* cli, int cond) const; + static int parsePenalty(const char* arg); + }; + + class NetworkCommand : public NdcNetdCommand { + public: + NetworkCommand(); + virtual ~NetworkCommand() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + + private: + int syntaxError(NdcClient* cli, const char* message) const; + int operationError(NdcClient* cli, const char* message, int ret) const; + int success(NdcClient* cli) const; + }; + + class ResolveCommand : public NdcNetdCommand { + public: + ResolveCommand(); + virtual ~ResolveCommand() {} + int runCommand(NdcClient* cli, int argc, char** argv) const; + + private: + struct ResolverParams { + unsigned netId; + std::vector domains; + std::vector servers; + int sampleValidity; // sample lifetime in s + // threshold of success / total samples below which a server is considered broken + int successThreshold; // 0: disable, value / 100 otherwise + int minSamples; // min # samples needed for statistics to be considered meaningful + int maxSamples; // max # samples taken into account for statistics + }; + bool parseParams(int argc, char** argv, struct ResolverParams& params) const; + bool setNetDns(const struct ResolverParams& params) const; + }; +}; + +} // namespace net +} // namespace android + +#endif -- Gitee