Robert Greenwalt | c462177 | 2012-01-31 12:46:45 -0800 | [diff] [blame] | 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 | |
Dan Albert | aa1be2b | 2015-01-06 09:36:17 -0800 | [diff] [blame] | 17 | #include <ctype.h> |
| 18 | #include <errno.h> |
Lorenzo Colitti | 70afde6 | 2013-03-04 17:58:40 +0900 | [diff] [blame] | 19 | #include <fcntl.h> |
Lorenzo Colitti | ba25df9 | 2014-06-18 00:22:17 +0900 | [diff] [blame] | 20 | #include <netdb.h> |
Dan Albert | aa1be2b | 2015-01-06 09:36:17 -0800 | [diff] [blame] | 21 | #include <net/if.h> |
Lorenzo Colitti | ba25df9 | 2014-06-18 00:22:17 +0900 | [diff] [blame] | 22 | #include <netinet/in.h> |
| 23 | #include <stdlib.h> |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 24 | #include <string.h> |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 25 | #include <sys/wait.h> |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 26 | |
Jeff Sharkey | bec6d04 | 2012-09-06 15:45:56 -0700 | [diff] [blame] | 27 | #define LOG_TAG "Netd" |
| 28 | |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 29 | #include <cutils/log.h> |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 30 | #include <logwrap/logwrap.h> |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 31 | |
Narayan Kamath | a5ace89 | 2017-01-06 15:10:02 +0000 | [diff] [blame] | 32 | #include "Controllers.h" |
Robert Greenwalt | c462177 | 2012-01-31 12:46:45 -0800 | [diff] [blame] | 33 | #include "NetdConstants.h" |
Narayan Kamath | a5ace89 | 2017-01-06 15:10:02 +0000 | [diff] [blame] | 34 | #include "IptablesRestoreController.h" |
Robert Greenwalt | c462177 | 2012-01-31 12:46:45 -0800 | [diff] [blame] | 35 | |
| 36 | const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh"; |
| 37 | const char * const IPTABLES_PATH = "/system/bin/iptables"; |
JP Abgrall | 0031cea | 2012-04-17 16:38:23 -0700 | [diff] [blame] | 38 | const char * const IP6TABLES_PATH = "/system/bin/ip6tables"; |
Robert Greenwalt | c462177 | 2012-01-31 12:46:45 -0800 | [diff] [blame] | 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"; |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 43 | |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 44 | static void logExecError(const char* argv[], int res, int status) { |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 45 | const char** argp = argv; |
| 46 | std::string args = ""; |
| 47 | while (*argp) { |
| 48 | args += *argp; |
| 49 | args += ' '; |
| 50 | argp++; |
| 51 | } |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 52 | ALOGE("exec() res=%d, status=%d for %s", res, status, args.c_str()); |
| 53 | } |
| 54 | |
| 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); |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 71 | } |
| 72 | |
| 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; |
Amith Yamasani | 390e4ea | 2015-04-25 19:08:57 -0700 | [diff] [blame] | 78 | |
| 79 | // Wait to avoid failure due to another process holding the lock |
| 80 | argsList.push_back("-w"); |
| 81 | |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 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; |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 97 | res |= execIptablesCommand(argsList.size(), argv, silent); |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 98 | } |
| 99 | if (target == V6 || target == V4V6) { |
| 100 | argv[0] = IP6TABLES_PATH; |
Rom Lemarchand | 838ef64 | 2013-01-24 15:14:41 -0800 | [diff] [blame] | 101 | res |= execIptablesCommand(argsList.size(), argv, silent); |
Jeff Sharkey | 8e188ed | 2012-07-12 18:32:03 -0700 | [diff] [blame] | 102 | } |
| 103 | return res; |
| 104 | } |
| 105 | |
| 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 | |
| 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 | } |
Lorenzo Colitti | 70afde6 | 2013-03-04 17:58:40 +0900 | [diff] [blame] | 121 | |
Lorenzo Colitti | cd28377 | 2017-01-31 19:00:49 +0900 | [diff] [blame^] | 122 | int execIptablesRestoreWithOutput(IptablesTarget target, const std::string& commands, |
| 123 | std::string *output) { |
| 124 | return android::net::gCtls->iptablesRestoreCtrl.execute(target, commands, output); |
| 125 | } |
| 126 | |
Lorenzo Colitti | 89faa34 | 2016-02-26 11:38:47 +0900 | [diff] [blame] | 127 | int execIptablesRestore(IptablesTarget target, const std::string& commands) { |
Lorenzo Colitti | cd28377 | 2017-01-31 19:00:49 +0900 | [diff] [blame^] | 128 | return execIptablesRestoreWithOutput(target, commands, nullptr); |
Lorenzo Colitti | 89faa34 | 2016-02-26 11:38:47 +0900 | [diff] [blame] | 129 | } |
| 130 | |
JP Abgrall | 69261cb | 2014-06-19 18:35:24 -0700 | [diff] [blame] | 131 | /* |
| 132 | * Check an interface name for plausibility. This should e.g. help against |
| 133 | * directory traversal. |
| 134 | */ |
| 135 | bool isIfaceName(const char *name) { |
| 136 | size_t i; |
| 137 | size_t name_len = strlen(name); |
| 138 | if ((name_len == 0) || (name_len > IFNAMSIZ)) { |
| 139 | return false; |
| 140 | } |
| 141 | |
| 142 | /* First character must be alphanumeric */ |
| 143 | if (!isalnum(name[0])) { |
| 144 | return false; |
| 145 | } |
| 146 | |
| 147 | for (i = 1; i < name_len; i++) { |
| 148 | if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) { |
| 149 | return false; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | return true; |
| 154 | } |
Lorenzo Colitti | ba25df9 | 2014-06-18 00:22:17 +0900 | [diff] [blame] | 155 | |
| 156 | int parsePrefix(const char *prefix, uint8_t *family, void *address, int size, uint8_t *prefixlen) { |
| 157 | if (!prefix || !family || !address || !prefixlen) { |
| 158 | return -EFAULT; |
| 159 | } |
| 160 | |
| 161 | // Find the '/' separating address from prefix length. |
| 162 | const char *slash = strchr(prefix, '/'); |
| 163 | const char *prefixlenString = slash + 1; |
| 164 | if (!slash || !*prefixlenString) |
| 165 | return -EINVAL; |
| 166 | |
| 167 | // Convert the prefix length to a uint8_t. |
| 168 | char *endptr; |
| 169 | unsigned templen; |
| 170 | templen = strtoul(prefixlenString, &endptr, 10); |
| 171 | if (*endptr || templen > 255) { |
| 172 | return -EINVAL; |
| 173 | } |
| 174 | *prefixlen = templen; |
| 175 | |
| 176 | // Copy the address part of the prefix to a local buffer. We have to copy |
| 177 | // because inet_pton and getaddrinfo operate on null-terminated address |
| 178 | // strings, but prefix is const and has '/' after the address. |
| 179 | std::string addressString(prefix, slash - prefix); |
| 180 | |
| 181 | // Parse the address. |
| 182 | addrinfo *res; |
| 183 | addrinfo hints = { |
| 184 | .ai_flags = AI_NUMERICHOST, |
| 185 | }; |
| 186 | int ret = getaddrinfo(addressString.c_str(), NULL, &hints, &res); |
| 187 | if (ret || !res) { |
| 188 | return -EINVAL; // getaddrinfo return values are not errno values. |
| 189 | } |
| 190 | |
| 191 | // Convert the address string to raw address bytes. |
| 192 | void *rawAddress; |
| 193 | int rawLength; |
| 194 | switch (res[0].ai_family) { |
| 195 | case AF_INET: { |
| 196 | if (*prefixlen > 32) { |
| 197 | return -EINVAL; |
| 198 | } |
| 199 | sockaddr_in *sin = (sockaddr_in *) res[0].ai_addr; |
| 200 | rawAddress = &sin->sin_addr; |
| 201 | rawLength = 4; |
| 202 | break; |
| 203 | } |
| 204 | case AF_INET6: { |
| 205 | if (*prefixlen > 128) { |
| 206 | return -EINVAL; |
| 207 | } |
| 208 | sockaddr_in6 *sin6 = (sockaddr_in6 *) res[0].ai_addr; |
| 209 | rawAddress = &sin6->sin6_addr; |
| 210 | rawLength = 16; |
| 211 | break; |
| 212 | } |
| 213 | default: { |
| 214 | freeaddrinfo(res); |
| 215 | return -EAFNOSUPPORT; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | if (rawLength > size) { |
| 220 | freeaddrinfo(res); |
| 221 | return -ENOSPC; |
| 222 | } |
| 223 | |
| 224 | *family = res[0].ai_family; |
| 225 | memcpy(address, rawAddress, rawLength); |
| 226 | freeaddrinfo(res); |
| 227 | |
| 228 | return rawLength; |
| 229 | } |