You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.2 KiB
180 lines
5.2 KiB
/* |
|
* Copyright (C) 2012 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <ctype.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <netdb.h> |
|
#include <net/if.h> |
|
#include <netinet/in.h> |
|
#include <openssl/ssl.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <sys/wait.h> |
|
|
|
#define LOG_TAG "Netd" |
|
|
|
#include <android-base/stringprintf.h> |
|
#include <cutils/log.h> |
|
#include <cutils/sockets.h> |
|
#include <logwrap/logwrap.h> |
|
|
|
#include "Controllers.h" |
|
#include "NetdConstants.h" |
|
#include "IptablesRestoreController.h" |
|
|
|
const size_t SHA256_SIZE = EVP_MD_size(EVP_sha256()); |
|
|
|
const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh"; |
|
const char * const ADD = "add"; |
|
const char * const DEL = "del"; |
|
|
|
int execIptablesRestoreWithOutput(IptablesTarget target, const std::string& commands, |
|
std::string *output) { |
|
return android::net::gCtls->iptablesRestoreCtrl.execute(target, commands, output); |
|
} |
|
|
|
int execIptablesRestore(IptablesTarget target, const std::string& commands) { |
|
return execIptablesRestoreWithOutput(target, commands, nullptr); |
|
} |
|
|
|
int execIptablesRestoreCommand(IptablesTarget target, const std::string& table, |
|
const std::string& command, std::string *output) { |
|
std::string fullCmd = android::base::StringPrintf("*%s\n%s\nCOMMIT\n", table.c_str(), |
|
command.c_str()); |
|
return execIptablesRestoreWithOutput(target, fullCmd, output); |
|
} |
|
|
|
/* |
|
* Check an interface name for plausibility. This should e.g. help against |
|
* directory traversal. |
|
*/ |
|
bool isIfaceName(const std::string& name) { |
|
size_t i; |
|
if ((name.empty()) || (name.size() > IFNAMSIZ)) { |
|
return false; |
|
} |
|
|
|
/* First character must be alphanumeric */ |
|
if (!isalnum(name[0])) { |
|
return false; |
|
} |
|
|
|
for (i = 1; i < name.size(); i++) { |
|
if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) { |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
int parsePrefix(const char *prefix, uint8_t *family, void *address, int size, uint8_t *prefixlen) { |
|
if (!prefix || !family || !address || !prefixlen) { |
|
return -EFAULT; |
|
} |
|
|
|
// Find the '/' separating address from prefix length. |
|
const char *slash = strchr(prefix, '/'); |
|
const char *prefixlenString = slash + 1; |
|
if (!slash || !*prefixlenString) |
|
return -EINVAL; |
|
|
|
// Convert the prefix length to a uint8_t. |
|
char *endptr; |
|
unsigned templen; |
|
templen = strtoul(prefixlenString, &endptr, 10); |
|
if (*endptr || templen > 255) { |
|
return -EINVAL; |
|
} |
|
*prefixlen = templen; |
|
|
|
// Copy the address part of the prefix to a local buffer. We have to copy |
|
// because inet_pton and getaddrinfo operate on null-terminated address |
|
// strings, but prefix is const and has '/' after the address. |
|
std::string addressString(prefix, slash - prefix); |
|
|
|
// Parse the address. |
|
addrinfo *res; |
|
addrinfo hints = { |
|
.ai_flags = AI_NUMERICHOST, |
|
}; |
|
int ret = getaddrinfo(addressString.c_str(), NULL, &hints, &res); |
|
if (ret || !res) { |
|
return -EINVAL; // getaddrinfo return values are not errno values. |
|
} |
|
|
|
// Convert the address string to raw address bytes. |
|
void *rawAddress; |
|
int rawLength; |
|
switch (res[0].ai_family) { |
|
case AF_INET: { |
|
if (*prefixlen > 32) { |
|
return -EINVAL; |
|
} |
|
sockaddr_in *sin = (sockaddr_in *) res[0].ai_addr; |
|
rawAddress = &sin->sin_addr; |
|
rawLength = 4; |
|
break; |
|
} |
|
case AF_INET6: { |
|
if (*prefixlen > 128) { |
|
return -EINVAL; |
|
} |
|
sockaddr_in6 *sin6 = (sockaddr_in6 *) res[0].ai_addr; |
|
rawAddress = &sin6->sin6_addr; |
|
rawLength = 16; |
|
break; |
|
} |
|
default: { |
|
freeaddrinfo(res); |
|
return -EAFNOSUPPORT; |
|
} |
|
} |
|
|
|
if (rawLength > size) { |
|
freeaddrinfo(res); |
|
return -ENOSPC; |
|
} |
|
|
|
*family = res[0].ai_family; |
|
memcpy(address, rawAddress, rawLength); |
|
freeaddrinfo(res); |
|
|
|
return rawLength; |
|
} |
|
|
|
void blockSigpipe() { |
|
sigset_t mask; |
|
|
|
sigemptyset(&mask); |
|
sigaddset(&mask, SIGPIPE); |
|
if (sigprocmask(SIG_BLOCK, &mask, NULL) != 0) |
|
ALOGW("WARNING: SIGPIPE not blocked\n"); |
|
} |
|
|
|
void setCloseOnExec(const char *sock) { |
|
int fd = android_get_control_socket(sock); |
|
int flags = fcntl(fd, F_GETFD, 0); |
|
if (flags == -1) { |
|
ALOGE("Can't get fd flags for control socket %s", sock); |
|
flags = 0; |
|
} |
|
flags |= FD_CLOEXEC; |
|
if (fcntl(fd, F_SETFD, flags) == -1) { |
|
ALOGE("Can't set control socket %s to FD_CLOEXEC", sock); |
|
} |
|
}
|
|
|