OSDN Git Service

Merge "Changed format of interface class acitivity message."
[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 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
39 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
40
41 NatController::NatController(SecondaryTableController *ctrl) {
42     secondaryTableCtrl = ctrl;
43 }
44
45 NatController::~NatController() {
46 }
47
48 int NatController::runCmd(const char *path, const char *cmd) {
49     char *buffer;
50     size_t len = strnlen(cmd, 255);
51     int res;
52
53     if (len == 255) {
54         ALOGE("command too long");
55         errno = E2BIG;
56         return -1;
57     }
58
59     asprintf(&buffer, "%s %s", path, cmd);
60     res = system_nosh(buffer);
61     ALOGV("runCmd() buffer='%s' res=%d", buffer, res);
62     free(buffer);
63     return res;
64 }
65
66 int NatController::setupIptablesHooks() {
67     setDefaults();
68     return 0;
69 }
70
71 int NatController::setDefaults() {
72     if (runCmd(IPTABLES_PATH, "-F natctrl_FORWARD"))
73         return -1;
74     if (runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING"))
75         return -1;
76
77     runCmd(IP_PATH, "rule flush");
78     runCmd(IP_PATH, "-6 rule flush");
79     runCmd(IP_PATH, "rule add from all lookup default prio 32767");
80     runCmd(IP_PATH, "rule add from all lookup main prio 32766");
81     runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767");
82     runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766");
83     runCmd(IP_PATH, "route flush cache");
84
85     natCount = 0;
86
87     return 0;
88 }
89
90 bool NatController::checkInterface(const char *iface) {
91     if (strlen(iface) > IFNAMSIZ) return false;
92     return true;
93 }
94
95 //  0    1       2       3       4            5
96 // nat enable intface extface addrcnt nated-ipaddr/prelength
97 int NatController::enableNat(const int argc, char **argv) {
98     char cmd[255];
99     int i;
100     int addrCount = atoi(argv[4]);
101     int ret = 0;
102     const char *intIface = argv[2];
103     const char *extIface = argv[3];
104     int tableNumber;
105
106     if (!checkInterface(intIface) || !checkInterface(extIface)) {
107         ALOGE("Invalid interface specified");
108         errno = ENODEV;
109         return -1;
110     }
111
112     if (argc < 5 + addrCount) {
113         ALOGE("Missing Argument");
114         errno = EINVAL;
115         return -1;
116     }
117
118     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
119     if (tableNumber != -1) {
120         for(i = 0; i < addrCount; i++) {
121             ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
122
123             ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
124         }
125         runCmd(IP_PATH, "route flush cache");
126     }
127
128     if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
129         if (tableNumber != -1) {
130             for (i = 0; i < addrCount; i++) {
131                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
132
133                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
134             }
135             runCmd(IP_PATH, "route flush cache");
136         }
137         ALOGE("Error setting forward rules");
138         errno = ENODEV;
139         return -1;
140     }
141
142     /* Always make sure the drop rule is at the end */
143     snprintf(cmd, sizeof(cmd), "-D natctrl_FORWARD -j DROP");
144     runCmd(IPTABLES_PATH, cmd);
145     snprintf(cmd, sizeof(cmd), "-A natctrl_FORWARD -j DROP");
146     runCmd(IPTABLES_PATH, cmd);
147
148
149     natCount++;
150     // add this if we are the first added nat
151     if (natCount == 1) {
152         snprintf(cmd, sizeof(cmd), "-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIface);
153         if (runCmd(IPTABLES_PATH, cmd)) {
154             ALOGE("Error seting postroute rule: %s", cmd);
155             // unwind what's been done, but don't care about success - what more could we do?
156             for (i = 0; i < addrCount; i++) {
157                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
158
159                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
160             }
161             setDefaults();
162             return -1;
163         }
164     }
165
166     return 0;
167 }
168
169 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
170     char cmd[255];
171
172     snprintf(cmd, sizeof(cmd),
173              "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
174              (add ? "A" : "D"),
175              extIface, intIface);
176     if (runCmd(IPTABLES_PATH, cmd) && add) {
177         return -1;
178     }
179
180     snprintf(cmd, sizeof(cmd),
181             "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
182             (add ? "A" : "D"),
183             intIface, extIface);
184     if (runCmd(IPTABLES_PATH, cmd) && add) {
185         // bail on error, but only if adding
186         snprintf(cmd, sizeof(cmd),
187                 "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
188                 (!add ? "A" : "D"),
189                 extIface, intIface);
190         runCmd(IPTABLES_PATH, cmd);
191         return -1;
192     }
193
194     snprintf(cmd, sizeof(cmd), "-%s natctrl_FORWARD -i %s -o %s -j RETURN", (add ? "A" : "D"),
195             intIface, extIface);
196     if (runCmd(IPTABLES_PATH, cmd) && add) {
197         // unwind what's been done, but don't care about success - what more could we do?
198         snprintf(cmd, sizeof(cmd),
199                 "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
200                 (!add ? "A" : "D"),
201                 intIface, extIface);
202         runCmd(IPTABLES_PATH, cmd);
203
204         snprintf(cmd, sizeof(cmd),
205                  "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
206                  (!add ? "A" : "D"),
207                  extIface, intIface);
208         runCmd(IPTABLES_PATH, cmd);
209         return -1;
210     }
211
212     return 0;
213 }
214
215 // nat disable intface extface
216 //  0    1       2       3       4            5
217 // nat enable intface extface addrcnt nated-ipaddr/prelength
218 int NatController::disableNat(const int argc, char **argv) {
219     char cmd[255];
220     int i;
221     int addrCount = atoi(argv[4]);
222     const char *intIface = argv[2];
223     const char *extIface = argv[3];
224     int tableNumber;
225
226     if (!checkInterface(intIface) || !checkInterface(extIface)) {
227         ALOGE("Invalid interface specified");
228         errno = ENODEV;
229         return -1;
230     }
231
232     if (argc < 5 + addrCount) {
233         ALOGE("Missing Argument");
234         errno = EINVAL;
235         return -1;
236     }
237
238     setForwardRules(false, intIface, extIface);
239
240     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
241     if (tableNumber != -1) {
242         for (i = 0; i < addrCount; i++) {
243             secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
244
245             secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
246         }
247
248         runCmd(IP_PATH, "route flush cache");
249     }
250
251     if (--natCount <= 0) {
252         // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
253         setDefaults();
254     }
255     return 0;
256 }