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 <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <netdb.h>
21 #include <net/if.h>
22 #include <netinet/in.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 
27 #define LOG_TAG "Netd"
28 
29 #include <cutils/log.h>
30 #include <logwrap/logwrap.h>
31 
32 #include "NetdConstants.h"
33 
34 const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh";
35 const char * const IPTABLES_PATH = "/system/bin/iptables";
36 const char * const IP6TABLES_PATH = "/system/bin/ip6tables";
37 const char * const IPTABLES_RESTORE_PATH = "/system/bin/iptables-restore";
38 const char * const IP6TABLES_RESTORE_PATH = "/system/bin/ip6tables-restore";
39 const char * const TC_PATH = "/system/bin/tc";
40 const char * const IP_PATH = "/system/bin/ip";
41 const char * const ADD = "add";
42 const char * const DEL = "del";
43 
logExecError(const char * argv[],int res,int status)44 static void logExecError(const char* argv[], int res, int status) {
45     const char** argp = argv;
46     std::string args = "";
47     while (*argp) {
48         args += *argp;
49         args += ' ';
50         argp++;
51     }
52     ALOGE("exec() res=%d, status=%d for %s", res, status, args.c_str());
53 }
54 
execIptablesCommand(int argc,const char * argv[],bool silent)55 static int execIptablesCommand(int argc, const char *argv[], bool silent) {
56     int res;
57     int status;
58 
59     res = android_fork_execvp(argc, (char **)argv, &status, false,
60         !silent);
61     if (res || !WIFEXITED(status) || WEXITSTATUS(status)) {
62         if (!silent) {
63             logExecError(argv, res, status);
64         }
65         if (res)
66             return res;
67         if (!WIFEXITED(status))
68             return ECHILD;
69     }
70     return WEXITSTATUS(status);
71 }
72 
execIptables(IptablesTarget target,bool silent,va_list args)73 static int execIptables(IptablesTarget target, bool silent, va_list args) {
74     /* Read arguments from incoming va_list; we expect the list to be NULL terminated. */
75     std::list<const char*> argsList;
76     argsList.push_back(NULL);
77     const char* arg;
78 
79     // Wait to avoid failure due to another process holding the lock
80     argsList.push_back("-w");
81 
82     do {
83         arg = va_arg(args, const char *);
84         argsList.push_back(arg);
85     } while (arg);
86 
87     int i = 0;
88     const char* argv[argsList.size()];
89     std::list<const char*>::iterator it;
90     for (it = argsList.begin(); it != argsList.end(); it++, i++) {
91         argv[i] = *it;
92     }
93 
94     int res = 0;
95     if (target == V4 || target == V4V6) {
96         argv[0] = IPTABLES_PATH;
97         res |= execIptablesCommand(argsList.size(), argv, silent);
98     }
99     if (target == V6 || target == V4V6) {
100         argv[0] = IP6TABLES_PATH;
101         res |= execIptablesCommand(argsList.size(), argv, silent);
102     }
103     return res;
104 }
105 
execIptables(IptablesTarget target,...)106 int execIptables(IptablesTarget target, ...) {
107     va_list args;
108     va_start(args, target);
109     int res = execIptables(target, false, args);
110     va_end(args);
111     return res;
112 }
113 
execIptablesSilently(IptablesTarget target,...)114 int execIptablesSilently(IptablesTarget target, ...) {
115     va_list args;
116     va_start(args, target);
117     int res = execIptables(target, true, args);
118     va_end(args);
119     return res;
120 }
121 
execIptablesRestoreCommand(const char * cmd,const std::string & commands)122 static int execIptablesRestoreCommand(const char *cmd, const std::string& commands) {
123     const char *argv[] = {
124         cmd,
125         "--noflush",  // Don't flush the whole table.
126         "-w",         // Wait instead of failing if the lock is held.
127     };
128     AndroidForkExecvpOption opt[1] = {
129         {
130             .opt_type = FORK_EXECVP_OPTION_INPUT,
131             .opt_input.input = reinterpret_cast<const uint8_t*>(commands.c_str()),
132             .opt_input.input_len = commands.size(),
133         }
134     };
135 
136     int status = 0;
137     int res = android_fork_execvp_ext(
138             ARRAY_SIZE(argv), (char**)argv, &status, false /* ignore_int_quit */, LOG_NONE,
139             false /* abbreviated */, NULL /* file_path */, opt, ARRAY_SIZE(opt));
140     if (res || status) {
141         ALOGE("%s failed with res=%d, status=%d", argv[0], res, status);
142         return -1;
143     }
144 
145     return 0;
146 }
147 
execIptablesRestore(IptablesTarget target,const std::string & commands)148 int execIptablesRestore(IptablesTarget target, const std::string& commands) {
149     int res = 0;
150     if (target == V4 || target == V4V6) {
151         res |= execIptablesRestoreCommand(IPTABLES_RESTORE_PATH, commands);
152     }
153     if (target == V6 || target == V4V6) {
154         res |= execIptablesRestoreCommand(IP6TABLES_RESTORE_PATH, commands);
155     }
156     return res;
157 }
158 
159 /*
160  * Check an interface name for plausibility. This should e.g. help against
161  * directory traversal.
162  */
isIfaceName(const char * name)163 bool isIfaceName(const char *name) {
164     size_t i;
165     size_t name_len = strlen(name);
166     if ((name_len == 0) || (name_len > IFNAMSIZ)) {
167         return false;
168     }
169 
170     /* First character must be alphanumeric */
171     if (!isalnum(name[0])) {
172         return false;
173     }
174 
175     for (i = 1; i < name_len; i++) {
176         if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) {
177             return false;
178         }
179     }
180 
181     return true;
182 }
183 
parsePrefix(const char * prefix,uint8_t * family,void * address,int size,uint8_t * prefixlen)184 int parsePrefix(const char *prefix, uint8_t *family, void *address, int size, uint8_t *prefixlen) {
185     if (!prefix || !family || !address || !prefixlen) {
186         return -EFAULT;
187     }
188 
189     // Find the '/' separating address from prefix length.
190     const char *slash = strchr(prefix, '/');
191     const char *prefixlenString = slash + 1;
192     if (!slash || !*prefixlenString)
193         return -EINVAL;
194 
195     // Convert the prefix length to a uint8_t.
196     char *endptr;
197     unsigned templen;
198     templen = strtoul(prefixlenString, &endptr, 10);
199     if (*endptr || templen > 255) {
200         return -EINVAL;
201     }
202     *prefixlen = templen;
203 
204     // Copy the address part of the prefix to a local buffer. We have to copy
205     // because inet_pton and getaddrinfo operate on null-terminated address
206     // strings, but prefix is const and has '/' after the address.
207     std::string addressString(prefix, slash - prefix);
208 
209     // Parse the address.
210     addrinfo *res;
211     addrinfo hints = {
212         .ai_flags = AI_NUMERICHOST,
213     };
214     int ret = getaddrinfo(addressString.c_str(), NULL, &hints, &res);
215     if (ret || !res) {
216         return -EINVAL;  // getaddrinfo return values are not errno values.
217     }
218 
219     // Convert the address string to raw address bytes.
220     void *rawAddress;
221     int rawLength;
222     switch (res[0].ai_family) {
223         case AF_INET: {
224             if (*prefixlen > 32) {
225                 return -EINVAL;
226             }
227             sockaddr_in *sin = (sockaddr_in *) res[0].ai_addr;
228             rawAddress = &sin->sin_addr;
229             rawLength = 4;
230             break;
231         }
232         case AF_INET6: {
233             if (*prefixlen > 128) {
234                 return -EINVAL;
235             }
236             sockaddr_in6 *sin6 = (sockaddr_in6 *) res[0].ai_addr;
237             rawAddress = &sin6->sin6_addr;
238             rawLength = 16;
239             break;
240         }
241         default: {
242             freeaddrinfo(res);
243             return -EAFNOSUPPORT;
244         }
245     }
246 
247     if (rawLength > size) {
248         freeaddrinfo(res);
249         return -ENOSPC;
250     }
251 
252     *family = res[0].ai_family;
253     memcpy(address, rawAddress, rawLength);
254     freeaddrinfo(res);
255 
256     return rawLength;
257 }
258