OSDN Git Service

Make netd track and notify IP address changes.
[android-x86/system-netd.git] / BandwidthController.cpp
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
17 // #define LOG_NDEBUG 0
18
19 /*
20  * The CommandListener, FrameworkListener don't allow for
21  * multiple calls in parallel to reach the BandwidthController.
22  * If they ever were to allow it, then netd/ would need some tweaking.
23  */
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <linux/netlink.h>
37 #include <linux/rtnetlink.h>
38 #include <linux/pkt_sched.h>
39
40 #define LOG_TAG "BandwidthController"
41 #include <cutils/log.h>
42 #include <cutils/properties.h>
43 #include <logwrap/logwrap.h>
44
45 #include "NetdConstants.h"
46 #include "BandwidthController.h"
47 #include "NatController.h"  /* For LOCAL_TETHER_COUNTERS_CHAIN */
48 #include "ResponseCode.h"
49
50 /* Alphabetical */
51 #define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %lld --name %s"
52 const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
53 const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
54 const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
55 const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
56 const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
57 const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
58 const int  BandwidthController::MAX_CMD_ARGS = 32;
59 const int  BandwidthController::MAX_CMD_LEN = 1024;
60 const int  BandwidthController::MAX_IFACENAME_LEN = 64;
61 const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
62
63 /**
64  * Some comments about the rules:
65  *  * Ordering
66  *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
67  *      E.g. "-I bw_INPUT -i rmnet0 --jump costly"
68  *    - quota'd rules in the costly chain should be before bw_penalty_box lookups.
69  *    - bw_happy_box rejects everything by default.
70  *    - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
71  *
72  * * global quota vs per interface quota
73  *   - global quota for all costly interfaces uses a single costly chain:
74  *    . initial rules
75  *      iptables -N bw_costly_shared
76  *      iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
77  *      iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
78  *      iptables -I bw_costly_shared -m quota \! --quota 500000 \
79  *          --jump REJECT --reject-with icmp-net-prohibited
80  *      iptables -A bw_costly_shared --jump bw_penalty_box
81  *      If the happy box is enabled,
82  *        iptables -A bw_penalty_box --jump bw_happy_box
83  *
84  *    . adding a new iface to this, E.g.:
85  *      iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
86  *      iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
87  *
88  *   - quota per interface. This is achieve by having "costly" chains per quota.
89  *     E.g. adding a new costly interface iface0 with its own quota:
90  *      iptables -N bw_costly_iface0
91  *      iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
92  *      iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
93  *      iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
94  *          --jump REJECT --reject-with icmp-port-unreachable
95  *      iptables -A bw_costly_iface0 --jump bw_penalty_box
96  *
97  * * bw_penalty_box handling:
98  *  - only one bw_penalty_box for all interfaces
99  *   E.g  Adding an app, it has to preserve the appened bw_happy_box, so "-I":
100  *    iptables -I bw_penalty_box -m owner --uid-owner app_3 \
101  *        --jump REJECT --reject-with icmp-port-unreachable
102  *
103  * * bw_happy_box handling:
104  *  - The bw_happy_box goes at the end of the penalty box.
105  *   E.g  Adding a happy app,
106  *    iptables -I bw_happy_box -m owner --uid-owner app_3 \
107  *        --jump RETURN
108  */
109 const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
110     /*
111      * Cleanup rules.
112      * Should normally include bw_costly_<iface>, but we rely on the way they are setup
113      * to allow coexistance.
114      */
115     "-F bw_INPUT",
116     "-F bw_OUTPUT",
117     "-F bw_FORWARD",
118     "-F bw_happy_box",
119     "-F bw_penalty_box",
120     "-F bw_costly_shared",
121
122     /* Just a couple that are the most common. */
123     "-F bw_costly_rmnet0",
124     "-F bw_costly_wlan0",
125
126     "-t raw -F bw_raw_PREROUTING",
127     "-t mangle -F bw_mangle_POSTROUTING",
128 };
129
130 /* The cleanup commands assume flushing has been done. */
131 const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
132     "-X bw_happy_box",
133     "-X bw_penalty_box",
134     "-X bw_costly_shared",
135
136     /* Just a couple that are the most common. */
137     "-X bw_costly_rmnet0",
138     "-X bw_costly_wlan0",
139 };
140
141 const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
142     "-N bw_happy_box",
143     "-N bw_penalty_box",
144     "-N bw_costly_shared",
145 };
146
147 const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
148     "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
149
150     "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
151
152     "-A bw_costly_shared --jump bw_penalty_box",
153
154     "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
155     "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
156 };
157
158 BandwidthController::BandwidthController(void) {
159 }
160
161 int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
162                                          IptFailureLog failureHandling) {
163     int res = 0;
164
165     ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
166     res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
167     res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
168     return res;
169 }
170
171 int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
172
173     memset(buffer, '\0', buffSize);  // strncpy() is not filling leftover with '\0'
174     strncpy(buffer, src, buffSize);
175     return buffer[buffSize - 1];
176 }
177
178 int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
179                                         IptIpVer iptVer, IptFailureLog failureHandling) {
180     char buffer[MAX_CMD_LEN];
181     const char *argv[MAX_CMD_ARGS];
182     int argc = 0;
183     char *next = buffer;
184     char *tmp;
185     int res;
186     int status = 0;
187
188     std::string fullCmd = cmd;
189
190     switch (jumpHandling) {
191     case IptJumpReject:
192         /*
193          * Must be carefull what one rejects with, as uper layer protocols will just
194          * keep on hammering the device until the number of retries are done.
195          * For port-unreachable (default), TCP should consider as an abort (RFC1122).
196          */
197         fullCmd += " --jump REJECT";
198         break;
199     case IptJumpReturn:
200         fullCmd += " --jump RETURN";
201         break;
202     case IptJumpNoAdd:
203         break;
204     }
205
206     fullCmd.insert(0, " ");
207     fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
208
209     if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
210         ALOGE("iptables command too long");
211         return -1;
212     }
213
214     argc = 0;
215     while ((tmp = strsep(&next, " "))) {
216         argv[argc++] = tmp;
217         if (argc >= MAX_CMD_ARGS) {
218             ALOGE("iptables argument overflow");
219             return -1;
220         }
221     }
222
223     argv[argc] = NULL;
224     res = android_fork_execvp(argc, (char **)argv, &status, false,
225             failureHandling == IptFailShow);
226     res = res || !WIFEXITED(status) || WEXITSTATUS(status);
227     if (res && failureHandling == IptFailShow) {
228       ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
229             fullCmd.c_str());
230     }
231     return res;
232 }
233
234 int BandwidthController::setupIptablesHooks(void) {
235
236     /* Some of the initialCommands are allowed to fail */
237     runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
238             IPT_FLUSH_COMMANDS, RunCmdFailureOk);
239
240     runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
241             IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
242
243     runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
244             IPT_SETUP_COMMANDS, RunCmdFailureBad);
245
246     return 0;
247 }
248
249 int BandwidthController::enableBandwidthControl(bool force) {
250     int res;
251     char value[PROPERTY_VALUE_MAX];
252
253     if (!force) {
254             property_get("persist.bandwidth.enable", value, "1");
255             if (!strcmp(value, "0"))
256                     return 0;
257     }
258
259     /* Let's pretend we started from scratch ... */
260     sharedQuotaIfaces.clear();
261     quotaIfaces.clear();
262     naughtyAppUids.clear();
263     niceAppUids.clear();
264     globalAlertBytes = 0;
265     globalAlertTetherCount = 0;
266     sharedQuotaBytes = sharedAlertBytes = 0;
267
268     res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
269             IPT_FLUSH_COMMANDS, RunCmdFailureOk);
270
271     res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
272             IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
273
274     return res;
275
276 }
277
278 int BandwidthController::disableBandwidthControl(void) {
279     runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
280             IPT_FLUSH_COMMANDS, RunCmdFailureOk);
281     return 0;
282 }
283
284 int BandwidthController::runCommands(int numCommands, const char *commands[],
285                                      RunCmdErrHandling cmdErrHandling) {
286     int res = 0;
287     IptFailureLog failureLogging = IptFailShow;
288     if (cmdErrHandling == RunCmdFailureOk) {
289         failureLogging = IptFailHide;
290     }
291     ALOGV("runCommands(): %d commands", numCommands);
292     for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
293         res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
294         if (res && cmdErrHandling != RunCmdFailureOk)
295             return res;
296     }
297     return 0;
298 }
299
300 std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
301     std::string res;
302     char *buff;
303     const char *opFlag;
304
305     switch (op) {
306     case IptOpInsert:
307         opFlag = "-I";
308         break;
309     case IptOpAppend:
310         ALOGE("Append op not supported for %s uids", chain);
311         res = "";
312         return res;
313         break;
314     case IptOpReplace:
315         opFlag = "-R";
316         break;
317     default:
318     case IptOpDelete:
319         opFlag = "-D";
320         break;
321     }
322     asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
323     res = buff;
324     free(buff);
325     return res;
326 }
327
328 int BandwidthController::enableHappyBox(void) {
329     char cmd[MAX_CMD_LEN];
330     int res = 0;
331
332     /*
333      * We tentatively delete before adding, which helps recovering
334      * from bad states (e.g. netd died).
335      */
336
337     /* Should not exist, but ignore result if already there. */
338     snprintf(cmd, sizeof(cmd), "-N bw_happy_box");
339     runIpxtablesCmd(cmd, IptJumpNoAdd);
340
341     /* Should be empty, but clear in case something was wrong. */
342     niceAppUids.clear();
343     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
344     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
345
346     snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
347     runIpxtablesCmd(cmd, IptJumpNoAdd);
348     snprintf(cmd, sizeof(cmd), "-A bw_penalty_box -j bw_happy_box");
349     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
350
351     /* Reject. Defaulting to prot-unreachable */
352     snprintf(cmd, sizeof(cmd), "-D bw_happy_box -j REJECT");
353     runIpxtablesCmd(cmd, IptJumpNoAdd);
354     snprintf(cmd, sizeof(cmd), "-A bw_happy_box -j REJECT");
355     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
356
357     return res;
358 }
359
360 int BandwidthController::disableHappyBox(void) {
361     char cmd[MAX_CMD_LEN];
362
363     /* Best effort */
364     snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
365     runIpxtablesCmd(cmd, IptJumpNoAdd);
366     niceAppUids.clear();
367     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
368     runIpxtablesCmd(cmd, IptJumpNoAdd);
369     snprintf(cmd, sizeof(cmd), "-X bw_happy_box");
370     runIpxtablesCmd(cmd, IptJumpNoAdd);
371
372     return 0;
373 }
374
375 int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
376     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
377 }
378
379 int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
380     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
381 }
382
383 int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
384     return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
385 }
386
387 int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
388     return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
389 }
390
391 int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
392     return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", naughtyAppUids, IptJumpReject, appOp);
393 }
394
395 int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
396     return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", niceAppUids, IptJumpReturn, appOp);
397 }
398
399
400 int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
401                                                const char *chain,
402                                                std::list<int /*appUid*/> &specialAppUids,
403                                                IptJumpOp jumpHandling, SpecialAppOp appOp) {
404
405     char cmd[MAX_CMD_LEN];
406     int uidNum;
407     const char *failLogTemplate;
408     IptOp op;
409     int appUids[numUids];
410     std::string iptCmd;
411     std::list<int /*uid*/>::iterator it;
412
413     switch (appOp) {
414     case SpecialAppOpAdd:
415         op = IptOpInsert;
416         failLogTemplate = "Failed to add app uid %s(%d) to %s.";
417         break;
418     case SpecialAppOpRemove:
419         op = IptOpDelete;
420         failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
421         break;
422     default:
423         ALOGE("Unexpected app Op %d", appOp);
424         return -1;
425     }
426
427     for (uidNum = 0; uidNum < numUids; uidNum++) {
428         char *end;
429         appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
430         if (*end || !*appStrUids[uidNum]) {
431             ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
432             goto fail_parse;
433         }
434     }
435
436     for (uidNum = 0; uidNum < numUids; uidNum++) {
437         int uid = appUids[uidNum];
438         for (it = specialAppUids.begin(); it != specialAppUids.end(); it++) {
439             if (*it == uid)
440                 break;
441         }
442         bool found = (it != specialAppUids.end());
443
444         if (appOp == SpecialAppOpRemove) {
445             if (!found) {
446                 ALOGE("No such appUid %d to remove", uid);
447                 return -1;
448             }
449             specialAppUids.erase(it);
450         } else {
451             if (found) {
452                 ALOGE("appUid %d exists already", uid);
453                 return -1;
454             }
455             specialAppUids.push_front(uid);
456         }
457
458         iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
459         if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
460             ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
461             goto fail_with_uidNum;
462         }
463     }
464     return 0;
465
466 fail_with_uidNum:
467     /* Try to remove the uid that failed in any case*/
468     iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
469     runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
470 fail_parse:
471     return -1;
472 }
473
474 std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
475     std::string res;
476     char *buff;
477     const char *opFlag;
478
479     ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
480
481     switch (op) {
482     case IptOpInsert:
483         opFlag = "-I";
484         break;
485     case IptOpAppend:
486         opFlag = "-A";
487         break;
488     case IptOpReplace:
489         opFlag = "-R";
490         break;
491     default:
492     case IptOpDelete:
493         opFlag = "-D";
494         break;
495     }
496
497     // The requried IP version specific --jump REJECT ... will be added later.
498     asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
499              costName);
500     res = buff;
501     free(buff);
502     return res;
503 }
504
505 int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
506     char cmd[MAX_CMD_LEN];
507     int res = 0, res1, res2;
508     int ruleInsertPos = 1;
509     std::string costString;
510     const char *costCString;
511
512     /* The "-N costly" is created upfront, no need to handle it here. */
513     switch (quotaType) {
514     case QuotaUnique:
515         costString = "bw_costly_";
516         costString += ifn;
517         costCString = costString.c_str();
518         /*
519          * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
520          * Creating a new one is allowed to fail in case it existed.
521          * This helps with netd restarts.
522          */
523         snprintf(cmd, sizeof(cmd), "-F %s", costCString);
524         res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
525         snprintf(cmd, sizeof(cmd), "-N %s", costCString);
526         res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
527         res = (res1 && res2) || (!res1 && !res2);
528
529         snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
530         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
531         break;
532     case QuotaShared:
533         costCString = "bw_costly_shared";
534         break;
535     default:
536         ALOGE("Unexpected quotatype %d", quotaType);
537         return -1;
538     }
539
540     if (globalAlertBytes) {
541         /* The alert rule comes 1st */
542         ruleInsertPos = 2;
543     }
544
545     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
546     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
547
548     snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
549     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
550
551     snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
552     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
553
554     snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
555     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
556     return res;
557 }
558
559 int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
560     char cmd[MAX_CMD_LEN];
561     int res = 0;
562     std::string costString;
563     const char *costCString;
564
565     switch (quotaType) {
566     case QuotaUnique:
567         costString = "bw_costly_";
568         costString += ifn;
569         costCString = costString.c_str();
570         break;
571     case QuotaShared:
572         costCString = "bw_costly_shared";
573         break;
574     default:
575         ALOGE("Unexpected quotatype %d", quotaType);
576         return -1;
577     }
578
579     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
580     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
581     snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
582     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
583
584     /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
585     if (quotaType == QuotaUnique) {
586         snprintf(cmd, sizeof(cmd), "-F %s", costCString);
587         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
588         snprintf(cmd, sizeof(cmd), "-X %s", costCString);
589         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
590     }
591     return res;
592 }
593
594 int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
595     char cmd[MAX_CMD_LEN];
596     char ifn[MAX_IFACENAME_LEN];
597     int res = 0;
598     std::string quotaCmd;
599     std::string ifaceName;
600     ;
601     const char *costName = "shared";
602     std::list<std::string>::iterator it;
603
604     if (!maxBytes) {
605         /* Don't talk about -1, deprecate it. */
606         ALOGE("Invalid bytes value. 1..max_int64.");
607         return -1;
608     }
609     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
610         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
611         return -1;
612     }
613     ifaceName = ifn;
614
615     if (maxBytes == -1) {
616         return removeInterfaceSharedQuota(ifn);
617     }
618
619     /* Insert ingress quota. */
620     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
621         if (*it == ifaceName)
622             break;
623     }
624
625     if (it == sharedQuotaIfaces.end()) {
626         res |= prepCostlyIface(ifn, QuotaShared);
627         if (sharedQuotaIfaces.empty()) {
628             quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
629             res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
630             if (res) {
631                 ALOGE("Failed set quota rule");
632                 goto fail;
633             }
634             sharedQuotaBytes = maxBytes;
635         }
636         sharedQuotaIfaces.push_front(ifaceName);
637
638     }
639
640     if (maxBytes != sharedQuotaBytes) {
641         res |= updateQuota(costName, maxBytes);
642         if (res) {
643             ALOGE("Failed update quota for %s", costName);
644             goto fail;
645         }
646         sharedQuotaBytes = maxBytes;
647     }
648     return 0;
649
650     fail:
651     /*
652      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
653      * rules in the kernel to see which ones need cleaning up.
654      * For now callers needs to choose if they want to "ndc bandwidth enable"
655      * which resets everything.
656      */
657     removeInterfaceSharedQuota(ifn);
658     return -1;
659 }
660
661 /* It will also cleanup any shared alerts */
662 int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
663     char ifn[MAX_IFACENAME_LEN];
664     int res = 0;
665     std::string ifaceName;
666     std::list<std::string>::iterator it;
667     const char *costName = "shared";
668
669     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
670         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
671         return -1;
672     }
673     ifaceName = ifn;
674
675     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
676         if (*it == ifaceName)
677             break;
678     }
679     if (it == sharedQuotaIfaces.end()) {
680         ALOGE("No such iface %s to delete", ifn);
681         return -1;
682     }
683
684     res |= cleanupCostlyIface(ifn, QuotaShared);
685     sharedQuotaIfaces.erase(it);
686
687     if (sharedQuotaIfaces.empty()) {
688         std::string quotaCmd;
689         quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
690         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
691         sharedQuotaBytes = 0;
692         if (sharedAlertBytes) {
693             removeSharedAlert();
694             sharedAlertBytes = 0;
695         }
696     }
697     return res;
698 }
699
700 int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
701     char ifn[MAX_IFACENAME_LEN];
702     int res = 0;
703     std::string ifaceName;
704     const char *costName;
705     std::list<QuotaInfo>::iterator it;
706     std::string quotaCmd;
707
708     if (!maxBytes) {
709         /* Don't talk about -1, deprecate it. */
710         ALOGE("Invalid bytes value. 1..max_int64.");
711         return -1;
712     }
713     if (maxBytes == -1) {
714         return removeInterfaceQuota(iface);
715     }
716
717     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
718         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
719         return -1;
720     }
721     ifaceName = ifn;
722     costName = iface;
723
724     /* Insert ingress quota. */
725     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
726         if (it->ifaceName == ifaceName)
727             break;
728     }
729
730     if (it == quotaIfaces.end()) {
731         /* Preparing the iface adds a penalty/happy box check */
732         res |= prepCostlyIface(ifn, QuotaUnique);
733         /*
734          * The rejecting quota limit should go after the penalty/happy box checks
735          * or else a naughty app could just eat up the quota.
736          * So we append here.
737          */
738         quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
739         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
740         if (res) {
741             ALOGE("Failed set quota rule");
742             goto fail;
743         }
744
745         quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
746
747     } else {
748         res |= updateQuota(costName, maxBytes);
749         if (res) {
750             ALOGE("Failed update quota for %s", iface);
751             goto fail;
752         }
753         it->quota = maxBytes;
754     }
755     return 0;
756
757     fail:
758     /*
759      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
760      * rules in the kernel to see which ones need cleaning up.
761      * For now callers needs to choose if they want to "ndc bandwidth enable"
762      * which resets everything.
763      */
764     removeInterfaceSharedQuota(ifn);
765     return -1;
766 }
767
768 int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
769     return getInterfaceQuota("shared", bytes);
770 }
771
772 int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
773     FILE *fp;
774     char *fname;
775     int scanRes;
776
777     asprintf(&fname, "/proc/net/xt_quota/%s", costName);
778     fp = fopen(fname, "r");
779     free(fname);
780     if (!fp) {
781         ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
782         return -1;
783     }
784     scanRes = fscanf(fp, "%lld", bytes);
785     ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
786     fclose(fp);
787     return scanRes == 1 ? 0 : -1;
788 }
789
790 int BandwidthController::removeInterfaceQuota(const char *iface) {
791
792     char ifn[MAX_IFACENAME_LEN];
793     int res = 0;
794     std::string ifaceName;
795     const char *costName;
796     std::list<QuotaInfo>::iterator it;
797
798     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
799         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
800         return -1;
801     }
802     ifaceName = ifn;
803     costName = iface;
804
805     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
806         if (it->ifaceName == ifaceName)
807             break;
808     }
809
810     if (it == quotaIfaces.end()) {
811         ALOGE("No such iface %s to delete", ifn);
812         return -1;
813     }
814
815     /* This also removes the quota command of CostlyIface chain. */
816     res |= cleanupCostlyIface(ifn, QuotaUnique);
817
818     quotaIfaces.erase(it);
819
820     return res;
821 }
822
823 int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
824     FILE *fp;
825     char *fname;
826
827     asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
828     fp = fopen(fname, "w");
829     free(fname);
830     if (!fp) {
831         ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
832         return -1;
833     }
834     fprintf(fp, "%lld\n", bytes);
835     fclose(fp);
836     return 0;
837 }
838
839 int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
840     int res = 0;
841     const char *opFlag;
842     char *alertQuotaCmd;
843
844     switch (op) {
845     case IptOpInsert:
846         opFlag = "-I";
847         break;
848     case IptOpAppend:
849         opFlag = "-A";
850         break;
851     case IptOpReplace:
852         opFlag = "-R";
853         break;
854     default:
855     case IptOpDelete:
856         opFlag = "-D";
857         break;
858     }
859
860     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
861         bytes, alertName);
862     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
863     free(alertQuotaCmd);
864     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
865         bytes, alertName);
866     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
867     free(alertQuotaCmd);
868     return res;
869 }
870
871 int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
872     int res = 0;
873     const char *opFlag;
874     char *alertQuotaCmd;
875
876     switch (op) {
877     case IptOpInsert:
878         opFlag = "-I";
879         break;
880     case IptOpAppend:
881         opFlag = "-A";
882         break;
883     case IptOpReplace:
884         opFlag = "-R";
885         break;
886     default:
887     case IptOpDelete:
888         opFlag = "-D";
889         break;
890     }
891
892     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
893         bytes, alertName);
894     res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
895     free(alertQuotaCmd);
896     return res;
897 }
898
899 int BandwidthController::setGlobalAlert(int64_t bytes) {
900     const char *alertName = ALERT_GLOBAL_NAME;
901     int res = 0;
902
903     if (!bytes) {
904         ALOGE("Invalid bytes value. 1..max_int64.");
905         return -1;
906     }
907     if (globalAlertBytes) {
908         res = updateQuota(alertName, bytes);
909     } else {
910         res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
911         if (globalAlertTetherCount) {
912             ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
913             res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
914         }
915     }
916     globalAlertBytes = bytes;
917     return res;
918 }
919
920 int BandwidthController::setGlobalAlertInForwardChain(void) {
921     const char *alertName = ALERT_GLOBAL_NAME;
922     int res = 0;
923
924     globalAlertTetherCount++;
925     ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
926
927     /*
928      * If there is no globalAlert active we are done.
929      * If there is an active globalAlert but this is not the 1st
930      * tether, we are also done.
931      */
932     if (!globalAlertBytes || globalAlertTetherCount != 1) {
933         return 0;
934     }
935
936     /* We only add the rule if this was the 1st tether added. */
937     res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
938     return res;
939 }
940
941 int BandwidthController::removeGlobalAlert(void) {
942
943     const char *alertName = ALERT_GLOBAL_NAME;
944     int res = 0;
945
946     if (!globalAlertBytes) {
947         ALOGE("No prior alert set");
948         return -1;
949     }
950     res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
951     if (globalAlertTetherCount) {
952         res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
953     }
954     globalAlertBytes = 0;
955     return res;
956 }
957
958 int BandwidthController::removeGlobalAlertInForwardChain(void) {
959     int res = 0;
960     const char *alertName = ALERT_GLOBAL_NAME;
961
962     if (!globalAlertTetherCount) {
963         ALOGE("No prior alert set");
964         return -1;
965     }
966
967     globalAlertTetherCount--;
968     /*
969      * If there is no globalAlert active we are done.
970      * If there is an active globalAlert but there are more
971      * tethers, we are also done.
972      */
973     if (!globalAlertBytes || globalAlertTetherCount >= 1) {
974         return 0;
975     }
976
977     /* We only detete the rule if this was the last tether removed. */
978     res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
979     return res;
980 }
981
982 int BandwidthController::setSharedAlert(int64_t bytes) {
983     if (!sharedQuotaBytes) {
984         ALOGE("Need to have a prior shared quota set to set an alert");
985         return -1;
986     }
987     if (!bytes) {
988         ALOGE("Invalid bytes value. 1..max_int64.");
989         return -1;
990     }
991     return setCostlyAlert("shared", bytes, &sharedAlertBytes);
992 }
993
994 int BandwidthController::removeSharedAlert(void) {
995     return removeCostlyAlert("shared", &sharedAlertBytes);
996 }
997
998 int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
999     std::list<QuotaInfo>::iterator it;
1000
1001     if (!bytes) {
1002         ALOGE("Invalid bytes value. 1..max_int64.");
1003         return -1;
1004     }
1005     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1006         if (it->ifaceName == iface)
1007             break;
1008     }
1009
1010     if (it == quotaIfaces.end()) {
1011         ALOGE("Need to have a prior interface quota set to set an alert");
1012         return -1;
1013     }
1014
1015     return setCostlyAlert(iface, bytes, &it->alert);
1016 }
1017
1018 int BandwidthController::removeInterfaceAlert(const char *iface) {
1019     std::list<QuotaInfo>::iterator it;
1020
1021     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1022         if (it->ifaceName == iface)
1023             break;
1024     }
1025
1026     if (it == quotaIfaces.end()) {
1027         ALOGE("No prior alert set for interface %s", iface);
1028         return -1;
1029     }
1030
1031     return removeCostlyAlert(iface, &it->alert);
1032 }
1033
1034 int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1035     char *alertQuotaCmd;
1036     char *chainName;
1037     int res = 0;
1038     char *alertName;
1039
1040     if (!bytes) {
1041         ALOGE("Invalid bytes value. 1..max_int64.");
1042         return -1;
1043     }
1044     asprintf(&alertName, "%sAlert", costName);
1045     if (*alertBytes) {
1046         res = updateQuota(alertName, *alertBytes);
1047     } else {
1048         asprintf(&chainName, "bw_costly_%s", costName);
1049         asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
1050         res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1051         free(alertQuotaCmd);
1052         free(chainName);
1053     }
1054     *alertBytes = bytes;
1055     free(alertName);
1056     return res;
1057 }
1058
1059 int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1060     char *alertQuotaCmd;
1061     char *chainName;
1062     char *alertName;
1063     int res = 0;
1064
1065     asprintf(&alertName, "%sAlert", costName);
1066     if (!*alertBytes) {
1067         ALOGE("No prior alert set for %s alert", costName);
1068         return -1;
1069     }
1070
1071     asprintf(&chainName, "bw_costly_%s", costName);
1072     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
1073     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1074     free(alertQuotaCmd);
1075     free(chainName);
1076
1077     *alertBytes = 0;
1078     free(alertName);
1079     return res;
1080 }
1081
1082 /*
1083  * Parse the ptks and bytes out of:
1084  *   Chain natctrl_tether_counters (4 references)
1085  *       pkts      bytes target     prot opt in     out     source               destination
1086  *         26     2373 RETURN     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0            counter wlan0_rmnet0: 0 bytes
1087  *         27     2002 RETURN     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0            counter rmnet0_wlan0: 0 bytes
1088  *       1040   107471 RETURN     all  --  bt-pan rmnet0  0.0.0.0/0            0.0.0.0/0            counter bt-pan_rmnet0: 0 bytes
1089  *       1450  1708806 RETURN     all  --  rmnet0 bt-pan  0.0.0.0/0            0.0.0.0/0            counter rmnet0_bt-pan: 0 bytes
1090  */
1091 int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
1092                                                 FILE *fp, std::string &extraProcessingInfo) {
1093     int res;
1094     char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1095     char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1096     char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1097     char rest[MAX_IPT_OUTPUT_LINE_LEN];
1098
1099     TetherStats stats;
1100     char *buffPtr;
1101     int64_t packets, bytes;
1102     int statsFound = 0;
1103
1104     bool filterPair = filter.intIface[0] && filter.extIface[0];
1105
1106     char *filterMsg = filter.getStatsLine();
1107     ALOGV("filter: %s",  filterMsg);
1108     free(filterMsg);
1109
1110     stats = filter;
1111
1112     while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1113         /* Clean up, so a failed parse can still print info */
1114         iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
1115         res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
1116                 &packets, &bytes, iface0, iface1, rest);
1117         ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
1118              iface0, iface1, packets, bytes, rest, buffPtr);
1119         extraProcessingInfo += buffPtr;
1120
1121         if (res != 5) {
1122             continue;
1123         }
1124         /*
1125          * The following assumes that the 1st rule has in:extIface out:intIface,
1126          * which is what NatController sets up.
1127          * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1128          */
1129         if (filter.intIface[0] && filter.extIface[0]) {
1130             if (filter.intIface == iface0 && filter.extIface == iface1) {
1131                 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1132                 stats.rxPackets = packets;
1133                 stats.rxBytes = bytes;
1134             } else if (filter.intIface == iface1 && filter.extIface == iface0) {
1135                 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1136                 stats.txPackets = packets;
1137                 stats.txBytes = bytes;
1138             }
1139         } else if (filter.intIface[0] || filter.extIface[0]) {
1140             if (filter.intIface == iface0 || filter.extIface == iface1) {
1141                 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1142                 stats.intIface = iface0;
1143                 stats.extIface = iface1;
1144                 stats.rxPackets = packets;
1145                 stats.rxBytes = bytes;
1146             } else if (filter.intIface == iface1 || filter.extIface == iface0) {
1147                 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1148                 stats.intIface = iface1;
1149                 stats.extIface = iface0;
1150                 stats.txPackets = packets;
1151                 stats.txBytes = bytes;
1152             }
1153         } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1154             if (!stats.intIface[0]) {
1155                 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1156                 stats.intIface = iface0;
1157                 stats.extIface = iface1;
1158                 stats.rxPackets = packets;
1159                 stats.rxBytes = bytes;
1160             } else if (stats.intIface == iface1 && stats.extIface == iface0) {
1161                 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
1162                 stats.txPackets = packets;
1163                 stats.txBytes = bytes;
1164             }
1165         }
1166         if (stats.rxBytes != -1 && stats.txBytes != -1) {
1167             ALOGV("rx_bytes=%lld tx_bytes=%lld filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
1168             /* Send out stats, and prep for the next if needed. */
1169             char *msg = stats.getStatsLine();
1170             if (filterPair) {
1171                 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1172                 return 0;
1173             } else {
1174                 cli->sendMsg(ResponseCode::TetheringStatsListResult, msg, false);
1175                 stats = filter;
1176             }
1177             free(msg);
1178             statsFound++;
1179         }
1180     }
1181     /* We found some stats, and the last one isn't a partial stats. */
1182     if (statsFound && (stats.rxBytes == -1 || stats.txBytes == -1)) {
1183         cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1184         return 0;
1185     }
1186     return -1;
1187 }
1188
1189 char *BandwidthController::TetherStats::getStatsLine(void) const {
1190     char *msg;
1191     asprintf(&msg, "%s %s %lld %lld %lld %lld", intIface.c_str(), extIface.c_str(),
1192             rxBytes, rxPackets, txBytes, txPackets);
1193     return msg;
1194 }
1195
1196 int BandwidthController::getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo) {
1197     int res;
1198     std::string fullCmd;
1199     FILE *iptOutput;
1200     const char *cmd;
1201
1202     /*
1203      * Why not use some kind of lib to talk to iptables?
1204      * Because the only libs are libiptc and libip6tc in iptables, and they are
1205      * not easy to use. They require the known iptables match modules to be
1206      * preloaded/linked, and require apparently a lot of wrapper code to get
1207      * the wanted info.
1208      */
1209     fullCmd = IPTABLES_PATH;
1210     fullCmd += " -nvx -L ";
1211     fullCmd += NatController::LOCAL_TETHER_COUNTERS_CHAIN;
1212     iptOutput = popen(fullCmd.c_str(), "r");
1213     if (!iptOutput) {
1214             ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1215             extraProcessingInfo += "Failed to run iptables.";
1216         return -1;
1217     }
1218     res = parseForwardChainStats(cli, stats, iptOutput, extraProcessingInfo);
1219     pclose(iptOutput);
1220
1221     /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1222     return res;
1223 }