Compare commits

...
26 Commits
Author SHA1 Message Date
dependabot[bot]andNikolay Edigaryev 762868a8eb Bump smoltcp from 0.11.0 to 0.12.0 (#62)
* Bump smoltcp from 0.11.0 to 0.12.0

Bumps [smoltcp](https://github.com/smoltcp-rs/smoltcp) from 0.11.0 to 0.12.0.
- [Release notes](https://github.com/smoltcp-rs/smoltcp/releases)
- [Changelog](https://github.com/smoltcp-rs/smoltcp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/smoltcp-rs/smoltcp/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: smoltcp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* smoltcp moved to core::net types for IP addresses

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>
2024-12-05 00:15:21 +04:00
dependabot[bot] 95a3358f59 Bump hashbrown from 0.15.0 to 0.15.2 in the cargo group (#63)
Bumps the cargo group with 1 update: [hashbrown](https://github.com/rust-lang/hashbrown).


Updates `hashbrown` from 0.15.0 to 0.15.2
- [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/hashbrown/commits)

---
updated-dependencies:
- dependency-name: hashbrown
  dependency-type: indirect
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 00:15:12 +04:00
dependabot[bot] ebc7cf8973 Bump sentry from 0.34.0 to 0.35.0 (#60)
Bumps [sentry](https://github.com/getsentry/sentry-rust) from 0.34.0 to 0.35.0.
- [Release notes](https://github.com/getsentry/sentry-rust/releases)
- [Changelog](https://github.com/getsentry/sentry-rust/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-rust/compare/0.34.0...0.35.0)

---
updated-dependencies:
- dependency-name: sentry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 12:11:21 +04:00
dependabot[bot] 86f082ac77 Bump sentry-anyhow from 0.34.0 to 0.35.0 (#59)
Bumps [sentry-anyhow](https://github.com/getsentry/sentry-rust) from 0.34.0 to 0.35.0.
- [Release notes](https://github.com/getsentry/sentry-rust/releases)
- [Changelog](https://github.com/getsentry/sentry-rust/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-rust/compare/0.34.0...0.35.0)

---
updated-dependencies:
- dependency-name: sentry-anyhow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 12:02:04 +04:00
dependabot[bot] b3df49889a Bump libc from 0.2.164 to 0.2.167 (#61)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.164 to 0.2.167.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.167/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.164...0.2.167)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 12:01:37 +04:00
dependabot[bot] 82be9577b3 Bump clap from 4.5.20 to 4.5.21 (#57)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.20 to 4.5.21.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.20...clap_complete-v4.5.21)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 13:32:24 +04:00
dependabot[bot] 04c6019437 Bump libc from 0.2.162 to 0.2.164 (#58)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.162 to 0.2.164.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.162...0.2.164)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 13:32:14 +04:00
dependabot[bot] 7374ceb239 Bump polling from 3.7.3 to 3.7.4 (#54)
Bumps [polling](https://github.com/smol-rs/polling) from 3.7.3 to 3.7.4.
- [Release notes](https://github.com/smol-rs/polling/releases)
- [Changelog](https://github.com/smol-rs/polling/blob/master/CHANGELOG.md)
- [Commits](https://github.com/smol-rs/polling/compare/v3.7.3...v3.7.4)

---
updated-dependencies:
- dependency-name: polling
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 10:38:49 +04:00
dependabot[bot] cc7cc0e740 Bump anyhow from 1.0.92 to 1.0.93 (#55)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.92 to 1.0.93.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.92...1.0.93)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 10:38:38 +04:00
dependabot[bot] e53beeeb79 Bump libc from 0.2.161 to 0.2.162 (#56)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.161 to 0.2.162.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.162/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.161...0.2.162)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 10:37:50 +04:00
dependabot[bot] 05cba5d771 Bump anyhow from 1.0.91 to 1.0.92 (#53)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.91 to 1.0.92.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.91...1.0.92)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 18:50:40 +04:00
dependabot[bot] cf97e3878d Bump anyhow from 1.0.90 to 1.0.91 (#52)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.90 to 1.0.91.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.90...1.0.91)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-28 12:13:17 +04:00
dependabot[bot] 7f5293dd5e Bump libc from 0.2.159 to 0.2.161 (#50)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.159 to 0.2.161.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.161/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.159...0.2.161)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 11:53:12 +04:00
dependabot[bot] 9a2e59b844 Bump anyhow from 1.0.89 to 1.0.90 (#51)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.89 to 1.0.90.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.89...1.0.90)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 11:42:26 +04:00
dependabot[bot] 603c8b4889 Bump clap from 4.5.19 to 4.5.20 (#49) 2024-10-14 10:48:35 -04:00
Nikolay Edigaryev 24641d5325 $ cargo update (#48) 2024-10-03 23:54:02 +04:00
Nikolay Edigaryev ed64c139cf dependabot.yml: enable version updates for Cargo (#42) 2024-10-03 23:45:45 +04:00
Nikolay Edigaryev 8359992a08 $ cargo update (#40)
Also convert the "rust-toolchain" to "rust-toolchain.toml".
2024-07-23 14:33:31 +04:00
Nikolay Edigaryev 147c051b0e Disable isolation when --allow=0.0.0.0/0 is specified (#39)
* Disable isolation when --allow=0.0.0.0/0 is specified

* Upgrade & upgrade the dependencies
2024-07-02 15:36:07 +04:00
Nikolay Edigaryev 6456ed7228 README.md: proper nested bullet point syntax 2024-06-13 14:57:44 +04:00
Nikolay Edigaryev 56808c591f README.md: remove extraneous space 2024-06-13 14:57:02 +04:00
Nikolay Edigaryev eba21ed33e Link to Wikipedia's "ARP spoofing" article
And include some examples of the tools.
2024-06-13 14:56:01 +04:00
Nikolay Edigaryev 867679446e Ignore socketpair(2) errors when sending (#36) 2024-03-25 12:37:53 -04:00
Nikolay Edigaryev 4a13c5922b Prevent multiple --allow flags (#35)
* Prevent multiple --allow flags

* --allow: better value name instead of just <ALLOW>
2024-03-11 23:02:59 +04:00
Nikolay Edigaryev a92f4e0c99 Introduce --allow command-line argument to allow traffic to CIDRs (#34) 2024-03-11 22:07:39 +04:00
Sergei Parshev 0a92c290be Added a way to enable host-only networking through tart using --net-host (#32)
* Added a way to enable host-only networking through tart using SOFTNET_NET_TYPE=host

* Removed env variable and moved to Enum instead of str

* Fixed defaults & restricted publicity of host

* Fixed usage of NetType
2024-03-01 11:25:19 -05:00
14 changed files with 1106 additions and 628 deletions
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
Generated
+960 -563
View File
File diff suppressed because it is too large Load Diff
+18 -16
View File
@@ -12,19 +12,21 @@ inherits = "release"
debug = true
[dependencies]
smoltcp = "0.8.1"
libc = "0.2.126"
polling = { git = "https://github.com/smol-rs/polling.git" }
dhcproto = "0.7.0"
vmnet = "0.1.1"
clap = { version = "3.1.18", features = ["derive"] }
mac_address = "1.1.3"
privdrop = "0.5.2"
anyhow = { version = "1.0.66", features = ["backtrace"] }
ip_network = "0.4.1"
uzers = "0.11.3"
system-configuration = "0.5.0"
num_enum = "0.5.7"
sentry = { version = "0.29.1", features = ["debug-images"] }
sentry-anyhow = { version = "0.29.1", features = ["backtrace"] }
nix = "0.26.2"
smoltcp = "0"
libc = "0"
polling = "3"
dhcproto = "0"
vmnet = "0"
clap = { version = "4", features = ["derive"] }
mac_address = "1"
privdrop = "0"
anyhow = { version = "1", features = ["backtrace"] }
ip_network = "0"
uzers = "0"
system-configuration = "0"
num_enum = "0"
sentry = { version = "0", features = ["debug-images"] }
sentry-anyhow = { version = "0", features = ["backtrace"] }
nix = { version = "0", features = ["signal"] }
prefix-trie = "0"
ipnet = "2"
+2 -2
View File
@@ -8,9 +8,9 @@ Please check out [this blog post](https://cirrus-ci.org/blog/2022/07/07/isolatin
Softnet solves two problems:
1. VM network isolation
* [`VZNATNetworkDeviceAttachment`](https://developer.apple.com/documentation/virtualization/vznatnetworkdeviceattachment) (the default networking in Tart) enables [vmnet's bridge isolation](https://developer.apple.com/documentation/vmnet/vmnet_enable_isolation_key) by default and prevents cross-VM traffic, however it's still possible for any VM to spoof the host's ARP-table and capture other VMs traffic
* [`VZNATNetworkDeviceAttachment`](https://developer.apple.com/documentation/virtualization/vznatnetworkdeviceattachment) (the default networking in Tart) enables [vmnet's bridge isolation](https://developer.apple.com/documentation/vmnet/vmnet_enable_isolation_key) by default and prevents cross-VM traffic, however it's still possible for any VM to spoof the host's ARP-table and capture other VMs traffic by using tools that enable conducting the [ARP spoofing attacks](https://en.wikipedia.org/wiki/ARP_spoofing) (e.g. [arpspoof](https://www.monkey.org/~dugsong/dsniff/), [arpoison](http://www.arpoison.net/) and so on)
2. DHCP exhaustion
* macOS built-in DHCP-server allocates a `/24` subnet with 86400 seconds lease time by default, which only allows for ~253 VMs a day (or 1 VM every ~6 minutes) to be spawned without causing a denial-of-service, which is pretty limiting for CI services like Cirrus CI
* macOS built-in DHCP-server allocates a `/24` subnet with 86400 seconds lease time by default, which only allows for ~253 VMs a day (or 1 VM every ~6 minutes) to be spawned without causing a denial-of-service, which is pretty limiting for CI services like Cirrus CI
And assumes that:
+4 -4
View File
@@ -26,14 +26,14 @@ impl DhcpSnooper {
};
let dns_ips = match message.opts().get(OptionCode::DomainNameServer) {
Some(DhcpOption::DomainNameServer(dns_ips)) => HashSet::from_iter(
dns_ips.iter().map(|dns_ip| Ipv4Address(dns_ip.octets())),
),
Some(DhcpOption::DomainNameServer(dns_ips)) => {
HashSet::from_iter(dns_ips.iter().cloned())
}
_ => HashSet::new(),
};
self.vm_lease = Some(Lease::new(
message.yiaddr().into(),
message.yiaddr(),
Duration::from_secs(*lease_time as u64),
dns_ips,
))
+36 -10
View File
@@ -1,4 +1,5 @@
use anyhow::{anyhow, Context, Result};
use clap::ValueEnum;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::UnixDatagram;
@@ -8,6 +9,18 @@ use vmnet::mode::Mode;
use vmnet::parameters::{Parameter, ParameterKind};
use vmnet::{Events, Options};
#[derive(ValueEnum, Clone, Debug)]
pub enum NetType {
/// Shared network
///
/// Uses NAT-translation to give guests access to the global network
Nat,
/// Host network
///
/// Guests will be able to talk only to the host without access to global network
Host,
}
pub struct Host {
interface: vmnet::Interface,
new_packets_rx: UnixDatagram,
@@ -18,27 +31,38 @@ pub struct Host {
}
impl Host {
pub fn new() -> Result<Host> {
// Initialize a vmnet.framework NAT interface with isolation enabled
pub fn new(vm_net_type: NetType, enable_isolation: bool) -> Result<Host> {
// Initialize a vmnet.framework NAT or Host interface with isolation enabled
let mut interface = vmnet::Interface::new(
Mode::Shared(Default::default()),
match vm_net_type {
NetType::Nat => Mode::Shared(Default::default()),
NetType::Host => Mode::Host(Default::default()),
},
Options {
enable_isolation: Some(true),
enable_isolation: Some(enable_isolation),
..Default::default()
},
)
.context("failed to initialize vmnet interface")?;
// Retrieve first IP (gateway) used for this interface
let Some(Parameter::StartAddress(gateway_ip)) = interface.parameters().get(ParameterKind::StartAddress) else {
return Err(anyhow!("failed to retrieve vmnet's interface start address"));
let Some(Parameter::StartAddress(gateway_ip)) =
interface.parameters().get(ParameterKind::StartAddress)
else {
return Err(anyhow!(
"failed to retrieve vmnet's interface start address"
));
};
let gateway_ip = Ipv4Addr::from_str(&gateway_ip)
.context("failed to parse vmnet's interface start address")?;
// Retrieve max packet size for this interface
let Some(Parameter::MaxPacketSize(max_packet_size)) = interface.parameters().get(ParameterKind::MaxPacketSize) else {
return Err(anyhow!("failed to retrieve vmnet's interface max packet size"));
let Some(Parameter::MaxPacketSize(max_packet_size)) =
interface.parameters().get(ParameterKind::MaxPacketSize)
else {
return Err(anyhow!(
"failed to retrieve vmnet's interface max packet size"
));
};
// Set up a socketpair() to emulate polling of the vmnet interface
@@ -50,7 +74,9 @@ impl Host {
interface
.set_event_callback(Events::PACKETS_AVAILABLE, move |_mask, _params| {
// Send a dummy datagram to make the other end of socketpair() readable
new_packets_tx.send(&[0; 1]).unwrap();
// and ignore the error as this merely a signalling channel to wake up
// the poller
new_packets_tx.send(&[0; 1]).ok();
// Wait for the permission to continue to avoid
// wasting CPU cycles or in case of termination,
@@ -66,7 +92,7 @@ impl Host {
interface,
new_packets_rx,
callback_can_continue_tx,
gateway_ip: gateway_ip.into(),
gateway_ip,
max_packet_size,
finalized: false,
})
+1
View File
@@ -1,5 +1,6 @@
mod dhcp_snooper;
mod host;
pub use host::NetType;
mod poller;
pub mod proxy;
mod vm;
+18 -16
View File
@@ -2,14 +2,15 @@ use anyhow::Result;
use num_enum::IntoPrimitive;
use polling::os::kqueue::PollerKqueueExt;
use polling::PollMode;
use std::os::fd::{AsRawFd, BorrowedFd};
use std::os::unix::io::RawFd;
use std::time::Duration;
pub struct Poller {
pub struct Poller<'poller> {
poller: polling::Poller,
events: Vec<polling::Event>,
vm_fd: RawFd,
host_fd: RawFd,
events: polling::Events,
vm_fd: BorrowedFd<'poller>,
host_fd: BorrowedFd<'poller>,
}
#[derive(IntoPrimitive)]
@@ -20,22 +21,25 @@ enum EventKey {
Interrupt,
}
impl Poller {
pub fn new(vm_fd: RawFd, host_fd: RawFd) -> Result<Poller> {
impl Poller<'_> {
pub fn new<'poller>(vm_fd: RawFd, host_fd: RawFd) -> Result<Poller<'poller>> {
let poller = polling::Poller::new()?;
Ok(Poller {
poller,
events: Vec::new(),
vm_fd,
host_fd,
events: polling::Events::new(),
vm_fd: unsafe { BorrowedFd::borrow_raw(vm_fd) },
host_fd: unsafe { BorrowedFd::borrow_raw(host_fd) },
})
}
pub fn arm(&self) -> Result<()> {
self.poller.add(self.vm_fd as RawFd, self.vm_interest())?;
self.poller
.add(self.host_fd as RawFd, self.host_interest())?;
unsafe {
self.poller
.add(self.vm_fd.as_raw_fd(), self.vm_interest())?;
self.poller
.add(self.host_fd.as_raw_fd(), self.host_interest())?;
}
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
self.poller
@@ -52,10 +56,8 @@ impl Poller {
pub fn rearm(&mut self) -> Result<()> {
self.events.clear();
self.poller
.modify(self.vm_fd as RawFd, self.vm_interest())?;
self.poller
.modify(self.host_fd as RawFd, self.host_interest())?;
self.poller.modify(self.vm_fd, self.vm_interest())?;
self.poller.modify(self.host_fd, self.host_interest())?;
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
self.poller.modify_filter(
+2 -2
View File
@@ -3,7 +3,7 @@ use crate::proxy::Proxy;
use anyhow::{Context, Result};
use smoltcp::wire::{EthernetFrame, EthernetProtocol, Ipv4Packet, UdpPacket};
impl Proxy {
impl Proxy<'_> {
pub(crate) fn process_frame_from_host(&mut self, frame: &EthernetFrame<&[u8]>) -> Result<()> {
if self.allowed_from_host(frame).is_none() {
// Block packet by not forwarding it to the VM
@@ -58,7 +58,7 @@ impl Proxy {
return;
}
if ipv4_pkt.protocol() != smoltcp::wire::IpProtocol::Udp {
if ipv4_pkt.next_header() != smoltcp::wire::IpProtocol::Udp {
return;
}
+15 -5
View File
@@ -4,27 +4,36 @@ mod vm;
use crate::dhcp_snooper::DhcpSnooper;
use crate::host::Host;
use crate::host::NetType;
use crate::poller::Poller;
use crate::vm::VM;
use anyhow::Result;
use ipnet::Ipv4Net;
use mac_address::MacAddress;
use prefix_trie::{Prefix, PrefixSet};
use smoltcp::wire::EthernetFrame;
use std::io::ErrorKind;
use std::os::unix::io::{AsRawFd, RawFd};
pub struct Proxy {
pub struct Proxy<'proxy> {
vm: VM,
host: Host,
poller: Poller,
poller: Poller<'proxy>,
vm_mac_address: smoltcp::wire::EthernetAddress,
dhcp_snooper: DhcpSnooper,
allow: PrefixSet<Ipv4Net>,
enobufs_encountered: bool,
}
impl Proxy {
pub fn new(vm_fd: RawFd, vm_mac_address: MacAddress) -> Result<Proxy> {
impl Proxy<'_> {
pub fn new<'proxy>(
vm_fd: RawFd,
vm_mac_address: MacAddress,
vm_net_type: NetType,
allow: PrefixSet<Ipv4Net>,
) -> Result<Proxy<'proxy>> {
let vm = VM::new(vm_fd)?;
let host = Host::new()?;
let host = Host::new(vm_net_type, !allow.contains(&Ipv4Net::zero()))?;
let poller = Poller::new(vm.as_raw_fd(), host.as_raw_fd())?;
Ok(Proxy {
@@ -33,6 +42,7 @@ impl Proxy {
poller,
vm_mac_address: smoltcp::wire::EthernetAddress(vm_mac_address.bytes()),
dhcp_snooper: Default::default(),
allow,
enobufs_encountered: false,
})
}
+19 -7
View File
@@ -2,12 +2,13 @@ use crate::proxy::udp_packet_helper::UdpPacketHelper;
use crate::proxy::Proxy;
use anyhow::Context;
use anyhow::Result;
use ipnet::Ipv4Net;
use smoltcp::wire::{
ArpPacket, EthernetFrame, EthernetProtocol, IpProtocol, Ipv4Packet, UdpPacket,
};
use std::net::Ipv4Addr;
impl Proxy {
impl Proxy<'_> {
pub(crate) fn process_frame_from_vm(&mut self, frame: EthernetFrame<&[u8]>) -> Result<()> {
if self.allowed_from_vm(&frame).is_none() {
// Block packet by not forwarding it to the host
@@ -47,7 +48,7 @@ impl Proxy {
let source_protocol_addr = Ipv4Addr::from(source_protocol_addr);
if let Some(lease) = self.dhcp_snooper.lease() {
if lease.valid_ip_source(source_protocol_addr.into()) {
if lease.valid_ip_source(source_protocol_addr) {
return Some(());
}
} else if source_protocol_addr.is_unspecified() {
@@ -58,15 +59,26 @@ impl Proxy {
}
fn allowed_from_vm_ipv4(&self, ipv4_pkt: Ipv4Packet<&[u8]>) -> Option<()> {
// Once we've learned the VM's IP from the DHCP snooping,
// allow all global traffic for that VM's IP
// Have we learned the VM's IP from the DHCP snooping?
if let Some(lease) = &self.dhcp_snooper.lease() {
let dst_is_global =
ip_network::IpNetwork::from(Ipv4Addr::from(ipv4_pkt.dst_addr().0)).is_global();
// If so, allow all global traffic
let dst_addr = ipv4_pkt.dst_addr();
let dst_is_global = ip_network::IpNetwork::from(dst_addr).is_global();
if lease.valid_ip_source(ipv4_pkt.src_addr()) && dst_is_global {
return Some(());
}
// Also allow all traffic to the user-specified CIDRs
let dst_net = Ipv4Net::from(dst_addr);
// Use get_lpm() instead of get_spm() to work around prefix-trie
// not handling prefixes like 0.0.0.0/0 correctly[1]
//
// [1]: https://github.com/tiborschneider/prefix-trie/issues/8
if self.allow.get_lpm(&dst_net).is_some() {
return Some(());
}
}
// Allow communication with host
@@ -74,7 +86,7 @@ impl Proxy {
return Some(());
}
if ipv4_pkt.protocol() == IpProtocol::Udp {
if ipv4_pkt.next_header() == IpProtocol::Udp {
let udp_pkt = UdpPacket::new_checked(ipv4_pkt.payload()).ok()?;
// Allow DNS communication with the DNS-servers provided by DHCP
-1
View File
@@ -1 +0,0 @@
nightly
+2
View File
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"
+23 -2
View File
@@ -1,10 +1,14 @@
use anyhow::{anyhow, Context};
use clap::Parser;
use ipnet::Ipv4Net;
use nix::sys::signal::{signal, SigHandler, Signal};
use prefix_trie::PrefixSet;
use privdrop::PrivDrop;
use softnet::proxy::Proxy;
use softnet::NetType;
use std::borrow::Cow;
use std::env;
use std::os::raw::c_int;
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
@@ -28,6 +32,9 @@ struct Args {
#[clap(long, help = "MAC address to enforce for the VM")]
vm_mac_address: mac_address::MacAddress,
#[clap(long, value_enum, help = "type of network to use for the VM", default_value_t=NetType::Nat)]
vm_net_type: NetType,
#[clap(
long,
help = "set bootpd(8) lease time to this value (in seconds) before starting the VM",
@@ -41,6 +48,15 @@ struct Args {
#[clap(long, help = "group name to drop privileges to")]
group: Option<String>,
#[clap(
long,
help = "comma-separated list of CIDRs to allow the traffic to (e.g. --allow=192.168.0.0/24)",
value_name = "comma-separated CIDRs",
use_value_delimiter = true,
action = clap::ArgAction::Set
)]
allow: Vec<Ipv4Net>,
#[clap(long, hide = true)]
sudo_escalation_probing: bool,
@@ -140,8 +156,13 @@ fn try_main() -> anyhow::Result<()> {
set_bootpd_lease_time(args.bootpd_lease_time);
// Initialize the proxy while still having the root privileges
let mut proxy = Proxy::new(args.vm_fd as RawFd, args.vm_mac_address)
.context("failed to initialize proxy")?;
let mut proxy = Proxy::new(
args.vm_fd as RawFd,
args.vm_mac_address,
args.vm_net_type,
PrefixSet::from_iter(args.allow),
)
.context("failed to initialize proxy")?;
// Drop effective privileges to the user
// and group which have had invoked us