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