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
NatController()51 NatController::NatController() {
52 }
53
~NatController()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
runCmd(int argc,const char ** argv)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
setupIptablesHooks()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
setDefaults()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
enableNat(const char * intIface,const char * extIface)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
checkTetherCountingRuleExist(const char * pair_name)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
setTetherCountingRules(bool add,const char * intIface,const char * extIface)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
setForwardRules(bool add,const char * intIface,const char * extIface)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
disableNat(const char * intIface,const char * extIface)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