1 /*
2 * Copyright (C) 2016 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 #include <cinttypes>
18 #include <regex>
19 #include <set>
20 #include <string>
21
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 #include <netdutils/Stopwatch.h>
25
26 #define LOG_TAG "Netd"
27 #include <log/log.h>
28
29 #include "ConnmarkFlags.h"
30 #include "Controllers.h"
31 #include "IdletimerController.h"
32 #include "NetworkController.h"
33 #include "RouteController.h"
34 #include "XfrmController.h"
35 #include "oem_iptables_hook.h"
36
37 namespace android {
38 namespace net {
39
40 using android::base::Join;
41 using android::base::StringAppendF;
42 using android::base::StringPrintf;
43 using android::netdutils::Stopwatch;
44
45 auto Controllers::execIptablesRestore = ::execIptablesRestore;
46 auto Controllers::execIptablesRestoreWithOutput = ::execIptablesRestoreWithOutput;
47
48 netdutils::Log gLog("netd");
49 netdutils::Log gUnsolicitedLog("netdUnsolicited");
50
51 namespace {
52
53 static constexpr char CONNMARK_MANGLE_INPUT[] = "connmark_mangle_INPUT";
54 static constexpr char CONNMARK_MANGLE_OUTPUT[] = "connmark_mangle_OUTPUT";
55
56 /**
57 * List of module chains to be created, along with explicit ordering. ORDERING
58 * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
59 */
60 static const std::vector<const char*> FILTER_INPUT = {
61 // Bandwidth should always be early in input chain, to make sure we
62 // correctly count incoming traffic against data plan.
63 OEM_IPTABLES_FILTER_INPUT,
64 BandwidthController::LOCAL_INPUT,
65 FirewallController::LOCAL_INPUT,
66 };
67
68 static const std::vector<const char*> FILTER_FORWARD = {
69 OEM_IPTABLES_FILTER_FORWARD,
70 FirewallController::LOCAL_FORWARD,
71 BandwidthController::LOCAL_FORWARD,
72 TetherController::LOCAL_FORWARD,
73 };
74
75 static const std::vector<const char*> FILTER_OUTPUT = {
76 OEM_IPTABLES_FILTER_OUTPUT,
77 FirewallController::LOCAL_OUTPUT,
78 StrictController::LOCAL_OUTPUT,
79 BandwidthController::LOCAL_OUTPUT,
80 };
81
82 static const std::vector<const char*> RAW_PREROUTING = {
83 IdletimerController::LOCAL_RAW_PREROUTING,
84 BandwidthController::LOCAL_RAW_PREROUTING,
85 TetherController::LOCAL_RAW_PREROUTING,
86 };
87
88 static const std::vector<const char*> MANGLE_POSTROUTING = {
89 OEM_IPTABLES_MANGLE_POSTROUTING,
90 BandwidthController::LOCAL_MANGLE_POSTROUTING,
91 IdletimerController::LOCAL_MANGLE_POSTROUTING,
92 };
93
94 static const std::vector<const char*> MANGLE_INPUT = {
95 CONNMARK_MANGLE_INPUT,
96 WakeupController::LOCAL_MANGLE_INPUT,
97 RouteController::LOCAL_MANGLE_INPUT,
98 };
99
100 static const std::vector<const char*> MANGLE_FORWARD = {
101 TetherController::LOCAL_MANGLE_FORWARD,
102 };
103
104 static const std::vector<const char*> MANGLE_OUTPUT = {
105 CONNMARK_MANGLE_OUTPUT,
106 };
107
108 static const std::vector<const char*> NAT_PREROUTING = {
109 OEM_IPTABLES_NAT_PREROUTING,
110 };
111
112 static const std::vector<const char*> NAT_POSTROUTING = {
113 TetherController::LOCAL_NAT_POSTROUTING,
114 };
115
116 // Commands to create child chains and to match created chains in iptables -S output. Keep in sync.
117 static const char* CHILD_CHAIN_TEMPLATE = "-A %s -j %s\n";
118 static const std::regex CHILD_CHAIN_REGEX("^-A ([^ ]+) -j ([^ ]+)$",
119 std::regex_constants::extended);
120
121 } // namespace
122
123 /* static */
findExistingChildChains(const IptablesTarget target,const char * table,const char * parentChain)124 std::set<std::string> Controllers::findExistingChildChains(const IptablesTarget target,
125 const char* table,
126 const char* parentChain) {
127 if (target == V4V6) {
128 ALOGE("findExistingChildChains only supports one protocol at a time");
129 abort();
130 }
131
132 std::set<std::string> existing;
133
134 // List the current contents of parentChain.
135 //
136 // TODO: there is no guarantee that nothing else modifies the chain in the few milliseconds
137 // between when we list the existing rules and when we delete them. However:
138 // - Since this code is only run on startup, nothing else in netd will be running.
139 // - While vendor code is known to add its own rules to chains created by netd, it should never
140 // be modifying the rules in childChains or the rules that hook said chains into their parent
141 // chains.
142 std::string command = StringPrintf("*%s\n-S %s\nCOMMIT\n", table, parentChain);
143 std::string output;
144 if (Controllers::execIptablesRestoreWithOutput(target, command, &output) == -1) {
145 ALOGE("Error listing chain %s in table %s", parentChain, table);
146 return existing;
147 }
148
149 // The only rules added by createChildChains are of the simple form "-A <parent> -j <child>".
150 // Find those rules and add each one's child chain to existing.
151 std::smatch matches;
152 std::stringstream stream(output);
153 std::string rule;
154 while (std::getline(stream, rule, '\n')) {
155 if (std::regex_search(rule, matches, CHILD_CHAIN_REGEX) && matches[1] == parentChain) {
156 existing.insert(matches[2]);
157 }
158 }
159
160 return existing;
161 }
162
163 /* static */
createChildChains(IptablesTarget target,const char * table,const char * parentChain,const std::vector<const char * > & childChains,bool exclusive)164 void Controllers::createChildChains(IptablesTarget target, const char* table,
165 const char* parentChain,
166 const std::vector<const char*>& childChains,
167 bool exclusive) {
168 std::string command = StringPrintf("*%s\n", table);
169
170 // We cannot just clear all the chains we create because vendor code modifies filter OUTPUT and
171 // mangle POSTROUTING directly. So:
172 //
173 // - If we're the exclusive owner of this chain, simply clear it entirely.
174 // - If not, then list the chain's current contents to ensure that if we restart after a crash,
175 // we leave the existing rules alone in the positions they currently occupy. This is faster
176 // than blindly deleting our rules and recreating them, because deleting a rule that doesn't
177 // exists causes iptables-restore to quit, which takes ~30ms per delete. It's also more
178 // correct, because if we delete rules and re-add them, they'll be in the wrong position with
179 // regards to the vendor rules.
180 //
181 // TODO: Make all chains exclusive once vendor code uses the oem_* rules.
182 std::set<std::string> existingChildChains;
183 if (exclusive) {
184 // Just running ":chain -" flushes user-defined chains, but not built-in chains like INPUT.
185 // Since at this point we don't know if parentChain is a built-in chain, do both.
186 StringAppendF(&command, ":%s -\n", parentChain);
187 StringAppendF(&command, "-F %s\n", parentChain);
188 } else {
189 existingChildChains = findExistingChildChains(target, table, parentChain);
190 }
191
192 for (const auto& childChain : childChains) {
193 // Always clear the child chain.
194 StringAppendF(&command, ":%s -\n", childChain);
195 // But only add it to the parent chain if it's not already there.
196 if (existingChildChains.find(childChain) == existingChildChains.end()) {
197 StringAppendF(&command, CHILD_CHAIN_TEMPLATE, parentChain, childChain);
198 }
199 }
200 command += "COMMIT\n";
201 execIptablesRestore(target, command);
202 }
203
Controllers()204 Controllers::Controllers()
205 : wakeupCtrl(
206 [this](const WakeupController::ReportArgs& args) {
207 const auto listener = eventReporter.getNetdEventListener();
208 if (listener == nullptr) {
209 gLog.error("getNetdEventListener() returned nullptr. dropping wakeup event");
210 return;
211 }
212 String16 prefix = String16(args.prefix.c_str());
213 String16 srcIp = String16(args.srcIp.c_str());
214 String16 dstIp = String16(args.dstIp.c_str());
215 listener->onWakeupEvent(prefix, args.uid, args.ethertype, args.ipNextHeader,
216 args.dstHw, srcIp, dstIp, args.srcPort, args.dstPort,
217 args.timestampNs);
218 },
219 &iptablesRestoreCtrl) {
220 InterfaceController::initializeAll();
221 }
222
initChildChains()223 void Controllers::initChildChains() {
224 /*
225 * This is the only time we touch top-level chains in iptables; controllers
226 * should only mutate rules inside of their children chains, as created by
227 * the constants above.
228 *
229 * Modules should never ACCEPT packets (except in well-justified cases);
230 * they should instead defer to any remaining modules using RETURN, or
231 * otherwise DROP/REJECT.
232 */
233
234 // Create chains for child modules.
235 createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT, true);
236 createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD, true);
237 createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING, true);
238 createChildChains(V4V6, "mangle", "FORWARD", MANGLE_FORWARD, true);
239 createChildChains(V4V6, "mangle", "INPUT", MANGLE_INPUT, true);
240 createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT, true);
241 createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING, true);
242 createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING, true);
243
244 createChildChains(V4, "filter", "OUTPUT", FILTER_OUTPUT, false);
245 createChildChains(V6, "filter", "OUTPUT", FILTER_OUTPUT, false);
246 createChildChains(V4, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
247 createChildChains(V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING, false);
248 }
249
setupConnmarkIptablesHooks()250 static void setupConnmarkIptablesHooks() {
251 // Rules to store parts of the fwmark (namely: netId, explicitlySelected, protectedFromVpn,
252 // permission) in connmark.
253 // Only saves the mark if no mark has been set before.
254 static_assert(std::string_view(CONNMARK_MANGLE_INPUT) == "connmark_mangle_INPUT");
255 static_assert(std::string_view(CONNMARK_MANGLE_OUTPUT) == "connmark_mangle_OUTPUT");
256 static_assert(CONNMARK_FWMARK_MASK == 0x000FFFFF);
257 const std::string cmd(
258 // CONNMARK:
259 // --save-mark [--nfmask nfmask] [--ctmask ctmask]
260 // Copy the packet mark (nfmark) to the connection mark (ctmark) using the given
261 // masks. The new nfmark value is determined as follows:
262 // ctmark = (ctmark & ~ctmask) ^ (nfmark & nfmask)
263 // i.e. ctmask defines what bits to clear and nfmask what bits of the nfmark to
264 // XOR into the ctmark. ctmask and nfmask default to 0xFFFFFFFF.
265 "*mangle\n"
266 "-A connmark_mangle_INPUT -m connmark --mark 0/0x000FFFFF "
267 "-j CONNMARK --save-mark --ctmask 0x000FFFFF --nfmask 0x000FFFFF\n"
268 "-A connmark_mangle_OUTPUT -m connmark --mark 0/0x000FFFFF "
269 "-j CONNMARK --save-mark --ctmask 0x000FFFFF --nfmask 0x000FFFFF\n"
270 "COMMIT\n");
271 execIptablesRestore(V4V6, cmd);
272 }
273
initIptablesRules()274 void Controllers::initIptablesRules() {
275 Stopwatch s;
276 initChildChains();
277 gLog.info("Creating child chains: %" PRId64 "us", s.getTimeAndResetUs());
278
279 // Let each module setup their child chains
280 setupOemIptablesHook();
281 gLog.info("Setting up OEM hooks: %" PRId64 "us", s.getTimeAndResetUs());
282
283 /* When enabled, DROPs all packets except those matching rules. */
284 firewallCtrl.setupIptablesHooks();
285 gLog.info("Setting up FirewallController hooks: %" PRId64 "us", s.getTimeAndResetUs());
286
287 /* Does DROPs in FORWARD by default */
288 tetherCtrl.setupIptablesHooks();
289 gLog.info("Setting up TetherController hooks: %" PRId64 "us", s.getTimeAndResetUs());
290
291 /*
292 * Does REJECT in INPUT, OUTPUT. Does counting also.
293 * No DROP/REJECT allowed later in netfilter-flow hook order.
294 */
295 bandwidthCtrl.setupIptablesHooks();
296 gLog.info("Setting up BandwidthController hooks: %" PRId64 "us", s.getTimeAndResetUs());
297
298 /*
299 * Counts in nat: PREROUTING, POSTROUTING.
300 * No DROP/REJECT allowed later in netfilter-flow hook order.
301 */
302 idletimerCtrl.setupIptablesHooks();
303 gLog.info("Setting up IdletimerController hooks: %" PRId64 "us", s.getTimeAndResetUs());
304
305 /*
306 * Add rules for detecting IPv6/IPv4 TCP/UDP connections with TLS/DTLS header
307 */
308 strictCtrl.setupIptablesHooks();
309 gLog.info("Setting up StrictController hooks: %" PRId64 "us", s.getTimeAndResetUs());
310
311 /*
312 * Add rules for storing netid in connmark.
313 */
314 setupConnmarkIptablesHooks();
315 gLog.info("Setting up connmark hooks: %" PRId64 "us", s.getTimeAndResetUs());
316 }
317
init()318 void Controllers::init() {
319 initIptablesRules();
320 Stopwatch s;
321
322 if (int ret = bandwidthCtrl.enableBandwidthControl()) {
323 gLog.error("Failed to initialize BandwidthController (%s)", strerror(-ret));
324 // A failure to init almost definitely means that iptables failed to load
325 // our static ruleset, which then basically means network accounting will not work.
326 // As such simply exit netd. This may crash loop the system, but by failing
327 // to bootup we will trigger rollback and thus this offers us protection against
328 // a mainline update breaking things.
329 exit(1);
330 }
331 gLog.info("Enabling bandwidth control: %" PRId64 "us", s.getTimeAndResetUs());
332
333 if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {
334 gLog.error("Failed to initialize RouteController (%s)", strerror(-ret));
335 exit(2);
336 }
337 gLog.info("Initializing RouteController: %" PRId64 "us", s.getTimeAndResetUs());
338
339 netdutils::Status xStatus = XfrmController::Init();
340 if (!isOk(xStatus)) {
341 gLog.error("Failed to initialize XfrmController (%s)", netdutils::toString(xStatus).c_str());
342 exit(3);
343 };
344 gLog.info("Initializing XfrmController: %" PRId64 "us", s.getTimeAndResetUs());
345 }
346
347 Controllers* gCtls = nullptr;
348
349 } // namespace net
350 } // namespace android
351