OSDN Git Service

am 8246d45e: Merge "bundle init.rc contents with its service"
[android-x86/system-netd.git] / server / FirewallController.cpp
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 <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 #include <private/android_filesystem_config.h>
27
28 #include "NetdConstants.h"
29 #include "FirewallController.h"
30
31 const char* FirewallController::TABLE = "filter";
32
33 const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
34 const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
35 const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
36
37 const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
38 const char* FirewallController::LOCAL_STANDBY = "fw_standby";
39
40 FirewallController::FirewallController(void) {
41     // If no rules are set, it's in BLACKLIST mode
42     mFirewallType = BLACKLIST;
43 }
44
45 int FirewallController::setupIptablesHooks(void) {
46     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;
55 }
56
57 int FirewallController::enableFirewall(FirewallType ftype) {
58     int res = 0;
59     if (mFirewallType != ftype) {
60         // flush any existing rules
61         disableFirewall();
62
63         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         }
69
70         // Set this after calling disableFirewall(), since it defaults to WHITELIST there
71         mFirewallType = ftype;
72     }
73     return res;
74 }
75
76 int FirewallController::disableFirewall(void) {
77     int res = 0;
78
79     mFirewallType = WHITELIST;
80
81     // 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
89 int 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
113 int FirewallController::isFirewallEnabled(void) {
114     // TODO: verify that rules are still in place near top
115     return -1;
116 }
117
118 int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
119     if (mFirewallType == BLACKLIST) {
120         // Unsupported in BLACKLIST mode
121         return -1;
122     }
123
124     if (!isIfaceName(iface)) {
125         errno = ENOENT;
126         return -1;
127     }
128
129     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
142 int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule) {
143     if (mFirewallType == BLACKLIST) {
144         // Unsupported in BLACKLIST mode
145         return -1;
146     }
147
148     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
166 int FirewallController::setEgressDestRule(const char* addr, int protocol, int port,
167         FirewallRule rule) {
168     if (mFirewallType == BLACKLIST) {
169         // Unsupported in BLACKLIST mode
170         return -1;
171     }
172
173     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
199 FirewallType 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
212 int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
213     char uidStr[16];
214     sprintf(uidStr, "%d", uid);
215
216     const char* op;
217     const char* target;
218     FirewallType firewallType = getFirewallType(chain);
219     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";
225     }
226
227     int res = 0;
228     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
250 int FirewallController::attachChain(const char* childChain, const char* parentChain) {
251     return execIptables(V4V6, "-t", TABLE, "-A", parentChain, "-j", childChain, NULL);
252 }
253
254 int FirewallController::detachChain(const char* childChain, const char* parentChain) {
255     return execIptables(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
256 }
257
258 int 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) {
267         // 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);
272         // create default rule to drop all traffic
273         res |= execIptables(V4V6, "-A", childChain, "-j", "DROP", NULL);
274     }
275     return res;
276 }