1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef _BANDWIDTH_CONTROLLER_H
17#define _BANDWIDTH_CONTROLLER_H
18
19#include <map>
20#include <set>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include <sysutils/SocketClient.h>
26#include <utils/RWLock.h>
27
28#include "NetdConstants.h"
29
30class BandwidthController {
31public:
32    android::RWLock lock;
33
34    class TetherStats {
35    public:
36        TetherStats() = default;
37        TetherStats(std::string intIfn, std::string extIfn,
38                int64_t rxB, int64_t rxP,
39                int64_t txB, int64_t txP)
40                        : intIface(intIfn), extIface(extIfn),
41                            rxBytes(rxB), rxPackets(rxP),
42                            txBytes(txB), txPackets(txP) {};
43        /* Internal interface. Same as NatController's notion. */
44        std::string intIface;
45        /* External interface. Same as NatController's notion. */
46        std::string extIface;
47        int64_t rxBytes = -1;
48        int64_t rxPackets = -1;
49        int64_t txBytes = -1;
50        int64_t txPackets = -1;
51        /*
52         * Allocates a new string representing this:
53         * intIface extIface rx_bytes rx_packets tx_bytes tx_packets
54         * The caller is responsible for free()'ing the returned ptr.
55         */
56        std::string getStatsLine() const;
57
58        bool addStatsIfMatch(const TetherStats& other) {
59            if (intIface == other.intIface && extIface == other.extIface) {
60                rxBytes   += other.rxBytes;
61                rxPackets += other.rxPackets;
62                txBytes   += other.txBytes;
63                txPackets += other.txPackets;
64                return true;
65            }
66            return false;
67        }
68    };
69
70    BandwidthController();
71
72    int setupIptablesHooks();
73
74    int enableBandwidthControl(bool force);
75    int disableBandwidthControl();
76    int enableDataSaver(bool enable);
77
78    int setInterfaceSharedQuota(const std::string& iface, int64_t bytes);
79    int getInterfaceSharedQuota(int64_t *bytes);
80    int removeInterfaceSharedQuota(const std::string& iface);
81
82    int setInterfaceQuota(const std::string& iface, int64_t bytes);
83    int getInterfaceQuota(const std::string& iface, int64_t* bytes);
84    int removeInterfaceQuota(const std::string& iface);
85
86    int addNaughtyApps(int numUids, char *appUids[]);
87    int removeNaughtyApps(int numUids, char *appUids[]);
88    int addNiceApps(int numUids, char *appUids[]);
89    int removeNiceApps(int numUids, char *appUids[]);
90
91    int setGlobalAlert(int64_t bytes);
92    int removeGlobalAlert();
93    int setGlobalAlertInForwardChain();
94    int removeGlobalAlertInForwardChain();
95
96    int setSharedAlert(int64_t bytes);
97    int removeSharedAlert();
98
99    int setInterfaceAlert(const std::string& iface, int64_t bytes);
100    int removeInterfaceAlert(const std::string& iface);
101
102    /*
103     * For single pair of ifaces, stats should have ifaceIn and ifaceOut initialized.
104     * For all pairs, stats should have ifaceIn=ifaceOut="".
105     * Sends out to the cli the single stat (TetheringStatsReluts) or a list of stats
106     * (TetheringStatsListResult+CommandOkay).
107     * Error is to be handled on the outside.
108     * It results in an error if invoked and no tethering counter rules exist.
109     */
110    int getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo);
111
112    static const char LOCAL_INPUT[];
113    static const char LOCAL_FORWARD[];
114    static const char LOCAL_OUTPUT[];
115    static const char LOCAL_RAW_PREROUTING[];
116    static const char LOCAL_MANGLE_POSTROUTING[];
117
118  private:
119    struct QuotaInfo {
120        int64_t quota;
121        int64_t alert;
122    };
123
124    enum IptIpVer { IptIpV4, IptIpV6 };
125    enum IptFullOp { IptFullOpInsert, IptFullOpDelete, IptFullOpAppend };
126    enum IptJumpOp { IptJumpReject, IptJumpReturn, IptJumpNoAdd };
127    enum IptOp { IptOpInsert, IptOpDelete };
128    enum QuotaType { QuotaUnique, QuotaShared };
129    enum RunCmdErrHandling { RunCmdFailureBad, RunCmdFailureOk };
130#if LOG_NDEBUG
131    enum IptFailureLog { IptFailShow, IptFailHide };
132#else
133    enum IptFailureLog { IptFailShow, IptFailHide = IptFailShow };
134#endif
135
136    std::string makeDataSaverCommand(IptablesTarget target, bool enable);
137
138    int manipulateSpecialApps(const std::vector<std::string>& appStrUids, const std::string& chain,
139                              IptJumpOp jumpHandling, IptOp appOp);
140
141    int runIptablesAlertCmd(IptOp op, const std::string& alertName, int64_t bytes);
142    int runIptablesAlertFwdCmd(IptOp op, const std::string& alertName, int64_t bytes);
143
144    int updateQuota(const std::string& alertName, int64_t bytes);
145
146    int setCostlyAlert(const std::string& costName, int64_t bytes, int64_t* alertBytes);
147    int removeCostlyAlert(const std::string& costName, int64_t* alertBytes);
148
149    typedef std::vector<TetherStats> TetherStatsList;
150
151    static void addStats(TetherStatsList& statsList, const TetherStats& stats);
152
153    /*
154     * stats should never have only intIface initialized. Other 3 combos are ok.
155     * fp should be a file to the apropriate FORWARD chain of iptables rules.
156     * extraProcessingInfo: contains raw parsed data, and error info.
157     * This strongly requires that setup of the rules is in a specific order:
158     *  in:intIface out:extIface
159     *  in:extIface out:intIface
160     * and the rules are grouped in pairs when more that one tethering was setup.
161     */
162    static int addForwardChainStats(const TetherStats& filter,
163                                    TetherStatsList& statsList, const std::string& iptOutput,
164                                    std::string &extraProcessingInfo);
165
166    /*
167     * Attempt to find the bw_costly_* tables that need flushing,
168     * and flush them.
169     * If doClean then remove the tables also.
170     * Deals with both ip4 and ip6 tables.
171     */
172    void flushExistingCostlyTables(bool doClean);
173    static void parseAndFlushCostlyTables(const std::string& ruleList, bool doRemove);
174
175    /*
176     * Attempt to flush our tables.
177     * If doClean then remove them also.
178     * Deals with both ip4 and ip6 tables.
179     */
180    void flushCleanTables(bool doClean);
181
182    // For testing.
183    friend class BandwidthControllerTest;
184    static int (*execFunction)(int, char **, int *, bool, bool);
185    static FILE *(*popenFunction)(const char *, const char *);
186    static int (*iptablesRestoreFunction)(IptablesTarget, const std::string&, std::string *);
187
188    static const char *opToString(IptOp op);
189    static const char *jumpToString(IptJumpOp jumpHandling);
190
191    int64_t mSharedQuotaBytes = 0;
192    int64_t mSharedAlertBytes = 0;
193    int64_t mGlobalAlertBytes = 0;
194    /*
195     * This tracks the number of tethers setup.
196     * The FORWARD chain is updated in the following cases:
197     *  - The 1st time a globalAlert is setup and there are tethers setup.
198     *  - Anytime a globalAlert is removed and there are tethers setup.
199     *  - The 1st tether is setup and there is a globalAlert active.
200     *  - The last tether is removed and there is a globalAlert active.
201     */
202    int mGlobalAlertTetherCount = 0;
203
204    std::map<std::string, QuotaInfo> mQuotaIfaces;
205    std::set<std::string> mSharedQuotaIfaces;
206};
207
208#endif
209