Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions base/cvd/allocd/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load("//cuttlefish/bazel:rules.bzl", "cf_cc_binary", "cf_cc_library")
load("//cuttlefish/bazel:rules.bzl", "cf_cc_binary", "cf_cc_library", "cf_cc_test")

package(
default_visibility = ["//:android_cuttlefish"],
Expand Down Expand Up @@ -33,8 +33,9 @@ cf_cc_library(
depend_on_what_you_use_enabled = False,
deps = select({
":netlink": [":alloc_netlink"],
"//conditions:default": [":alloc_iproute2"],
"//conditions:default": [":alloc_netlink"],
}) + [
"//allocd/net:nftables",
"//cuttlefish/common/libs/fs",
"//cuttlefish/common/libs/utils:files",
"//cuttlefish/common/libs/utils:network",
Expand Down Expand Up @@ -80,3 +81,13 @@ cf_cc_library(
"@abseil-cpp//absl/strings:str_format",
],
)

cf_cc_test(
name = "alloc_utils_firewall_test",
srcs = ["alloc_utils_firewall_test.cpp"],
deps = [
":alloc_utils",
"//allocd/test:mock_nftables",
"//cuttlefish/result:result_matchers",
],
)
3 changes: 0 additions & 3 deletions base/cvd/allocd/alloc_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ Result<void> LinkTapToBridge(std::string_view tap_name,
Result<void> DeleteIface(std::string_view name);
Result<bool> BridgeInUse(std::string_view name);
Result<bool> BridgeExists(std::string_view name);
Result<bool> BridgeInUse(std::string_view name);
Result<void> CreateBridge(std::string_view name);
Result<void> IptableConfig(std::string_view iptables_path,
std::string_view network, bool add);

} // namespace cuttlefish
9 changes: 0 additions & 9 deletions base/cvd/allocd/alloc_iproute2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,4 @@ Result<void> CreateBridge(std::string_view name) {
return {};
}

Result<void> IptableConfig(std::string_view iptables_path,
std::string_view network, bool add) {
CF_EXPECT(Execute({std::string(iptables_path), "-t", "nat", add ? "-A" : "-D",
"POSTROUTING", "-s", std::string(network), "-j",
"MASQUERADE"}) == 0,
"IptableConfig");
return {};
}

} // namespace cuttlefish
10 changes: 0 additions & 10 deletions base/cvd/allocd/alloc_netlink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,4 @@ Result<void> CreateBridge(std::string_view name) {
return {};
}

Result<void> IptableConfig(std::string_view iptables_path,
std::string_view network, bool add) {
// TODO: Use NETLINK_NETFILTER.
CF_EXPECT(Execute({std::string(iptables_path), "-t", "nat", add ? "-A" : "-D",
"POSTROUTING", "-s", std::string(network), "-j",
"MASQUERADE"}) == 0,
"IptableConfig");
return {};
}

} // namespace cuttlefish
163 changes: 90 additions & 73 deletions base/cvd/allocd/alloc_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include <string>
#include <string_view>

#include "absl/base/no_destructor.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
Expand All @@ -48,16 +47,78 @@ namespace cuttlefish {

namespace {

Result<std::string> SearchForIptables() {
Result<std::string> p = Search(Path(), "iptables");
if (p.ok()) {
return p;
// nftables address families.
constexpr std::string_view kFamilyIp = "ip";
constexpr std::string_view kFamilyBridge = "bridge";

// nftables table names.
constexpr std::string_view kNatTable = "cuttlefish_nat";
constexpr std::string_view kBridgeTable = "cuttlefish_bridge";

// nftables chain names.
constexpr std::string_view kPostroutingChain = "postrouting";
constexpr std::string_view kPreroutingChain = "prerouting";
constexpr std::string_view kForwardChain = "forward";

// Base chain hook definitions, supplied when the chains are created.
constexpr std::string_view kNatPostroutingChainDef =
"{ type nat hook postrouting priority 100 ; }";
constexpr std::string_view kBridgePreroutingChainDef =
"{ type filter hook prerouting priority -250 ; }";
constexpr std::string_view kBridgeForwardChainDef =
"{ type filter hook forward priority 0 ; }";

// The /30 netmask carving each mobile interface into a point-to-point subnet.
constexpr std::string_view kMobileNetmask = "/30";

// Bridge subnets that receive a permanent masquerade rule during setup.
constexpr std::string_view kBridgeSubnets[] = {
"192.168.96.0/24",
"192.168.98.0/24",
"192.168.160.0/24",
"192.168.192.0/24",
};

// Builds the nftables expression masquerading traffic sourced from `source`,
// an address or CIDR subnet.
std::string MasqueradeRule(std::string_view source) {
return absl::StrCat("ip saddr ", source, " masquerade");
}

} // namespace

Result<void> SetupFirewall(Nftables& nft, bool setup_byob) {
CF_EXPECT(nft.EnsureTable(kFamilyIp, kNatTable));
CF_EXPECT(nft.EnsureChain(kFamilyIp, kNatTable, kPostroutingChain,
kNatPostroutingChainDef));

for (std::string_view subnet : kBridgeSubnets) {
CF_EXPECT(nft.AddRule(kFamilyIp, kNatTable, kPostroutingChain,
MasqueradeRule(subnet)));
}

if (setup_byob) {
CF_EXPECT(nft.EnsureTable(kFamilyBridge, kBridgeTable));
CF_EXPECT(nft.EnsureChain(kFamilyBridge, kBridgeTable, kPreroutingChain,
kBridgePreroutingChainDef));
CF_EXPECT(nft.EnsureChain(kFamilyBridge, kBridgeTable, kForwardChain,
kBridgeForwardChainDef));
}

return CF_EXPECT(Search({"/usr/sbin", "/sbin"}, "iptables"));
return {};
}

} // namespace
Result<void> TeardownFirewall(Nftables& nft) {
auto res = nft.DeleteTable(kFamilyIp, kNatTable);
if (!res.ok()) {
LOG(WARNING) << "Failed to delete " << kNatTable
<< " table: " << res.error();
}

(void)nft.DeleteTable(kFamilyBridge, kBridgeTable);

return {};
}

bool CreateEthernetIface(std::string_view name, std::string_view bridge_name) {
// assume bridge exists
Expand Down Expand Up @@ -87,56 +148,43 @@ std::string MobileNetworkName(std::string_view ipaddr, std::string_view netmask,
return ss.str();
}

bool CreateMobileIface(std::string_view name, uint16_t id,
std::string_view ipaddr) {
if (id > kMaxIfaceNameId) {
LOG(ERROR) << "ID exceeds maximum value to assign a netmask: " << id;
return false;
}

auto netmask = "/30";
Result<std::string> iptables_path = IptablesPath();
if (!iptables_path.ok()) {
return false;
}
Result<NftRule> CreateMobileIface(Nftables& nft, std::string_view name,
uint16_t id, std::string_view ipaddr) {
CF_EXPECTF(id <= kMaxIfaceNameId,
"ID exceeds maximum value to assign a netmask: {}", id);

auto gateway = MobileGatewayName(ipaddr, id);
auto network = MobileNetworkName(ipaddr, netmask, id);
auto network = MobileNetworkName(ipaddr, kMobileNetmask, id);

if (!CreateTap(name)) {
return false;
}
CF_EXPECTF(CreateTap(name), "Failed to create tap interface: {}", name);

if (!AddGateway(name, gateway, netmask).ok()) {
DestroyIface(name);
if (!AddGateway(name, gateway, kMobileNetmask).ok()) {
(void)DestroyIface(name);
return CF_ERRF("Failed to add gateway to interface: {}", name);
}

if (!IptableConfig(*iptables_path, network, true).ok()) {
(void)DestroyGateway(name, gateway, netmask);
auto rule = NftRule::Create(nft, kFamilyIp, kNatTable, kPostroutingChain,
MasqueradeRule(network));
if (!rule.ok()) {
(void)DestroyGateway(name, gateway, kMobileNetmask);
(void)DestroyIface(name);
return false;
};
return CF_ERRF("Failed to create NftRule for interface {}: {}", name,
rule.error());
}

return true;
return rule;
}

bool DestroyMobileIface(std::string_view name, uint16_t id,
std::string_view ipaddr) {
if (id > 63) {
if (id > kMaxIfaceNameId) {
LOG(ERROR) << "ID exceeds maximum value to assign a netmask: " << id;
return false;
}

auto netmask = "/30";
auto gateway = MobileGatewayName(ipaddr, id);
auto network = MobileNetworkName(ipaddr, netmask, id);

Result<std::string> iptables_path = IptablesPath();
if (!iptables_path.ok()) {
return false;
}
(void)IptableConfig(*iptables_path, network, false);
(void)DestroyGateway(name, gateway, netmask);
(void)DestroyGateway(name, gateway, kMobileNetmask);
return DestroyIface(name);
}

Expand Down Expand Up @@ -226,15 +274,9 @@ bool DestroyBridge(std::string_view name) {
}

bool SetupBridgeGateway(std::string_view bridge_name, std::string_view ipaddr) {
Result<std::string> iptables_path = IptablesPath();
if (!iptables_path.ok()) {
return false;
}

GatewayConfig config{false, false, false};
GatewayConfig config{false, false};
auto gateway = absl::StrFormat("%s.1", ipaddr);
auto netmask = "/24";
auto network = absl::StrFormat("%s.0%s", ipaddr, netmask);
auto dhcp_range = absl::StrFormat("%s.2,%s.255", ipaddr, ipaddr);

if (!AddGateway(bridge_name, gateway, netmask).ok()) {
Expand All @@ -248,30 +290,13 @@ bool SetupBridgeGateway(std::string_view bridge_name, std::string_view ipaddr) {
return false;
}

config.has_dnsmasq = true;

auto ret = IptableConfig(*iptables_path, network, true).ok();
if (!ret) {
CleanupBridgeGateway(bridge_name, ipaddr, config);
LOG(WARNING) << "Failed to setup ip tables";
}

return ret;
return true;
}

void CleanupBridgeGateway(std::string_view name, std::string_view ipaddr,
const GatewayConfig& config) {
auto gateway = absl::StrFormat("%s.1", ipaddr);
auto netmask = "/24";
auto network = absl::StrFormat("%s.0%s", ipaddr, netmask);
auto dhcp_range = absl::StrFormat("%s.2,%s.255", ipaddr, ipaddr);

if (config.has_iptable) {
Result<std::string> iptables_path = IptablesPath();
if (iptables_path.ok()) {
(void)IptableConfig(*iptables_path, network, false);
}
}

if (config.has_dnsmasq) {
StopDnsmasq(name);
Expand Down Expand Up @@ -349,7 +374,7 @@ bool CreateEthernetBridgeIface(std::string_view name, std::string_view ipaddr) {

bool DestroyEthernetBridgeIface(std::string_view name,
std::string_view ipaddr) {
GatewayConfig config{true, true, true};
GatewayConfig config{true, true};

// Don't need to check if removing some part of the config failed, we need to
// remove the entire interface, so just ignore any error until the end
Expand All @@ -358,12 +383,4 @@ bool DestroyEthernetBridgeIface(std::string_view name,
return DestroyBridge(name);
}

Result<std::string> IptablesPath() {
static const absl::NoDestructor<std::string> iptables_path(
SearchForIptables().value_or(""));

CF_EXPECT(!iptables_path->empty(), "could not find iptables");
return *iptables_path;
}

} // namespace cuttlefish
11 changes: 7 additions & 4 deletions base/cvd/allocd/alloc_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <string>
#include <string_view>

#include "allocd/net/nft_rule.h"
#include "allocd/net/nftables.h"
#include "cuttlefish/result/result.h"

namespace cuttlefish {
Expand All @@ -48,11 +50,9 @@ inline constexpr uint32_t kMaxIfaceNameId = 63;
struct GatewayConfig {
bool has_gateway = false;
bool has_dnsmasq = false;
bool has_iptable = false;
};

int RunExternalCommand(const std::string& command);
Result<std::string> IptablesPath();
std::optional<std::string> GetUserName(uid_t uid);

bool CreateTap(std::string_view name);
Expand All @@ -65,8 +65,11 @@ bool DestroyIface(std::string_view name);

bool DestroyBridge(std::string_view name);

bool CreateMobileIface(std::string_view name, uint16_t id,
std::string_view ipaddr);
Result<void> SetupFirewall(Nftables& nft, bool setup_byob = false);
Result<void> TeardownFirewall(Nftables& nft);

Result<NftRule> CreateMobileIface(Nftables& nft, std::string_view name,
uint16_t id, std::string_view ipaddr);
bool DestroyMobileIface(std::string_view name, uint16_t id,
std::string_view ipaddr);

Expand Down
Loading
Loading