blob: bcf7524cb3de290a933cbc71f218521fc5e85ae1 [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>
Xiaohui Chenfeb2b612015-06-25 21:19:38 -070026#include <private/android_filesystem_config.h>
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070027
28#include "NetdConstants.h"
29#include "FirewallController.h"
30
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070031const char* FirewallController::TABLE = "filter";
32
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070033const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
34const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
35const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
36
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070037const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
38const char* FirewallController::LOCAL_STANDBY = "fw_standby";
39
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070040FirewallController::FirewallController(void) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -070041 // If no rules are set, it's in BLACKLIST mode
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070042 mFirewallType = BLACKLIST;
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070043}
44
45int FirewallController::setupIptablesHooks(void) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070046 int res = 0;
47 // child chains are created but not attached, they will be attached explicitly.
48 FirewallType firewallType = getFirewallType(DOZABLE);
49 res |= createChain(LOCAL_DOZABLE, LOCAL_INPUT, firewallType);
50
51 firewallType = getFirewallType(STANDBY);
52 res |= createChain(LOCAL_STANDBY, LOCAL_INPUT, firewallType);
53
54 return res;
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070055}
56
Amith Yamasani390e4ea2015-04-25 19:08:57 -070057int FirewallController::enableFirewall(FirewallType ftype) {
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070058 int res = 0;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070059 if (mFirewallType != ftype) {
60 // flush any existing rules
61 disableFirewall();
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070062
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070063 if (ftype == WHITELIST) {
64 // create default rule to drop all traffic
65 res |= execIptables(V4V6, "-A", LOCAL_INPUT, "-j", "DROP", NULL);
66 res |= execIptables(V4V6, "-A", LOCAL_OUTPUT, "-j", "REJECT", NULL);
67 res |= execIptables(V4V6, "-A", LOCAL_FORWARD, "-j", "REJECT", NULL);
68 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070069
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070070 // Set this after calling disableFirewall(), since it defaults to WHITELIST there
71 mFirewallType = ftype;
Amith Yamasani390e4ea2015-04-25 19:08:57 -070072 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070073 return res;
74}
75
76int FirewallController::disableFirewall(void) {
77 int res = 0;
78
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070079 mFirewallType = WHITELIST;
Amith Yamasani390e4ea2015-04-25 19:08:57 -070080
Jeff Sharkeyd8c64022012-07-13 18:04:07 -070081 // flush any existing rules
82 res |= execIptables(V4V6, "-F", LOCAL_INPUT, NULL);
83 res |= execIptables(V4V6, "-F", LOCAL_OUTPUT, NULL);
84 res |= execIptables(V4V6, "-F", LOCAL_FORWARD, NULL);
85
86 return res;
87}
88
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -070089int FirewallController::enableChildChains(ChildChain chain, bool enable) {
90 int res = 0;
91 const char* name;
92 switch(chain) {
93 case DOZABLE:
94 name = LOCAL_DOZABLE;
95 break;
96 case STANDBY:
97 name = LOCAL_STANDBY;
98 break;
99 default:
100 return res;
101 }
102
103 if (enable) {
104 res |= attachChain(name, LOCAL_INPUT);
105 res |= attachChain(name, LOCAL_OUTPUT);
106 } else {
107 res |= detachChain(name, LOCAL_INPUT);
108 res |= detachChain(name, LOCAL_OUTPUT);
109 }
110 return res;
111}
112
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700113int FirewallController::isFirewallEnabled(void) {
114 // TODO: verify that rules are still in place near top
115 return -1;
116}
117
118int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700119 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700120 // Unsupported in BLACKLIST mode
121 return -1;
122 }
123
JP Abgrall69261cb2014-06-19 18:35:24 -0700124 if (!isIfaceName(iface)) {
125 errno = ENOENT;
126 return -1;
127 }
128
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700129 const char* op;
130 if (rule == ALLOW) {
131 op = "-I";
132 } else {
133 op = "-D";
134 }
135
136 int res = 0;
137 res |= execIptables(V4V6, op, LOCAL_INPUT, "-i", iface, "-j", "RETURN", NULL);
138 res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-o", iface, "-j", "RETURN", NULL);
139 return res;
140}
141
142int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700143 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700144 // Unsupported in BLACKLIST mode
145 return -1;
146 }
147
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700148 IptablesTarget target = V4;
149 if (strchr(addr, ':')) {
150 target = V6;
151 }
152
153 const char* op;
154 if (rule == ALLOW) {
155 op = "-I";
156 } else {
157 op = "-D";
158 }
159
160 int res = 0;
161 res |= execIptables(target, op, LOCAL_INPUT, "-d", addr, "-j", "RETURN", NULL);
162 res |= execIptables(target, op, LOCAL_OUTPUT, "-s", addr, "-j", "RETURN", NULL);
163 return res;
164}
165
166int FirewallController::setEgressDestRule(const char* addr, int protocol, int port,
167 FirewallRule rule) {
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700168 if (mFirewallType == BLACKLIST) {
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700169 // Unsupported in BLACKLIST mode
170 return -1;
171 }
172
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700173 IptablesTarget target = V4;
174 if (strchr(addr, ':')) {
175 target = V6;
176 }
177
178 char protocolStr[16];
179 sprintf(protocolStr, "%d", protocol);
180
181 char portStr[16];
182 sprintf(portStr, "%d", port);
183
184 const char* op;
185 if (rule == ALLOW) {
186 op = "-I";
187 } else {
188 op = "-D";
189 }
190
191 int res = 0;
192 res |= execIptables(target, op, LOCAL_INPUT, "-s", addr, "-p", protocolStr,
193 "--sport", portStr, "-j", "RETURN", NULL);
194 res |= execIptables(target, op, LOCAL_OUTPUT, "-d", addr, "-p", protocolStr,
195 "--dport", portStr, "-j", "RETURN", NULL);
196 return res;
197}
198
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700199FirewallType FirewallController::getFirewallType(ChildChain chain) {
200 switch(chain) {
201 case DOZABLE:
202 return WHITELIST;
203 case STANDBY:
204 return BLACKLIST;
205 case NONE:
206 return mFirewallType;
207 default:
208 return BLACKLIST;
209 }
210}
211
212int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700213 char uidStr[16];
214 sprintf(uidStr, "%d", uid);
215
216 const char* op;
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700217 const char* target;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700218 FirewallType firewallType = getFirewallType(chain);
Amith Yamasani390e4ea2015-04-25 19:08:57 -0700219 if (firewallType == WHITELIST) {
220 target = "RETURN";
221 op = (rule == ALLOW)? "-I" : "-D";
222 } else { // BLACKLIST mode
223 target = "DROP";
224 op = (rule == DENY)? "-I" : "-D";
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700225 }
226
227 int res = 0;
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700228 switch(chain) {
229 case DOZABLE:
230 res |= execIptables(V4V6, op, LOCAL_DOZABLE, "-m", "owner", "--uid-owner",
231 uidStr, "-j", target, NULL);
232 break;
233 case STANDBY:
234 res |= execIptables(V4V6, op, LOCAL_STANDBY, "-m", "owner", "--uid-owner",
235 uidStr, "-j", target, NULL);
236 break;
237 case NONE:
238 res |= execIptables(V4V6, op, LOCAL_INPUT, "-m", "owner", "--uid-owner", uidStr,
239 "-j", target, NULL);
240 res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-m", "owner", "--uid-owner", uidStr,
241 "-j", target, NULL);
242 break;
243 default:
244 ALOGW("Unknown child chain: %d", chain);
245 break;
246 }
247 return res;
248}
249
250int FirewallController::attachChain(const char* childChain, const char* parentChain) {
251 return execIptables(V4V6, "-t", TABLE, "-A", parentChain, "-j", childChain, NULL);
252}
253
254int FirewallController::detachChain(const char* childChain, const char* parentChain) {
255 return execIptables(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
256}
257
258int FirewallController::createChain(const char* childChain,
259 const char* parentChain, FirewallType type) {
260 // Order is important, otherwise later steps may fail.
261 execIptablesSilently(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
262 execIptablesSilently(V4V6, "-t", TABLE, "-F", childChain, NULL);
263 execIptablesSilently(V4V6, "-t", TABLE, "-X", childChain, NULL);
264 int res = 0;
265 res |= execIptables(V4V6, "-t", TABLE, "-N", childChain, NULL);
266 if (type == WHITELIST) {
Xiaohui Chenfeb2b612015-06-25 21:19:38 -0700267 // create default white list for system uid range
268 char uidStr[16];
269 sprintf(uidStr, "0-%d", AID_APP - 1);
270 res |= execIptables(V4V6, "-A", childChain, "-m", "owner", "--uid-owner",
271 uidStr, "-j", "RETURN", NULL);
Xiaohui Chen1cdfa9a2015-06-08 16:28:12 -0700272 // create default rule to drop all traffic
273 res |= execIptables(V4V6, "-A", childChain, "-j", "DROP", NULL);
274 }
Jeff Sharkeyd8c64022012-07-13 18:04:07 -0700275 return res;
276}