1/* 2 * Copyright (C) 2008 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#include <stdlib.h> 20#include <errno.h> 21#include <sys/socket.h> 22#include <sys/stat.h> 23#include <sys/wait.h> 24#include <fcntl.h> 25#include <netinet/in.h> 26#include <arpa/inet.h> 27#include <string.h> 28#include <cutils/properties.h> 29 30#define LOG_TAG "NatController" 31#include <cutils/log.h> 32#include <logwrap/logwrap.h> 33 34#include "NatController.h" 35#include "NetdConstants.h" 36#include "RouteController.h" 37 38const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD"; 39const char* NatController::LOCAL_MANGLE_FORWARD = "natctrl_mangle_FORWARD"; 40const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING"; 41const char* NatController::LOCAL_RAW_PREROUTING = "natctrl_raw_PREROUTING"; 42const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters"; 43 44auto NatController::execFunction = android_fork_execvp; 45 46NatController::NatController() { 47} 48 49NatController::~NatController() { 50} 51 52struct CommandsAndArgs { 53 /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */ 54 const char *cmd[32]; 55 bool checkRes; 56}; 57 58int NatController::runCmd(int argc, const char **argv) { 59 int res; 60 61 res = execFunction(argc, (char **)argv, NULL, false, false); 62 63#if !LOG_NDEBUG 64 std::string full_cmd = argv[0]; 65 argc--; argv++; 66 /* 67 * HACK: Sometimes runCmd() is called with a ridcously large value (32) 68 * and it works because the argv[] contains a NULL after the last 69 * true argv. So here we use the NULL argv[] to terminate when the argc 70 * is horribly wrong, and argc for the normal cases. 71 */ 72 for (; argc && argv[0]; argc--, argv++) { 73 full_cmd += " "; 74 full_cmd += argv[0]; 75 } 76 ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res); 77#endif 78 return res; 79} 80 81int NatController::setupIptablesHooks() { 82 int res; 83 res = setDefaults(); 84 if (res < 0) { 85 return res; 86 } 87 88 struct CommandsAndArgs defaultCommands[] = { 89 /* 90 * This is for tethering counters. 91 * This chain is reached via --goto, and then RETURNS. 92 */ 93 {{IPTABLES_PATH, "-w", "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0}, 94 {{IP6TABLES_PATH, "-w", "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0}, 95 {{IPTABLES_PATH, "-w", "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0}, 96 {{IP6TABLES_PATH, "-w", "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0}, 97 {{IPTABLES_PATH, "-w", "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1}, 98 {{IP6TABLES_PATH, "-w", "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1}, 99 100 /* 101 * Second chain is used to limit downstream mss to the upstream pmtu 102 * so we don't end up fragmenting every large packet tethered devices 103 * send. Note this feature requires kernel support with flag 104 * CONFIG_NETFILTER_XT_TARGET_TCPMSS=y, which not all builds will have, 105 * so the final rule is allowed to fail. 106 * Bug 17629786 asks to make the failure more obvious, or even fatal 107 * so that all builds eventually gain the performance improvement. 108 */ 109 {{IPTABLES_PATH, "-w", "-t", "mangle", "-A", LOCAL_MANGLE_FORWARD, "-p", "tcp", 110 "--tcp-flags", "SYN", "SYN", "-j", "TCPMSS", "--clamp-mss-to-pmtu"}, 0}, 111 }; 112 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) { 113 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) && 114 defaultCommands[cmdNum].checkRes) { 115 return -1; 116 } 117 } 118 ifacePairList.clear(); 119 120 return 0; 121} 122 123int NatController::setDefaults() { 124 /* 125 * The following only works because: 126 * - the defaultsCommands[].cmd array is padded with NULL, and 127 * - the 1st argc of runCmd() will just be the max for the CommandsAndArgs[].cmd, and 128 * - internally it will be memcopied to an array and terminated with a NULL. 129 */ 130 struct CommandsAndArgs defaultCommands[] = { 131 {{IPTABLES_PATH, "-w", "-F", LOCAL_FORWARD,}, 1}, 132 {{IP6TABLES_PATH, "-w", "-F", LOCAL_FORWARD,}, 1}, 133 {{IPTABLES_PATH, "-w", "-A", LOCAL_FORWARD, "-j", "DROP"}, 1}, 134 {{IPTABLES_PATH, "-w", "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1}, 135 {{IP6TABLES_PATH, "-w", "-t", "raw", "-F", LOCAL_RAW_PREROUTING}, 1}, 136 }; 137 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) { 138 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) && 139 defaultCommands[cmdNum].checkRes) { 140 return -1; 141 } 142 } 143 144 natCount = 0; 145 146 return 0; 147} 148 149int NatController::enableNat(const char* intIface, const char* extIface) { 150 ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface); 151 152 if (!isIfaceName(intIface) || !isIfaceName(extIface)) { 153 errno = ENODEV; 154 return -1; 155 } 156 157 /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */ 158 if (!strcmp(intIface, extIface)) { 159 ALOGE("Duplicate interface specified: %s %s", intIface, extIface); 160 errno = EINVAL; 161 return -1; 162 } 163 164 // add this if we are the first added nat 165 if (natCount == 0) { 166 const char *v4Cmd[] = { 167 IPTABLES_PATH, 168 "-w", 169 "-t", 170 "nat", 171 "-A", 172 LOCAL_NAT_POSTROUTING, 173 "-o", 174 extIface, 175 "-j", 176 "MASQUERADE" 177 }; 178 179 /* 180 * IPv6 tethering doesn't need the state-based conntrack rules, so 181 * it unconditionally jumps to the tether counters chain all the time. 182 */ 183 const char *v6Cmd[] = {IP6TABLES_PATH, "-w", "-A", LOCAL_FORWARD, 184 "-g", LOCAL_TETHER_COUNTERS_CHAIN}; 185 186 if (runCmd(ARRAY_SIZE(v4Cmd), v4Cmd) || runCmd(ARRAY_SIZE(v6Cmd), v6Cmd)) { 187 ALOGE("Error setting postroute rule: iface=%s", extIface); 188 // unwind what's been done, but don't care about success - what more could we do? 189 setDefaults(); 190 return -1; 191 } 192 } 193 194 if (setForwardRules(true, intIface, extIface) != 0) { 195 ALOGE("Error setting forward rules"); 196 if (natCount == 0) { 197 setDefaults(); 198 } 199 errno = ENODEV; 200 return -1; 201 } 202 203 /* Always make sure the drop rule is at the end */ 204 const char *cmd1[] = { 205 IPTABLES_PATH, 206 "-w", 207 "-D", 208 LOCAL_FORWARD, 209 "-j", 210 "DROP" 211 }; 212 runCmd(ARRAY_SIZE(cmd1), cmd1); 213 const char *cmd2[] = { 214 IPTABLES_PATH, 215 "-w", 216 "-A", 217 LOCAL_FORWARD, 218 "-j", 219 "DROP" 220 }; 221 runCmd(ARRAY_SIZE(cmd2), cmd2); 222 223 natCount++; 224 return 0; 225} 226 227bool NatController::checkTetherCountingRuleExist(const char *pair_name) { 228 std::list<std::string>::iterator it; 229 230 for (it = ifacePairList.begin(); it != ifacePairList.end(); it++) { 231 if (*it == pair_name) { 232 /* We already have this counter */ 233 return true; 234 } 235 } 236 return false; 237} 238 239int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) { 240 241 /* We only ever add tethering quota rules so that they stick. */ 242 if (!add) { 243 return 0; 244 } 245 char *pair_name; 246 asprintf(&pair_name, "%s_%s", intIface, extIface); 247 248 if (checkTetherCountingRuleExist(pair_name)) { 249 free(pair_name); 250 return 0; 251 } 252 const char *cmd2b[] = { 253 IPTABLES_PATH, 254 "-w", "-A", LOCAL_TETHER_COUNTERS_CHAIN, "-i", intIface, "-o", extIface, "-j", "RETURN" 255 }; 256 257 const char *cmd2c[] = { 258 IP6TABLES_PATH, 259 "-w", "-A", LOCAL_TETHER_COUNTERS_CHAIN, "-i", intIface, "-o", extIface, "-j", "RETURN" 260 }; 261 262 if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) || runCmd(ARRAY_SIZE(cmd2c), cmd2c)) { 263 free(pair_name); 264 return -1; 265 } 266 ifacePairList.push_front(pair_name); 267 free(pair_name); 268 269 asprintf(&pair_name, "%s_%s", extIface, intIface); 270 if (checkTetherCountingRuleExist(pair_name)) { 271 free(pair_name); 272 return 0; 273 } 274 275 const char *cmd3b[] = { 276 IPTABLES_PATH, 277 "-w", "-A", LOCAL_TETHER_COUNTERS_CHAIN, "-i", extIface, "-o", intIface, "-j", "RETURN" 278 }; 279 280 const char *cmd3c[] = { 281 IP6TABLES_PATH, 282 "-w", "-A", LOCAL_TETHER_COUNTERS_CHAIN, "-i", extIface, "-o", intIface, "-j", "RETURN" 283 }; 284 285 if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) || runCmd(ARRAY_SIZE(cmd3c), cmd3c)) { 286 // unwind what's been done, but don't care about success - what more could we do? 287 free(pair_name); 288 return -1; 289 } 290 ifacePairList.push_front(pair_name); 291 free(pair_name); 292 return 0; 293} 294 295int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) { 296 const char *cmd1[] = { 297 IPTABLES_PATH, 298 "-w", 299 add ? "-A" : "-D", 300 LOCAL_FORWARD, 301 "-i", 302 extIface, 303 "-o", 304 intIface, 305 "-m", 306 "state", 307 "--state", 308 "ESTABLISHED,RELATED", 309 "-g", 310 LOCAL_TETHER_COUNTERS_CHAIN 311 }; 312 int rc = 0; 313 314 if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) { 315 return -1; 316 } 317 318 const char *cmd2[] = { 319 IPTABLES_PATH, 320 "-w", 321 add ? "-A" : "-D", 322 LOCAL_FORWARD, 323 "-i", 324 intIface, 325 "-o", 326 extIface, 327 "-m", 328 "state", 329 "--state", 330 "INVALID", 331 "-j", 332 "DROP" 333 }; 334 335 const char *cmd3[] = { 336 IPTABLES_PATH, 337 "-w", 338 add ? "-A" : "-D", 339 LOCAL_FORWARD, 340 "-i", 341 intIface, 342 "-o", 343 extIface, 344 "-g", 345 LOCAL_TETHER_COUNTERS_CHAIN 346 }; 347 348 const char *cmd4[] = { 349 IP6TABLES_PATH, 350 "-w", 351 "-t", 352 "raw", 353 add ? "-A" : "-D", 354 LOCAL_RAW_PREROUTING, 355 "-i", 356 intIface, 357 "-m", 358 "rpfilter", 359 "--invert", 360 "!", 361 "-s", 362 "fe80::/64", 363 "-j", 364 "DROP" 365 }; 366 367 if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) { 368 // bail on error, but only if adding 369 rc = -1; 370 goto err_invalid_drop; 371 } 372 373 if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) { 374 // unwind what's been done, but don't care about success - what more could we do? 375 rc = -1; 376 goto err_return; 377 } 378 379 if (runCmd(ARRAY_SIZE(cmd4), cmd4) && add) { 380 rc = -1; 381 goto err_rpfilter; 382 } 383 384 if (setTetherCountingRules(add, intIface, extIface) && add) { 385 rc = -1; 386 goto err_return; 387 } 388 389 return 0; 390 391err_rpfilter: 392 cmd3[2] = "-D"; 393 runCmd(ARRAY_SIZE(cmd3), cmd3); 394err_return: 395 cmd2[2] = "-D"; 396 runCmd(ARRAY_SIZE(cmd2), cmd2); 397err_invalid_drop: 398 cmd1[2] = "-D"; 399 runCmd(ARRAY_SIZE(cmd1), cmd1); 400 return rc; 401} 402 403int NatController::disableNat(const char* intIface, const char* extIface) { 404 if (!isIfaceName(intIface) || !isIfaceName(extIface)) { 405 errno = ENODEV; 406 return -1; 407 } 408 409 setForwardRules(false, intIface, extIface); 410 if (--natCount <= 0) { 411 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0 412 setDefaults(); 413 } 414 return 0; 415} 416