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 "-w", 158 "-t", 159 "raw", 160 "-F", 161 LOCAL_RAW_PREROUTING 162 }; 163 res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1); 164 165 if (res) 166 return res; 167 168 const char *cmd2[] = { 169 NULL, // To be filled inside runIpxtablesCmd 170 "-w", 171 "-t", 172 "mangle", 173 "-F", 174 LOCAL_MANGLE_POSTROUTING 175 }; 176 res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2); 177 178 return res; 179 } 180 181 int IdletimerController::enableIdletimerControl() { 182 int res = setDefaults(); 183 return res; 184 } 185 186 int IdletimerController::disableIdletimerControl() { 187 int res = setDefaults(); 188 return res; 189 } 190 191 int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface, 192 uint32_t timeout, 193 const char *classLabel) { 194 int res; 195 char timeout_str[11]; //enough to store any 32-bit unsigned decimal 196 197 if (!isIfaceName(iface)) { 198 errno = ENOENT; 199 return -1; 200 } 201 202 snprintf(timeout_str, sizeof(timeout_str), "%u", timeout); 203 204 const char *cmd1[] = { 205 NULL, // To be filled inside runIpxtablesCmd 206 "-w", 207 "-t", 208 "raw", 209 (op == IptOpAdd) ? "-A" : "-D", 210 LOCAL_RAW_PREROUTING, 211 "-i", 212 iface, 213 "-j", 214 "IDLETIMER", 215 "--timeout", 216 timeout_str, 217 "--label", 218 classLabel, 219 "--send_nl_msg", 220 "1" 221 }; 222 res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1); 223 224 if (res) 225 return res; 226 227 const char *cmd2[] = { 228 NULL, // To be filled inside runIpxtablesCmd 229 "-w", 230 "-t", 231 "mangle", 232 (op == IptOpAdd) ? "-A" : "-D", 233 LOCAL_MANGLE_POSTROUTING, 234 "-o", 235 iface, 236 "-j", 237 "IDLETIMER", 238 "--timeout", 239 timeout_str, 240 "--label", 241 classLabel, 242 "--send_nl_msg", 243 "1" 244 }; 245 res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2); 246 247 return res; 248 } 249 250 int IdletimerController::addInterfaceIdletimer(const char *iface, 251 uint32_t timeout, 252 const char *classLabel) { 253 return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel); 254 } 255 256 int IdletimerController::removeInterfaceIdletimer(const char *iface, 257 uint32_t timeout, 258 const char *classLabel) { 259 return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel); 260 } 261