1 /*
2 * Copyright (C) 2012 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 <set>
18
19 #include <errno.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <cstdint>
25
26 #define LOG_TAG "FirewallController"
27 #define LOG_NDEBUG 0
28
29 #include <android-base/file.h>
30 #include <android-base/stringprintf.h>
31 #include <android-base/strings.h>
32 #include <log/log.h>
33
34 #include "Controllers.h"
35 #include "FirewallController.h"
36 #include "NetdConstants.h"
37
38 using android::base::Join;
39 using android::base::StringAppendF;
40 using android::base::StringPrintf;
41
42 namespace android {
43 namespace net {
44
45 auto FirewallController::execIptablesRestore = ::execIptablesRestore;
46
47 const char* FirewallController::TABLE = "filter";
48
49 const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
50 const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
51 const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
52
53 // ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
54 // fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
55 // to be able to send (e.g., RS, NS), and packets that we need to receive (e.g., RA, NA).
56 const char* FirewallController::ICMPV6_TYPES[] = {
57 "packet-too-big",
58 "router-solicitation",
59 "router-advertisement",
60 "neighbour-solicitation",
61 "neighbour-advertisement",
62 "redirect",
63 };
64
FirewallController(void)65 FirewallController::FirewallController(void) {
66 // If no rules are set, it's in DENYLIST mode
67 mFirewallType = DENYLIST;
68 mIfaceRules = {};
69 }
70
setupIptablesHooks(void)71 int FirewallController::setupIptablesHooks(void) {
72 return flushRules();
73 }
74
setFirewallType(FirewallType ftype)75 int FirewallController::setFirewallType(FirewallType ftype) {
76 int res = 0;
77 if (mFirewallType != ftype) {
78 // flush any existing rules
79 resetFirewall();
80
81 if (ftype == ALLOWLIST) {
82 // create default rule to drop all traffic
83 std::string command =
84 "*filter\n"
85 "-A fw_INPUT -j DROP\n"
86 "-A fw_OUTPUT -j REJECT\n"
87 "-A fw_FORWARD -j REJECT\n"
88 "COMMIT\n";
89 res = execIptablesRestore(V4V6, command.c_str());
90 }
91
92 // Set this after calling disableFirewall(), since it defaults to ALLOWLIST there
93 mFirewallType = ftype;
94 }
95 return res ? -EREMOTEIO : 0;
96 }
97
flushRules()98 int FirewallController::flushRules() {
99 std::string command =
100 "*filter\n"
101 ":fw_INPUT -\n"
102 ":fw_OUTPUT -\n"
103 ":fw_FORWARD -\n"
104 "-6 -A fw_OUTPUT ! -o lo -s ::1 -j DROP\n"
105 "COMMIT\n";
106
107 return (execIptablesRestore(V4V6, command.c_str()) == 0) ? 0 : -EREMOTEIO;
108 }
109
resetFirewall(void)110 int FirewallController::resetFirewall(void) {
111 mFirewallType = ALLOWLIST;
112 mIfaceRules.clear();
113 return flushRules();
114 }
115
isFirewallEnabled(void)116 int FirewallController::isFirewallEnabled(void) {
117 // TODO: verify that rules are still in place near top
118 return -1;
119 }
120
setInterfaceRule(const char * iface,FirewallRule rule)121 int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
122 if (mFirewallType == DENYLIST) {
123 // Unsupported in DENYLIST mode
124 return -EINVAL;
125 }
126
127 if (!isIfaceName(iface)) {
128 errno = ENOENT;
129 return -ENOENT;
130 }
131
132 // Only delete rules if we actually added them, because otherwise our iptables-restore
133 // processes will terminate with "no such rule" errors and cause latency penalties while we
134 // spin up new ones.
135 const char* op;
136 if (rule == ALLOW && mIfaceRules.find(iface) == mIfaceRules.end()) {
137 op = "-I";
138 mIfaceRules.insert(iface);
139 } else if (rule == DENY && mIfaceRules.find(iface) != mIfaceRules.end()) {
140 op = "-D";
141 mIfaceRules.erase(iface);
142 } else {
143 return 0;
144 }
145
146 std::string command = Join(std::vector<std::string> {
147 "*filter",
148 StringPrintf("%s fw_INPUT -i %s -j RETURN", op, iface),
149 StringPrintf("%s fw_OUTPUT -o %s -j RETURN", op, iface),
150 "COMMIT\n"
151 }, "\n");
152 return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
153 }
154
155 /* static */
makeCriticalCommands(IptablesTarget target,const char * chainName)156 std::string FirewallController::makeCriticalCommands(IptablesTarget target, const char* chainName) {
157 // Allow ICMPv6 packets necessary to make IPv6 connectivity work. http://b/23158230 .
158 std::string commands;
159 if (target == V6) {
160 for (size_t i = 0; i < ARRAY_SIZE(ICMPV6_TYPES); i++) {
161 StringAppendF(&commands, "-A %s -p icmpv6 --icmpv6-type %s -j RETURN\n",
162 chainName, ICMPV6_TYPES[i]);
163 }
164 }
165 return commands;
166 }
167
168 } // namespace net
169 } // namespace android
170