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