1 /* 2 * Copyright (C) 2012 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 /* 18 * MODUS OPERANDI 19 * -------------- 20 * 21 * IPTABLES command sequence: 22 * 23 * iptables -F 24 * 25 * iptables -t raw -F idletimer_PREROUTING 26 * iptables -t mangle -F idletimer_POSTROUTING 27 * 28 * 29 * iptables -t raw -N idletimer_PREROUTING 30 * iptables -t mangle -N idletimer_POSTROUTING 31 * 32 * iptables -t raw -D PREROUTING -j idletimer_PREROUTING 33 * iptables -t mangle -D POSTROUTING -j idletimer_POSTROUTING 34 * 35 * 36 * iptables -t raw -I PREROUTING -j idletimer_PREROUTING 37 * iptables -t mangle -I POSTROUTING -j idletimer_POSTROUTING 38 * 39 * # For notifications to work the lable name must match the name of a valid interface. 40 * # If the label name does match an interface, the rules will be a no-op. 41 * 42 * iptables -t raw -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1 43 * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1 44 * 45 * iptables -nxvL -t raw 46 * iptables -nxvL -t mangle 47 * 48 * ================= 49 * 50 * ndc command sequence 51 * ------------------ 52 * ndc idletimer enable 53 * ndc idletimer add <iface> <timeout> <class label> 54 * ndc idletimer remove <iface> <timeout> <class label> 55 * 56 * Monitor effect on the iptables chains after each step using: 57 * iptables -nxvL -t raw 58 * iptables -nxvL -t mangle 59 * 60 * Remember that the timeout value has to be same at the time of the 61 * removal. 62 * 63 * ================= 64 * 65 * Verifying the iptables rule 66 * --------------------------- 67 * We want to make sure the iptable rules capture every packet. It can be 68 * verified with tcpdump. First take a note of the pkts count for the two rules: 69 * 70 * adb shell iptables -t mangle -L idletimer_mangle_POSTROUTING -v && adb shell iptables -t raw -L idletimer_raw_PREROUTING -v 71 * 72 * And then, before any network traffics happen on the device, run tcpdump: 73 * 74 * adb shell tcpdump | tee tcpdump.log 75 * 76 * After a while run iptables commands again, you could then count the number 77 * of incoming and outgoing packets captured by tcpdump, and compare that with 78 * the numbers reported by iptables command. There shouldn't be too much 79 * difference on these numbers, i.e., with 2000 packets captured it should 80 * differ by less than 5. 81 * 82 * ================= 83 * 84 * Note that currently if the name of the iface is incorrect, iptables 85 * will setup rules without checking if it is the name of a valid 86 * interface (although no notifications will ever be received). It is 87 * the responsibility of code in Java land to ensure that the interface name 88 * is correct. The benefit of this, is that idletimers can be setup on 89 * interfaces than come and go. 90 * 91 * A remove should be called for each add command issued during cleanup, as duplicate 92 * entries of the rule may exist and will all have to removed. 93 * 94 */ 95 96 #define LOG_NDEBUG 0 97 98 #include <stdlib.h> 99 #include <errno.h> 100 #include <sys/socket.h> 101 #include <sys/stat.h> 102 #include <sys/wait.h> 103 #include <fcntl.h> 104 #include <netinet/in.h> 105 #include <arpa/inet.h> 106 #include <string.h> 107 #include <cutils/properties.h> 108 109 #define LOG_TAG "IdletimerController" 110 #include <cutils/log.h> 111 #include <logwrap/logwrap.h> 112 113 #include "IdletimerController.h" 114 #include "NetdConstants.h" 115 116 const char* IdletimerController::LOCAL_RAW_PREROUTING = "idletimer_raw_PREROUTING"; 117 const char* IdletimerController::LOCAL_MANGLE_POSTROUTING = "idletimer_mangle_POSTROUTING"; 118 119 IdletimerController::IdletimerController() { 120 } 121 122 IdletimerController::~IdletimerController() { 123 } 124 /* return 0 or non-zero */ 125 int IdletimerController::runIpxtablesCmd(int argc, const char **argv) { 126 int resIpv4, resIpv6; 127 128 // Running for IPv4 129 argv[0] = IPTABLES_PATH; 130 resIpv4 = android_fork_execvp(argc, (char **)argv, NULL, false, false); 131 132 // Running for IPv6 133 argv[0] = IP6TABLES_PATH; 134 resIpv6 = android_fork_execvp(argc, (char **)argv, NULL, false, false); 135 136 #if !LOG_NDEBUG 137 std::string full_cmd = argv[0]; 138 argc--; argv++; 139 for (; argc; argc--, argv++) { 140 full_cmd += " "; 141 full_cmd += argv[0]; 142 } 143 ALOGV("runCmd(%s) res_ipv4=%d, res_ipv6=%d", full_cmd.c_str(), resIpv4, resIpv6); 144 #endif 145 146 return (resIpv4 == 0 && resIpv6 == 0) ? 0 : -1; 147 } 148 149 bool IdletimerController::setupIptablesHooks() { 150 return true; 151 } 152 153 int IdletimerController::setDefaults() { 154 int res; 155 const char *cmd1[] = { 156 NULL, // To be filled inside runIpxtablesCmd 157 "-t", 158 "raw", 159 "-F", 160 LOCAL_RAW_PREROUTING 161 }; 162 res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1); 163 164 if (res) 165 return res; 166 167 const char *cmd2[] = { 168 NULL, // To be filled inside runIpxtablesCmd 169 "-t", 170 "mangle", 171 "-F", 172 LOCAL_MANGLE_POSTROUTING 173 }; 174 res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2); 175 176 return res; 177 } 178 179 int IdletimerController::enableIdletimerControl() { 180 int res = setDefaults(); 181 return res; 182 } 183 184 int IdletimerController::disableIdletimerControl() { 185 int res = setDefaults(); 186 return res; 187 } 188 189 int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface, 190 uint32_t timeout, 191 const char *classLabel) { 192 int res; 193 char timeout_str[11]; //enough to store any 32-bit unsigned decimal 194 195 if (!isIfaceName(iface)) { 196 errno = ENOENT; 197 return -1; 198 } 199 200 snprintf(timeout_str, sizeof(timeout_str), "%u", timeout); 201 202 const char *cmd1[] = { 203 NULL, // To be filled inside runIpxtablesCmd 204 "-t", 205 "raw", 206 (op == IptOpAdd) ? "-A" : "-D", 207 LOCAL_RAW_PREROUTING, 208 "-i", 209 iface, 210 "-j", 211 "IDLETIMER", 212 "--timeout", 213 timeout_str, 214 "--label", 215 classLabel, 216 "--send_nl_msg", 217 "1" 218 }; 219 res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1); 220 221 if (res) 222 return res; 223 224 const char *cmd2[] = { 225 NULL, // To be filled inside runIpxtablesCmd 226 "-t", 227 "mangle", 228 (op == IptOpAdd) ? "-A" : "-D", 229 LOCAL_MANGLE_POSTROUTING, 230 "-o", 231 iface, 232 "-j", 233 "IDLETIMER", 234 "--timeout", 235 timeout_str, 236 "--label", 237 classLabel, 238 "--send_nl_msg", 239 "1" 240 }; 241 res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2); 242 243 return res; 244 } 245 246 int IdletimerController::addInterfaceIdletimer(const char *iface, 247 uint32_t timeout, 248 const char *classLabel) { 249 return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel); 250 } 251 252 int IdletimerController::removeInterfaceIdletimer(const char *iface, 253 uint32_t timeout, 254 const char *classLabel) { 255 return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel); 256 } 257