BandwidthController.cpp revision 4a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11
14a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/* 24a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Copyright (C) 2011 The Android Open Source Project 34a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 44a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Licensed under the Apache License, Version 2.0 (the "License"); 54a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * you may not use this file except in compliance with the License. 64a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * You may obtain a copy of the License at 74a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 84a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * http://www.apache.org/licenses/LICENSE-2.0 94a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Unless required by applicable law or agreed to in writing, software 114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * distributed under the License is distributed on an "AS IS" BASIS, 124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * See the License for the specific language governing permissions and 144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * limitations under the License. 154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <stdlib.h> 184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <errno.h> 194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <fcntl.h> 204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <string.h> 214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/socket.h> 234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/stat.h> 244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/types.h> 254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/wait.h> 264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/netlink.h> 284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/rtnetlink.h> 294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/pkt_sched.h> 304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#define LOG_TAG "BandwidthController" 324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/log.h> 334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/properties.h> 344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallextern "C" int logwrap(int argc, const char **argv, int background); 364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include "BandwidthController.h" 384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_LEN = 255; 414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_IFACENAME_LEN = 64; 424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_ARGS = 32; 434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables"; 444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/** 474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules: 484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * Ordering 494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains. 504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g. "-I INPUT -i rmnet0 --goto costly" 514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - quota'd rules in the costly chain should be before penalty_box lookups. 524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota 544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - global quota for all costly interfaces uses a single costly chain: 554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * . initial rules 564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -N costly 574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface0 --goto costly 584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface0 --goto costly 594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I costly -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited 604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly --jump penalty_box 614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly -m owner --socket-exists 624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * . adding a new iface to this, E.g.: 634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface1 --goto costly 644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface1 --goto costly 654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - quota per interface. This is achieve by having "costly" chains per quota. 674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g. adding a new costly interface iface0 with its own quota: 684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -N costly_iface0 694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface0 --goto costly_iface0 704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface0 --goto costly_iface0 714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited 724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 --jump penalty_box 734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 -m owner --socket-exists 744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling: 764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - only one penalty_box for all interfaces 774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g Adding an app: 784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A penalty_box -m owner --uid-owner app_3 --jump REJECT --reject-with icmp-net-prohibited 794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::cleanupCommands[] = { 814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* Cleanup rules. */ 824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-F", 834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-t raw -F", 844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-X costly", 854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-X penalty_box", 864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}; 874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = { 894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* Created needed chains. */ 904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-N costly", 914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-N penalty_box", 924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}; 934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = { 954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-F INPUT", 964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A INPUT -i lo --jump ACCEPT", 974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */ 984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-F OUTPUT", 1004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A OUTPUT -o lo --jump ACCEPT", 1014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */ 1024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-F costly", 1044a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A costly --jump penalty_box", 1054a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A costly -m owner --socket-exists", /* This is a tracking rule. */ 1064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* TODO(jpa): Figure out why iptables doesn't correctly return from this 1074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * chain. For now, hack the chain exit with an ACCEPT. 1084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 1094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall "-A costly --jump ACCEPT", 1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}; 1114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) { 1144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char value[PROPERTY_VALUE_MAX]; 1164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall property_get("persist.bandwidth.enable", value, "0"); 1184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (!strcmp(value, "1")) { 1194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall enableBandwidthControl(); 1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd) { 1254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char buffer[MAX_CMD_LEN]; 1264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGD("About to run: iptables %s", cmd); 1284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall strncpy(buffer, cmd, sizeof(buffer)-1); 1304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall const char *argv[MAX_CMD_ARGS]; 1324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char *next = buffer; 1334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char *tmp; 1344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall argv[0] = IPTABLES_PATH; 1364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int argc = 1; 1374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall while ((tmp = strsep(&next, " "))) { 1394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall argv[argc++] = tmp; 1404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (argc == MAX_CMD_ARGS) { 1414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGE("iptables argument overflow"); 1424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall errno = E2BIG; 1434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return -1; 1444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall argv[argc] = NULL; 1474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd 1484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Then just talk directly to the kernel via rtnetlink. 1494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 1504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return logwrap(argc, argv, 0); 1514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) { 1554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* Some of the initialCommands are allowed to fail */ 1564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall runCommands(cleanupCommands, sizeof(cleanupCommands)/sizeof(char*), true); 1574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall runCommands(setupCommands, sizeof(setupCommands)/sizeof(char*), true); 1584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return runCommands(basicAccountingCommands, 1594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall sizeof(basicAccountingCommands)/sizeof(char*)); 1604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) { 1644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* The cleanupCommands are allowed to fail */ 1654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall runCommands(cleanupCommands, sizeof(cleanupCommands)/sizeof(char*), true); 1664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return 0; 1674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::runCommands(const char *commands[], int numCommands, bool allowFailure) { 1704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int res = 0; 1714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGD("runCommands(): %d commands", numCommands); 1724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) { 1734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res = runIptablesCmd(commands[cmdNum]); 1744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if(res && !allowFailure) return res; 1754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return allowFailure?res:0; 1774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface, 1814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int64_t maxBytes) { 1824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char cmd[MAX_CMD_LEN]; 1834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char ifn[MAX_IFACENAME_LEN]; 1844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int res; 1854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall memset(ifn, 0, sizeof(ifn)); 1874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall strncpy(ifn, iface, sizeof(ifn)-1); 1884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (maxBytes == -1) { 1904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return removeQuota(ifn); 1914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* Insert ingress quota. */ 1944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall std::string ifaceName(ifn); 1954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall std::list<std::string>::iterator it; 1964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int pos; 1974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall for (pos=1, it = ifaceRules.begin(); it != ifaceRules.end(); it++, pos++) { 1984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (*it == ifaceName) 1994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall break; 2004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (it != ifaceRules.end()) { 2024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-R INPUT %d -i %s --goto costly", pos, ifn); 2034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res = runIptablesCmd(cmd); 2044a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-R OUTPUT %d -o %s --goto costly", pos, ifn); 2054a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-R costly %d -m quota ! --quota %lld" 2074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall " --jump REJECT --reject-with icmp-net-prohibited", 2084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall pos, maxBytes); 2094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (res) { 2114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGE("Failed set quota rule."); 2124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall goto fail; 2134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } else { 2154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall pos = 1; 2164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto costly", ifn); 2174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res = runIptablesCmd(cmd); 2184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto costly", ifn); 2194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "-I costly -m quota ! --quota %lld" 2214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall " --jump REJECT --reject-with icmp-net-prohibited", 2224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall maxBytes); 2234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (res) { 2254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGE("Failed set quota rule."); 2264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall goto fail; 2274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall ifaceRules.push_front(ifaceName); 2294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return 0; 2314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallfail: 2324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* 2334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Failure tends to be that the rules have been messed up. 2344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * For now cleanup all the rules. 2354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse 2364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * rules in the kernel to see which ones need cleaning up. 2374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 2384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall runCommands(basicAccountingCommands, 2394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall sizeof(basicAccountingCommands)/sizeof(char*), true); 2404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall removeQuota(ifn); 2414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return -1; 2424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 2434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 2444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::removeQuota(const char *iface) { 2454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char cmd[MAX_CMD_LEN]; 2464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char ifn[MAX_IFACENAME_LEN]; 2474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int res; 2484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 2494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall memset(ifn, 0, sizeof(ifn)); 2504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall strncpy(ifn, iface, sizeof(ifn)-1); 2514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 2524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall std::string ifaceName(ifn); 2534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall std::list<std::string>::iterator it; 2544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 2554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall int pos; 2564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall for (pos=1, it = ifaceRules.begin(); it != ifaceRules.end(); it++, pos++) { 2574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (*it == ifaceName) 2584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall break; 2594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if(it == ifaceRules.end()) { 2614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGE("No such iface %s to delete.", ifn); 2624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return -1; 2634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 2644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall ifaceRules.erase(it); 2654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "--delete INPUT -i %s --goto costly", ifn); 2664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res = runIptablesCmd(cmd); 2674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "--delete OUTPUT -o %s --goto costly", ifn); 2684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall // Don't use rule-matching for this one. Quota is the remaining one. 2704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall snprintf(cmd, sizeof(cmd), "--delete costly %d", pos); 2714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall res |= runIptablesCmd(cmd); 2724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return res; 2734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 274