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