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