/* * Copyright (C) 2008 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 _TETHER_CONTROLLER_H #define _TETHER_CONTROLLER_H #include #include #include #include #include #include #include "NetdConstants.h" #include "android-base/result.h" #include "bpf/BpfMap.h" #include "netdbpf/bpf_shared.h" #include "android/net/TetherOffloadRuleParcel.h" namespace android { namespace net { class TetherController { private: struct ForwardingDownstream { std::string iface; bool active; }; std::list mInterfaces; // Map upstream iface -> downstream iface. A pair is in the map if forwarding was enabled at // some point since the controller was initialized. std::multimap mFwdIfaces; bool mIsTetheringStarted = false; // NetId to use for forwarded DNS queries. This may not be the default // network, e.g., in the case where we are tethering to a DUN APN. unsigned mDnsNetId = 0; std::list mDnsForwarders; pid_t mDaemonPid = 0; int mDaemonFd = -1; std::set mForwardingRequests; struct DnsmasqState { static int sendCmd(int daemonFd, const std::string& cmd); // List of downstream interfaces on which to serve. The format used is: // update_ifaces|||... std::string update_ifaces_cmd; // Forwarding (upstream) DNS configuration to use. The format used is: // update_dns||||... std::string update_dns_cmd; void clear(); int sendAllState(int daemonFd) const; } mDnsmasqState{}; // BPF maps, initialized by maybeInitMaps. bpf::BpfMap mBpfIngressMap; bpf::BpfMap mBpfStatsMap; bpf::BpfMap mBpfLimitMap; public: TetherController(); ~TetherController() = default; bool enableForwarding(const char* requester); bool disableForwarding(const char* requester); const std::set& getIpfwdRequesterList() const; //TODO: Clean up the overload function int startTethering(bool isLegacyDnsProxy, int num_addrs, char** dhcp_ranges); int startTethering(bool isLegacyDnsProxy, const std::vector& dhcpRanges); int stopTethering(); bool isTetheringStarted(); unsigned getDnsNetId(); int setDnsForwarders(unsigned netId, char **servers, int numServers); int setDnsForwarders(unsigned netId, const std::vector& servers); const std::list &getDnsForwarders() const; int tetherInterface(const char *interface); int untetherInterface(const char *interface); const std::list &getTetheredInterfaceList() const; bool applyDnsInterfaces(); int enableNat(const char* intIface, const char* extIface); int disableNat(const char* intIface, const char* extIface); int setupIptablesHooks(); base::Result addOffloadRule(const TetherOffloadRuleParcel& rule); base::Result removeOffloadRule(const TetherOffloadRuleParcel& rule); int setTetherOffloadInterfaceQuota(int ifIndex, int64_t maxBytes); class TetherStats { public: TetherStats() = default; TetherStats(std::string intIfn, std::string extIfn, int64_t rxB, int64_t rxP, int64_t txB, int64_t txP) : intIface(intIfn), extIface(extIfn), rxBytes(rxB), rxPackets(rxP), txBytes(txB), txPackets(txP) {}; std::string intIface; std::string extIface; int64_t rxBytes = -1; int64_t rxPackets = -1; int64_t txBytes = -1; int64_t txPackets = -1; bool addStatsIfMatch(const TetherStats& other) { if (intIface == other.intIface && extIface == other.extIface) { rxBytes += other.rxBytes; rxPackets += other.rxPackets; txBytes += other.txBytes; txPackets += other.txPackets; return true; } return false; } }; struct TetherOffloadStats { int ifIndex; int64_t rxBytes; int64_t rxPackets; int64_t txBytes; int64_t txPackets; }; typedef std::vector TetherStatsList; typedef std::vector TetherOffloadStatsList; netdutils::StatusOr getTetherStats(); netdutils::StatusOr getTetherOffloadStats(); base::Result getAndClearTetherOffloadStats(int ifIndex); /* * extraProcessingInfo: contains raw parsed data, and error info. * This strongly requires that setup of the rules is in a specific order: * in:intIface out:extIface * in:extIface out:intIface * and the rules are grouped in pairs when more that one tethering was setup. */ static int addForwardChainStats(TetherStatsList& statsList, const std::string& iptOutput, std::string &extraProcessingInfo); static constexpr const char* LOCAL_FORWARD = "tetherctrl_FORWARD"; static constexpr const char* LOCAL_MANGLE_FORWARD = "tetherctrl_mangle_FORWARD"; static constexpr const char* LOCAL_NAT_POSTROUTING = "tetherctrl_nat_POSTROUTING"; static constexpr const char* LOCAL_RAW_PREROUTING = "tetherctrl_raw_PREROUTING"; static constexpr const char* LOCAL_TETHER_COUNTERS_CHAIN = "tetherctrl_counters"; std::mutex lock; void dump(netdutils::DumpWriter& dw); void dumpIfaces(netdutils::DumpWriter& dw); void dumpBpf(netdutils::DumpWriter& dw); private: bool setIpFwdEnabled(); std::vector toCstrVec(const std::vector& addrs); int setupIPv6CountersChain(); static std::string makeTetherCountingRule(const char *if1, const char *if2); ForwardingDownstream* findForwardingDownstream(const std::string& intIface, const std::string& extIface); void addForwardingPair(const std::string& intIface, const std::string& extIface); void markForwardingPairDisabled(const std::string& intIface, const std::string& extIface); bool isForwardingPairEnabled(const std::string& intIface, const std::string& extIface); bool isAnyForwardingEnabledOnUpstream(const std::string& extIface); bool isAnyForwardingPairEnabled(); bool tetherCountingRuleExists(const std::string& iface1, const std::string& iface2); int setDefaults(); int setTetherGlobalAlertRule(); int setForwardRules(bool set, const char *intIface, const char *extIface); int setTetherCountingRules(bool add, const char *intIface, const char *extIface); base::Result setBpfLimit(uint32_t ifIndex, uint64_t limit); void maybeInitMaps(); void maybeStartBpf(const char* extIface); void maybeStopBpf(const char* extIface); static void addStats(TetherStatsList& statsList, const TetherStats& stats); // For testing. friend class TetherControllerTest; static int (*iptablesRestoreFunction)(IptablesTarget, const std::string&, std::string *); }; } // namespace net } // namespace android #endif