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 <string>
20#include <vector>
21
22#include <errno.h>
23#include <fcntl.h>
24#include <stdlib.h>
25#include <string.h>
26#include <arpa/inet.h>
27#include <linux/in.h>
28#include <netinet/in.h>
29#include <sys/socket.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32
33#define LOG_TAG "NatController"
34#include <android-base/strings.h>
35#include <android-base/stringprintf.h>
36#include <cutils/log.h>
37#include <cutils/properties.h>
38#include <logwrap/logwrap.h>
39
40#include "NatController.h"
41#include "NetdConstants.h"
42#include "RouteController.h"
43
44using android::base::Join;
45using android::base::StringPrintf;
46
47const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
48const char* NatController::LOCAL_MANGLE_FORWARD = "natctrl_mangle_FORWARD";
49const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
50const char* NatController::LOCAL_RAW_PREROUTING = "natctrl_raw_PREROUTING";
51const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
52
53auto NatController::execFunction = android_fork_execvp;
54auto NatController::iptablesRestoreFunction = execIptablesRestore;
55
56NatController::NatController() {
57}
58
59NatController::~NatController() {
60}
61
62struct CommandsAndArgs {
63    /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
64    const char *cmd[32];
65    bool checkRes;
66};
67
68int NatController::setupIptablesHooks() {
69    int res;
70    res = setDefaults();
71    if (res < 0) {
72        return res;
73    }
74
75    // Used to limit downstream mss to the upstream pmtu so we don't end up fragmenting every large
76    // packet tethered devices send. This is IPv4-only, because in IPv6 we send the MTU in the RA.
77    // This is no longer optional and tethering will fail to start if it fails.
78    std::string mssRewriteCommand = StringPrintf(
79        "*mangle\n"
80        "-A %s -p tcp --tcp-flags SYN SYN -j TCPMSS --clamp-mss-to-pmtu\n"
81        "COMMIT\n", LOCAL_MANGLE_FORWARD);
82
83    // This is for tethering counters. This chain is reached via --goto, and then RETURNS.
84    std::string defaultCommands = StringPrintf(
85        "*filter\n"
86        ":%s -\n"
87        "COMMIT\n", LOCAL_TETHER_COUNTERS_CHAIN);
88
89    res = iptablesRestoreFunction(V4, mssRewriteCommand);
90    if (res < 0) {
91        return res;
92    }
93
94    res = iptablesRestoreFunction(V4V6, defaultCommands);
95    if (res < 0) {
96        return res;
97    }
98
99    ifacePairList.clear();
100
101    return 0;
102}
103
104int NatController::setDefaults() {
105    std::string v4Cmd = StringPrintf(
106        "*filter\n"
107        ":%s -\n"
108        "-A %s -j DROP\n"
109        "COMMIT\n"
110        "*nat\n"
111        ":%s -\n"
112        "COMMIT\n", LOCAL_FORWARD, LOCAL_FORWARD, LOCAL_NAT_POSTROUTING);
113
114    std::string v6Cmd = StringPrintf(
115        "*filter\n"
116        ":%s -\n"
117        "COMMIT\n"
118        "*raw\n"
119        ":%s -\n"
120        "COMMIT\n", LOCAL_FORWARD, LOCAL_RAW_PREROUTING);
121
122    int res = iptablesRestoreFunction(V4, v4Cmd);
123    if (res < 0) {
124        return res;
125    }
126
127    res = iptablesRestoreFunction(V6, v6Cmd);
128    if (res < 0) {
129        return res;
130    }
131
132    natCount = 0;
133
134    return 0;
135}
136
137int NatController::enableNat(const char* intIface, const char* extIface) {
138    ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
139
140    if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
141        errno = ENODEV;
142        return -1;
143    }
144
145    /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
146    if (!strcmp(intIface, extIface)) {
147        ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
148        errno = EINVAL;
149        return -1;
150    }
151
152    // add this if we are the first added nat
153    if (natCount == 0) {
154        std::vector<std::string> v4Cmds = {
155            "*nat",
156            StringPrintf("-A %s -o %s -j MASQUERADE", LOCAL_NAT_POSTROUTING, extIface),
157            "COMMIT\n"
158        };
159
160        /*
161         * IPv6 tethering doesn't need the state-based conntrack rules, so
162         * it unconditionally jumps to the tether counters chain all the time.
163         */
164        std::vector<std::string> v6Cmds = {
165            "*filter",
166            StringPrintf("-A %s -g %s", LOCAL_FORWARD, LOCAL_TETHER_COUNTERS_CHAIN),
167            "COMMIT\n"
168        };
169
170        if (iptablesRestoreFunction(V4, Join(v4Cmds, '\n')) ||
171            iptablesRestoreFunction(V6, Join(v6Cmds, '\n'))) {
172            ALOGE("Error setting postroute rule: iface=%s", extIface);
173            // unwind what's been done, but don't care about success - what more could we do?
174            setDefaults();
175            return -1;
176        }
177    }
178
179    if (setForwardRules(true, intIface, extIface) != 0) {
180        ALOGE("Error setting forward rules");
181        if (natCount == 0) {
182            setDefaults();
183        }
184        errno = ENODEV;
185        return -1;
186    }
187
188    natCount++;
189    return 0;
190}
191
192bool NatController::checkTetherCountingRuleExist(const std::string& pair_name) {
193    return std::find(ifacePairList.begin(), ifacePairList.end(), pair_name) != ifacePairList.end();
194}
195
196/* static */
197std::string NatController::makeTetherCountingRule(const char *if1, const char *if2) {
198    return StringPrintf("-A %s -i %s -o %s -j RETURN", LOCAL_TETHER_COUNTERS_CHAIN, if1, if2);
199}
200
201int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
202    const char *op = add ? "-A" : "-D";
203
204    std::string rpfilterCmd = StringPrintf(
205        "*raw\n"
206        "%s %s -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
207        "COMMIT\n", op, LOCAL_RAW_PREROUTING, intIface);
208    if (iptablesRestoreFunction(V6, rpfilterCmd) == -1 && add) {
209        return -1;
210    }
211
212    std::vector<std::string> v4 = {
213        "*filter",
214        StringPrintf("%s %s -i %s -o %s -m state --state ESTABLISHED,RELATED -g %s",
215                     op, LOCAL_FORWARD, extIface, intIface, LOCAL_TETHER_COUNTERS_CHAIN),
216        StringPrintf("%s %s -i %s -o %s -m state --state INVALID -j DROP",
217                     op, LOCAL_FORWARD, intIface, extIface),
218        StringPrintf("%s %s -i %s -o %s -g %s",
219                     op, LOCAL_FORWARD, intIface, extIface, LOCAL_TETHER_COUNTERS_CHAIN),
220    };
221
222    std::vector<std::string> v6 = {
223        "*filter",
224    };
225
226    /* We only ever add tethering quota rules so that they stick. */
227    std::string pair1 = StringPrintf("%s_%s", intIface, extIface);
228    if (add && !checkTetherCountingRuleExist(pair1)) {
229        v4.push_back(makeTetherCountingRule(intIface, extIface));
230        v6.push_back(makeTetherCountingRule(intIface, extIface));
231    }
232    std::string pair2 = StringPrintf("%s_%s", extIface, intIface);
233    if (add && !checkTetherCountingRuleExist(pair2)) {
234        v4.push_back(makeTetherCountingRule(extIface, intIface));
235        v6.push_back(makeTetherCountingRule(extIface, intIface));
236    }
237
238    // Always make sure the drop rule is at the end.
239    // TODO: instead of doing this, consider just rebuilding LOCAL_FORWARD completely from scratch
240    // every time, starting with ":natctrl_FORWARD -\n". This method would likely be a bit simpler.
241    if (add) {
242        v4.push_back(StringPrintf("-D %s -j DROP", LOCAL_FORWARD));
243        v4.push_back(StringPrintf("-A %s -j DROP", LOCAL_FORWARD));
244    }
245
246    v4.push_back("COMMIT\n");
247    v6.push_back("COMMIT\n");
248
249    // We only add IPv6 rules here, never remove them.
250    if (iptablesRestoreFunction(V4, Join(v4, '\n')) == -1 ||
251        (add && iptablesRestoreFunction(V6, Join(v6, '\n')) == -1)) {
252        // unwind what's been done, but don't care about success - what more could we do?
253        if (add) {
254            setForwardRules(false, intIface, extIface);
255        }
256        return -1;
257    }
258
259    if (add && !checkTetherCountingRuleExist(pair1)) {
260        ifacePairList.push_front(pair1);
261    }
262    if (add && !checkTetherCountingRuleExist(pair2)) {
263        ifacePairList.push_front(pair2);
264    }
265
266    return 0;
267}
268
269int NatController::disableNat(const char* intIface, const char* extIface) {
270    if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
271        errno = ENODEV;
272        return -1;
273    }
274
275    setForwardRules(false, intIface, extIface);
276    if (--natCount <= 0) {
277        // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
278        setDefaults();
279    }
280    return 0;
281}
282