• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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