2020-02-20 23:45:22 +08:00
|
|
|
// Copyright 2019 Google LLC
|
|
|
|
//
|
|
|
|
// 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 "sandboxed_api/sandbox2/network_proxy/filtering.h"
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include <glog/logging.h>
|
2020-08-28 19:49:15 +08:00
|
|
|
#include "absl/status/status.h"
|
2020-09-02 23:46:48 +08:00
|
|
|
#include "absl/status/statusor.h"
|
2020-02-20 23:45:22 +08:00
|
|
|
#include "absl/strings/numbers.h"
|
|
|
|
#include "absl/strings/str_cat.h"
|
|
|
|
#include "absl/strings/str_split.h"
|
|
|
|
#include "sandboxed_api/sandbox2/util/strerror.h"
|
|
|
|
#include "sandboxed_api/util/status_macros.h"
|
|
|
|
|
|
|
|
namespace sandbox2 {
|
|
|
|
|
2020-09-02 23:46:48 +08:00
|
|
|
static absl::StatusOr<std::string> Addr6ToString(
|
2020-02-20 23:45:22 +08:00
|
|
|
const struct sockaddr_in6* saddr) {
|
|
|
|
char addr[INET6_ADDRSTRLEN];
|
|
|
|
int port = htons(saddr->sin6_port);
|
|
|
|
if (!inet_ntop(AF_INET6, &saddr->sin6_addr, addr, sizeof addr)) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InternalError(
|
2020-02-20 23:45:22 +08:00
|
|
|
"Error in converting sockaddr_in6 addres to string");
|
|
|
|
}
|
|
|
|
return absl::StrCat("IP: ", addr, ", port: ", port);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts sockaddr_in structure into a string IPv4 representation.
|
2020-09-02 23:46:48 +08:00
|
|
|
static absl::StatusOr<std::string> Addr4ToString(
|
2020-02-20 23:45:22 +08:00
|
|
|
const struct sockaddr_in* saddr) {
|
|
|
|
char addr[INET_ADDRSTRLEN];
|
|
|
|
int port = htons(saddr->sin_port);
|
|
|
|
if (!inet_ntop(AF_INET, &saddr->sin_addr, addr, sizeof addr)) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InternalError(
|
2020-02-20 23:45:22 +08:00
|
|
|
"Error in converting sockaddr_in addres to string");
|
|
|
|
}
|
|
|
|
return absl::StrCat("IP: ", addr, ", port: ", port);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts sockaddr_in6 structure into a string IPv6 representation.
|
2020-09-02 23:46:48 +08:00
|
|
|
absl::StatusOr<std::string> AddrToString(const struct sockaddr* saddr) {
|
2020-02-20 23:45:22 +08:00
|
|
|
switch (saddr->sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
return Addr4ToString(reinterpret_cast<const struct sockaddr_in*>(saddr));
|
|
|
|
case AF_INET6:
|
|
|
|
return Addr6ToString(reinterpret_cast<const struct sockaddr_in6*>(saddr));
|
|
|
|
default:
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InternalError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat("Unexpected sa_family value: ", saddr->sa_family));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
static absl::Status IPStringToAddr(const std::string& ip, int address_family,
|
2020-02-20 23:45:22 +08:00
|
|
|
void* addr) {
|
|
|
|
int err = inet_pton(address_family, ip.c_str(), addr);
|
|
|
|
if (err == 0) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(absl::StrCat("Invalid address: ", ip));
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
if (err == -1) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InternalError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat("inet_pton() failed for ", ip, ": ", StrError(errno)));
|
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parses a string of type IP or IP/mask or IP/cidr and saves appropriate
|
|
|
|
// values in output arguments.
|
2020-02-28 01:23:44 +08:00
|
|
|
static absl::Status ParseIpAndMask(const std::string& ip_and_mask,
|
2020-02-20 23:45:22 +08:00
|
|
|
std::string* ip, std::string* mask,
|
|
|
|
uint32_t* cidr) {
|
|
|
|
// mask is checked later because only IPv4 format supports mask
|
|
|
|
if (ip == nullptr || cidr == nullptr) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
"ip and cidr arguments of ParseIpAndMask cannot be nullptr");
|
|
|
|
}
|
|
|
|
*cidr = 0;
|
|
|
|
|
|
|
|
std::vector<std::string> ip_and_mask_split =
|
|
|
|
absl::StrSplit(ip_and_mask, absl::MaxSplits('/', 1));
|
|
|
|
|
|
|
|
*ip = ip_and_mask_split[0];
|
|
|
|
if (ip_and_mask_split.size() == 1) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
std::string mask_or_cidr = ip_and_mask_split[1];
|
|
|
|
|
|
|
|
const bool has_dot = mask_or_cidr.find(".") == absl::string_view::npos;
|
|
|
|
if (has_dot) { // mask_or_cidr is cidr
|
|
|
|
bool res = absl::SimpleAtoi<uint32_t>(mask_or_cidr, cidr);
|
|
|
|
if (!res || !*cidr) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat(mask_or_cidr, " is not a correct cidr"));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mask == nullptr) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
"mask argument of ParseIpAndMask cannot be NULL in this case");
|
|
|
|
}
|
|
|
|
*mask = std::string(mask_or_cidr);
|
|
|
|
}
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
static absl::Status CidrToIn6Addr(uint32_t cidr, in6_addr* addr) {
|
2020-02-20 23:45:22 +08:00
|
|
|
if (cidr > 128) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat(cidr, " is not a correct cidr"));
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
while (cidr >= 8) {
|
|
|
|
addr->s6_addr[i++] = 0xff;
|
|
|
|
cidr -= 8;
|
|
|
|
}
|
|
|
|
if (cidr) {
|
|
|
|
uint8_t tmp = 0x0;
|
|
|
|
while (cidr--) {
|
|
|
|
tmp >>= 1;
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
addr->s6_addr[i] = tmp;
|
|
|
|
}
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
static absl::Status CidrToInAddr(uint32_t cidr, in_addr* addr) {
|
2020-02-20 23:45:22 +08:00
|
|
|
if (cidr > 32) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat(cidr, " is not a correct cidr"));
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
uint32_t tmp = 0x0;
|
|
|
|
while (cidr--) {
|
|
|
|
tmp >>= 1;
|
|
|
|
tmp |= 0x80000000;
|
|
|
|
}
|
|
|
|
addr->s_addr = htonl(tmp);
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsIPv4MaskCorrect(in_addr_t m) {
|
|
|
|
m = ntohl(m);
|
|
|
|
if (m == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m = ~m + 1;
|
|
|
|
return !(m & (m - 1));
|
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
absl::Status AllowedHosts::AllowIPv4(const std::string& ip_and_mask,
|
2020-02-20 23:45:22 +08:00
|
|
|
uint32_t port) {
|
|
|
|
std::string ip, mask;
|
|
|
|
uint32_t cidr;
|
|
|
|
SAPI_RETURN_IF_ERROR(ParseIpAndMask(ip_and_mask, &ip, &mask, &cidr));
|
|
|
|
SAPI_RETURN_IF_ERROR(AllowIPv4(ip, mask, cidr, port));
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
absl::Status AllowedHosts::AllowIPv6(const std::string& ip_and_mask,
|
2020-02-20 23:45:22 +08:00
|
|
|
uint32_t port) {
|
|
|
|
std::string ip;
|
|
|
|
uint32_t cidr;
|
|
|
|
SAPI_RETURN_IF_ERROR(ParseIpAndMask(ip_and_mask, &ip, NULL, &cidr));
|
|
|
|
SAPI_RETURN_IF_ERROR(AllowIPv6(ip, cidr, port));
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
absl::Status AllowedHosts::AllowIPv4(const std::string& ip,
|
2020-02-20 23:45:22 +08:00
|
|
|
const std::string& mask, uint32_t cidr,
|
|
|
|
uint32_t port) {
|
|
|
|
in_addr addr{};
|
|
|
|
in_addr m{};
|
|
|
|
|
|
|
|
if (mask.length()) {
|
|
|
|
SAPI_RETURN_IF_ERROR(IPStringToAddr(mask, AF_INET, &m));
|
|
|
|
|
|
|
|
if (!IsIPv4MaskCorrect(m.s_addr)) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat(mask, " is not a correct mask"));
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (cidr > 32) {
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::InvalidArgumentError(
|
2020-02-20 23:45:22 +08:00
|
|
|
absl::StrCat(cidr, " is not a correct cidr"));
|
|
|
|
}
|
|
|
|
if (!cidr) {
|
|
|
|
cidr = 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
SAPI_RETURN_IF_ERROR(CidrToInAddr(cidr, &m));
|
|
|
|
}
|
|
|
|
|
|
|
|
SAPI_RETURN_IF_ERROR(IPStringToAddr(ip, AF_INET, &addr));
|
|
|
|
allowed_IPv4_.emplace_back(addr.s_addr, m.s_addr, htons(port));
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 01:23:44 +08:00
|
|
|
absl::Status AllowedHosts::AllowIPv6(const std::string& ip, uint32_t cidr,
|
2020-02-20 23:45:22 +08:00
|
|
|
uint32_t port) {
|
|
|
|
if (cidr == 0) {
|
|
|
|
cidr = 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
in6_addr addr{};
|
|
|
|
SAPI_RETURN_IF_ERROR(IPStringToAddr(ip, AF_INET6, &addr));
|
|
|
|
|
|
|
|
in6_addr m;
|
|
|
|
SAPI_RETURN_IF_ERROR(CidrToIn6Addr(cidr, &m));
|
|
|
|
|
|
|
|
allowed_IPv6_.emplace_back(addr, m, htons(port));
|
2020-02-28 01:23:44 +08:00
|
|
|
return absl::OkStatus();
|
2020-02-20 23:45:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AllowedHosts::IsHostAllowed(const struct sockaddr* saddr) const {
|
|
|
|
switch (saddr->sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
return IsIPv4Allowed(reinterpret_cast<const struct sockaddr_in*>(saddr));
|
|
|
|
case AF_INET6:
|
|
|
|
return IsIPv6Allowed(reinterpret_cast<const struct sockaddr_in6*>(saddr));
|
|
|
|
default:
|
|
|
|
LOG(FATAL) << absl::StrCat("Unexpected sa_family value: ",
|
|
|
|
saddr->sa_family);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AllowedHosts::IsIPv6Allowed(const struct sockaddr_in6* saddr) const {
|
|
|
|
auto result = std::find_if(
|
|
|
|
allowed_IPv6_.begin(), allowed_IPv6_.end(), [saddr](const IPv6& entry) {
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if ((entry.ip.__in6_u.__u6_addr32[i] &
|
|
|
|
entry.mask.__in6_u.__u6_addr32[i]) !=
|
|
|
|
(saddr->sin6_addr.__in6_u.__u6_addr32[i] &
|
|
|
|
entry.mask.__in6_u.__u6_addr32[i])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!entry.port || (entry.port == saddr->sin6_port)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
return result != allowed_IPv6_.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AllowedHosts::IsIPv4Allowed(const struct sockaddr_in* saddr) const {
|
|
|
|
auto result = std::find_if(
|
|
|
|
allowed_IPv4_.begin(), allowed_IPv4_.end(), [saddr](const IPv4& entry) {
|
|
|
|
return ((entry.ip & entry.mask) ==
|
|
|
|
(saddr->sin_addr.s_addr & entry.mask)) &&
|
|
|
|
(!entry.port || (entry.port == saddr->sin_port));
|
|
|
|
});
|
|
|
|
|
|
|
|
return result != allowed_IPv4_.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace sandbox2
|