OSDN Git Service

am c9ed2f47: (-s ours) Allow additional interface flags. Do not merge
[android-x86/system-netd.git] / NatController.cpp
1 /*
2  * Copyright (C) 2008 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 // #define LOG_NDEBUG 0
18
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27 #include <cutils/properties.h>
28
29 #define LOG_TAG "NatController"
30 #include <cutils/log.h>
31
32 #include "NatController.h"
33 #include "SecondaryTableController.h"
34 #include "NetdConstants.h"
35
36 extern "C" int system_nosh(const char *command);
37
38 NatController::NatController(SecondaryTableController *ctrl) {
39     secondaryTableCtrl = ctrl;
40 }
41
42 NatController::~NatController() {
43 }
44
45 int NatController::runCmd(const char *path, const char *cmd) {
46     char *buffer;
47     size_t len = strnlen(cmd, 255);
48     int res;
49
50     if (len == 255) {
51         ALOGE("command too long");
52         errno = E2BIG;
53         return -1;
54     }
55
56     asprintf(&buffer, "%s %s", path, cmd);
57     res = system_nosh(buffer);
58     ALOGV("runCmd() buffer='%s' res=%d", buffer, res);
59     free(buffer);
60     return res;
61 }
62
63 int NatController::setupIptablesHooks() {
64     if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
65         return -1;
66     if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
67         return -1;
68     if (runCmd(IPTABLES_PATH, "-P FORWARD ACCEPT"))
69         return -1;
70
71     // Order is important!
72     // -D to delete any pre-existing jump rule, to prevent dupes (no-op if doesn't exist)
73     // -F to flush the chain (no-op if doesn't exist).
74     // -N to create the chain (no-op if already exist).
75
76     runCmd(IPTABLES_PATH, "-D FORWARD -j natctrl_FORWARD");
77     runCmd(IPTABLES_PATH, "-F natctrl_FORWARD");
78     runCmd(IPTABLES_PATH, "-N natctrl_FORWARD");
79     if (runCmd(IPTABLES_PATH, "-A FORWARD -j natctrl_FORWARD"))
80         return -1;
81
82     runCmd(IPTABLES_PATH, "-t nat -D POSTROUTING -j natctrl_nat_POSTROUTING");
83     runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING");
84     runCmd(IPTABLES_PATH, "-t nat -N natctrl_nat_POSTROUTING");
85     if (runCmd(IPTABLES_PATH, "-t nat -A POSTROUTING -j natctrl_nat_POSTROUTING"))
86         return -1;
87
88     setDefaults();
89     return 0;
90 }
91
92 int NatController::setDefaults() {
93     if (runCmd(IPTABLES_PATH, "-F natctrl_FORWARD"))
94         return -1;
95     if (runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING"))
96         return -1;
97
98     runCmd(IP_PATH, "rule flush");
99     runCmd(IP_PATH, "-6 rule flush");
100     runCmd(IP_PATH, "rule add from all lookup default prio 32767");
101     runCmd(IP_PATH, "rule add from all lookup main prio 32766");
102     runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767");
103     runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766");
104     runCmd(IP_PATH, "route flush cache");
105
106     natCount = 0;
107
108     return 0;
109 }
110
111 bool NatController::checkInterface(const char *iface) {
112     if (strlen(iface) > IFNAMSIZ) return false;
113     return true;
114 }
115
116 //  0    1       2       3       4            5
117 // nat enable intface extface addrcnt nated-ipaddr/prelength
118 int NatController::enableNat(const int argc, char **argv) {
119     char cmd[255];
120     int i;
121     int addrCount = atoi(argv[4]);
122     int ret = 0;
123     const char *intIface = argv[2];
124     const char *extIface = argv[3];
125     int tableNumber;
126
127     if (!checkInterface(intIface) || !checkInterface(extIface)) {
128         ALOGE("Invalid interface specified");
129         errno = ENODEV;
130         return -1;
131     }
132
133     if (argc < 5 + addrCount) {
134         ALOGE("Missing Argument");
135         errno = EINVAL;
136         return -1;
137     }
138
139     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
140     if (tableNumber != -1) {
141         for(i = 0; i < addrCount; i++) {
142             ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
143
144             ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
145         }
146         runCmd(IP_PATH, "route flush cache");
147     }
148
149     if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
150         if (tableNumber != -1) {
151             for (i = 0; i < addrCount; i++) {
152                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
153
154                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
155             }
156             runCmd(IP_PATH, "route flush cache");
157         }
158         ALOGE("Error setting forward rules");
159         errno = ENODEV;
160         return -1;
161     }
162
163     /* Always make sure the drop rule is at the end */
164     snprintf(cmd, sizeof(cmd), "-D natctrl_FORWARD -j DROP");
165     runCmd(IPTABLES_PATH, cmd);
166     snprintf(cmd, sizeof(cmd), "-A natctrl_FORWARD -j DROP");
167     runCmd(IPTABLES_PATH, cmd);
168
169
170     natCount++;
171     // add this if we are the first added nat
172     if (natCount == 1) {
173         snprintf(cmd, sizeof(cmd), "-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIface);
174         if (runCmd(IPTABLES_PATH, cmd)) {
175             ALOGE("Error seting postroute rule: %s", cmd);
176             // unwind what's been done, but don't care about success - what more could we do?
177             for (i = 0; i < addrCount; i++) {
178                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
179
180                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
181             }
182             setDefaults();
183             return -1;
184         }
185     }
186
187     return 0;
188 }
189
190 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
191     char cmd[255];
192
193     snprintf(cmd, sizeof(cmd),
194              "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
195              (add ? "A" : "D"),
196              extIface, intIface);
197     if (runCmd(IPTABLES_PATH, cmd) && add) {
198         return -1;
199     }
200
201     snprintf(cmd, sizeof(cmd),
202             "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
203             (add ? "A" : "D"),
204             intIface, extIface);
205     if (runCmd(IPTABLES_PATH, cmd) && add) {
206         // bail on error, but only if adding
207         snprintf(cmd, sizeof(cmd),
208                 "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
209                 (!add ? "A" : "D"),
210                 extIface, intIface);
211         runCmd(IPTABLES_PATH, cmd);
212         return -1;
213     }
214
215     snprintf(cmd, sizeof(cmd), "-%s natctrl_FORWARD -i %s -o %s -j RETURN", (add ? "A" : "D"),
216             intIface, extIface);
217     if (runCmd(IPTABLES_PATH, cmd) && add) {
218         // unwind what's been done, but don't care about success - what more could we do?
219         snprintf(cmd, sizeof(cmd),
220                 "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
221                 (!add ? "A" : "D"),
222                 intIface, extIface);
223         runCmd(IPTABLES_PATH, cmd);
224
225         snprintf(cmd, sizeof(cmd),
226                  "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
227                  (!add ? "A" : "D"),
228                  extIface, intIface);
229         runCmd(IPTABLES_PATH, cmd);
230         return -1;
231     }
232
233     return 0;
234 }
235
236 // nat disable intface extface
237 //  0    1       2       3       4            5
238 // nat enable intface extface addrcnt nated-ipaddr/prelength
239 int NatController::disableNat(const int argc, char **argv) {
240     char cmd[255];
241     int i;
242     int addrCount = atoi(argv[4]);
243     const char *intIface = argv[2];
244     const char *extIface = argv[3];
245     int tableNumber;
246
247     if (!checkInterface(intIface) || !checkInterface(extIface)) {
248         ALOGE("Invalid interface specified");
249         errno = ENODEV;
250         return -1;
251     }
252
253     if (argc < 5 + addrCount) {
254         ALOGE("Missing Argument");
255         errno = EINVAL;
256         return -1;
257     }
258
259     setForwardRules(false, intIface, extIface);
260
261     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
262     if (tableNumber != -1) {
263         for (i = 0; i < addrCount; i++) {
264             secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
265
266             secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
267         }
268
269         runCmd(IP_PATH, "route flush cache");
270     }
271
272     if (--natCount <= 0) {
273         // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
274         setDefaults();
275     }
276     return 0;
277 }