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