This commit is contained in:
Nikolay Edigaryev 2026-05-28 00:56:08 +01:00
parent 2947383d1a
commit 97e7da22fb
2 changed files with 78 additions and 16 deletions

View File

@ -42,6 +42,16 @@ pub enum Target {
Host,
}
impl Target {
pub fn is_ipv4_default_route(&self) -> bool {
matches!(self, Target::Prefix(prefix) if *prefix == Ipv4Net::zero())
}
pub fn is_mac_address(&self) -> bool {
matches!(self, Target::MacAddress(_))
}
}
impl FromStr for Target {
type Err = ipnet::AddrParseError;
@ -69,17 +79,11 @@ impl Proxy<'_> {
vm_fd: RawFd,
vm_mac_address: MacAddress,
vm_net_type: NetType,
enable_isolation: bool,
allow: Vec<Target>,
block: Vec<Target>,
exposed_ports: Vec<ExposedPort>,
) -> Result<Proxy<'proxy>> {
let allowing_all_ipv4 = allow.contains(&Target::Prefix(Ipv4Net::zero()));
let using_mac_filtering = allow
.iter()
.chain(block.iter())
.any(|target| matches!(target, Target::MacAddress(_)));
let enable_isolation = !allowing_all_ipv4 && !using_mac_filtering;
let vm = VM::new(vm_fd)?;
let host = Host::new(vm_net_type, enable_isolation)?;
let poller_timeout = Duration::from_millis(100);
@ -226,7 +230,7 @@ impl Proxy<'_> {
mod tests {
use crate::NetType;
use crate::dhcp_snooper::Lease;
use crate::proxy::{Action, Proxy};
use crate::proxy::{Action, Proxy, Target};
use ipnet::Ipv4Net;
use mac_address::MacAddress;
use nix::sys::socket::{AddressFamily, SockFlag, SockType, socketpair};
@ -329,18 +333,24 @@ mod tests {
.unwrap();
let vm_fd = Box::leak(Box::new(vm_fd));
let allow: Vec<Target> = allow
.into_iter()
.map(|cidr| cidr.parse().unwrap())
.collect();
let block: Vec<Target> = block
.into_iter()
.map(|cidr| cidr.parse().unwrap())
.collect();
let enable_isolation = !allow.iter().any(Target::is_ipv4_default_route)
&& !allow.iter().chain(block.iter()).any(Target::is_mac_address);
let mut proxy = Proxy::new(
vm_fd.as_raw_fd(),
MacAddress::from_str("02:00:00:00:00:01").unwrap(),
NetType::Nat,
allow
.into_iter()
.map(|cidr| cidr.parse().unwrap())
.collect(),
block
.into_iter()
.map(|cidr| cidr.parse().unwrap())
.collect(),
enable_isolation,
allow,
block,
Vec::default(),
)
.unwrap();

View File

@ -194,11 +194,14 @@ fn try_main() -> anyhow::Result<()> {
// Set bootpd(8) min/max lease time while still having the root privileges
set_bootpd_lease_time(args.bootpd_lease_time);
let enable_isolation = bridge_isolation_enabled(&args.allow, &args.block);
// Initialize the proxy while still having the root privileges
let mut proxy = Proxy::new(
args.vm_fd as RawFd,
args.vm_mac_address,
args.vm_net_type,
enable_isolation,
args.allow,
args.block,
args.expose,
@ -231,6 +234,14 @@ fn sudo_escalation_works() -> bool {
.unwrap_or(false)
}
fn bridge_isolation_enabled(allow: &[Target], block: &[Target]) -> bool {
let disables_isolation_for_compat = allow.iter().any(Target::is_ipv4_default_route);
let disables_isolation_for_mac_filtering =
allow.iter().chain(block.iter()).any(Target::is_mac_address);
!(disables_isolation_for_compat || disables_isolation_for_mac_filtering)
}
fn set_bootpd_lease_time(lease_time: u32) {
let prefs = SCPreferences::group(
&CFString::new("softnet"),
@ -252,3 +263,44 @@ fn set_bootpd_lease_time(lease_time: u32) {
SCPreferencesCommitChanges(prefs.as_concrete_TypeRef());
}
}
#[cfg(test)]
mod tests {
use super::*;
fn targets(values: &[&str]) -> Vec<Target> {
values.iter().map(|value| value.parse().unwrap()).collect()
}
#[test]
fn bridge_isolation_disabled_for_legacy_allow_default_route() {
assert!(!bridge_isolation_enabled(
&targets(&["0.0.0.0/0"]),
&targets(&[])
));
}
#[test]
fn bridge_isolation_disabled_for_legacy_allow_default_route_even_when_blocked() {
assert!(!bridge_isolation_enabled(
&targets(&["0.0.0.0/0"]),
&targets(&["0.0.0.0/0"])
));
}
#[test]
fn bridge_isolation_kept_for_block_default_route_only() {
assert!(bridge_isolation_enabled(
&targets(&[]),
&targets(&["0.0.0.0/0"])
));
}
#[test]
fn bridge_isolation_disabled_for_mac_filtering() {
assert!(!bridge_isolation_enabled(
&targets(&[]),
&targets(&["02:00:00:00:00:02"])
));
}
}