blob: 4847c85def58e8b7cf234b2e0c38a01d86cc5b41 [file] [log] [blame]
Jeff Sharkeyd8c64022012-07-13 18:04:07 -07001/*
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 <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#define LOG_TAG "FirewallController"
23#define LOG_NDEBUG 0
24
25#include <cutils/log.h>
26
27#include "NetdConstants.h"
28#include "FirewallController.h"
29
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070030const char* FirewallController::TABLE = "filter";
31
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070032const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
33const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
34const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
35
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070036const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
37const char* FirewallController::LOCAL_STANDBY = "fw_standby";
38
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070039FirewallController::FirewallController(void) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -070040 // If no rules are set, it's in BLACKLIST mode
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070041 mFirewallType = BLACKLIST;
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070042}
43
44int FirewallController::setupIptablesHooks(void) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070045 int res = 0;
46 // child chains are created but not attached, they will be attached explicitly.
47 FirewallType firewallType = getFirewallType(DOZABLE);
48 res |= createChain(LOCAL_DOZABLE, LOCAL_INPUT, firewallType);
49
50 firewallType = getFirewallType(STANDBY);
51 res |= createChain(LOCAL_STANDBY, LOCAL_INPUT, firewallType);
52
53 return res;
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070054}
55
Amith Yamasani390e4ea2015-04-25 19:08:57 -070056int FirewallController::enableFirewall(FirewallType ftype) {
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070057 int res = 0;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070058 if (mFirewallType != ftype) {
59 // flush any existing rules
60 disableFirewall();
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070061
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070062 if (ftype == WHITELIST) {
63 // create default rule to drop all traffic
64 res |= execIptables(V4V6, "-A", LOCAL_INPUT, "-j", "DROP", NULL);
65 res |= execIptables(V4V6, "-A", LOCAL_OUTPUT, "-j", "REJECT", NULL);
66 res |= execIptables(V4V6, "-A", LOCAL_FORWARD, "-j", "REJECT", NULL);
67 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070068
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070069 // Set this after calling disableFirewall(), since it defaults to WHITELIST there
70 mFirewallType = ftype;
Amith Yamasani390e4ea2015-04-25 19:08:57 -070071 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070072 return res;
73}
74
75int FirewallController::disableFirewall(void) {
76 int res = 0;
77
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070078 mFirewallType = WHITELIST;
Amith Yamasani390e4ea2015-04-25 19:08:57 -070079
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070080 // flush any existing rules
81 res |= execIptables(V4V6, "-F", LOCAL_INPUT, NULL);
82 res |= execIptables(V4V6, "-F", LOCAL_OUTPUT, NULL);
83 res |= execIptables(V4V6, "-F", LOCAL_FORWARD, NULL);
84
85 return res;
86}
87
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070088int FirewallController::enableChildChains(ChildChain chain, bool enable) {
89 int res = 0;
90 const char* name;
91 switch(chain) {
92 case DOZABLE:
93 name = LOCAL_DOZABLE;
94 break;
95 case STANDBY:
96 name = LOCAL_STANDBY;
97 break;
98 default:
99 return res;
100 }
101
102 if (enable) {
103 res |= attachChain(name, LOCAL_INPUT);
104 res |= attachChain(name, LOCAL_OUTPUT);
105 } else {
106 res |= detachChain(name, LOCAL_INPUT);
107 res |= detachChain(name, LOCAL_OUTPUT);
108 }
109 return res;
110}
111
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700112int FirewallController::isFirewallEnabled(void) {
113 // TODO: verify that rules are still in place near top
114 return -1;
115}
116
117int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700118 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700119 // Unsupported in BLACKLIST mode
120 return -1;
121 }
122
JP Abgrall69261cb2014-06-19 18:35:24 -0700123 if (!isIfaceName(iface)) {
124 errno = ENOENT;
125 return -1;
126 }
127
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700128 const char* op;
129 if (rule == ALLOW) {
130 op = "-I";
131 } else {
132 op = "-D";
133 }
134
135 int res = 0;
136 res |= execIptables(V4V6, op, LOCAL_INPUT, "-i", iface, "-j", "RETURN", NULL);
137 res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-o", iface, "-j", "RETURN", NULL);
138 return res;
139}
140
141int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700142 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700143 // Unsupported in BLACKLIST mode
144 return -1;
145 }
146
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700147 IptablesTarget target = V4;
148 if (strchr(addr, ':')) {
149 target = V6;
150 }
151
152 const char* op;
153 if (rule == ALLOW) {
154 op = "-I";
155 } else {
156 op = "-D";
157 }
158
159 int res = 0;
160 res |= execIptables(target, op, LOCAL_INPUT, "-d", addr, "-j", "RETURN", NULL);
161 res |= execIptables(target, op, LOCAL_OUTPUT, "-s", addr, "-j", "RETURN", NULL);
162 return res;
163}
164
165int FirewallController::setEgressDestRule(const char* addr, int protocol, int port,
166 FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700167 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700168 // Unsupported in BLACKLIST mode
169 return -1;
170 }
171
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700172 IptablesTarget target = V4;
173 if (strchr(addr, ':')) {
174 target = V6;
175 }
176
177 char protocolStr[16];
178 sprintf(protocolStr, "%d", protocol);
179
180 char portStr[16];
181 sprintf(portStr, "%d", port);
182
183 const char* op;
184 if (rule == ALLOW) {
185 op = "-I";
186 } else {
187 op = "-D";
188 }
189
190 int res = 0;
191 res |= execIptables(target, op, LOCAL_INPUT, "-s", addr, "-p", protocolStr,
192 "--sport", portStr, "-j", "RETURN", NULL);
193 res |= execIptables(target, op, LOCAL_OUTPUT, "-d", addr, "-p", protocolStr,
194 "--dport", portStr, "-j", "RETURN", NULL);
195 return res;
196}
197
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700198FirewallType FirewallController::getFirewallType(ChildChain chain) {
199 switch(chain) {
200 case DOZABLE:
201 return WHITELIST;
202 case STANDBY:
203 return BLACKLIST;
204 case NONE:
205 return mFirewallType;
206 default:
207 return BLACKLIST;
208 }
209}
210
211int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700212 char uidStr[16];
213 sprintf(uidStr, "%d", uid);
214
215 const char* op;
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700216 const char* target;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700217 FirewallType firewallType = getFirewallType(chain);
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700218 if (firewallType == WHITELIST) {
219 target = "RETURN";
220 op = (rule == ALLOW)? "-I" : "-D";
221 } else { // BLACKLIST mode
222 target = "DROP";
223 op = (rule == DENY)? "-I" : "-D";
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700224 }
225
226 int res = 0;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700227 switch(chain) {
228 case DOZABLE:
229 res |= execIptables(V4V6, op, LOCAL_DOZABLE, "-m", "owner", "--uid-owner",
230 uidStr, "-j", target, NULL);
231 break;
232 case STANDBY:
233 res |= execIptables(V4V6, op, LOCAL_STANDBY, "-m", "owner", "--uid-owner",
234 uidStr, "-j", target, NULL);
235 break;
236 case NONE:
237 res |= execIptables(V4V6, op, LOCAL_INPUT, "-m", "owner", "--uid-owner", uidStr,
238 "-j", target, NULL);
239 res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-m", "owner", "--uid-owner", uidStr,
240 "-j", target, NULL);
241 break;
242 default:
243 ALOGW("Unknown child chain: %d", chain);
244 break;
245 }
246 return res;
247}
248
249int FirewallController::attachChain(const char* childChain, const char* parentChain) {
250 return execIptables(V4V6, "-t", TABLE, "-A", parentChain, "-j", childChain, NULL);
251}
252
253int FirewallController::detachChain(const char* childChain, const char* parentChain) {
254 return execIptables(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
255}
256
257int FirewallController::createChain(const char* childChain,
258 const char* parentChain, FirewallType type) {
259 // Order is important, otherwise later steps may fail.
260 execIptablesSilently(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
261 execIptablesSilently(V4V6, "-t", TABLE, "-F", childChain, NULL);
262 execIptablesSilently(V4V6, "-t", TABLE, "-X", childChain, NULL);
263 int res = 0;
264 res |= execIptables(V4V6, "-t", TABLE, "-N", childChain, NULL);
265 if (type == WHITELIST) {
266 // create default rule to drop all traffic
267 res |= execIptables(V4V6, "-A", childChain, "-j", "DROP", NULL);
268 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700269 return res;
270}