Compare commits

...
12 Commits
Author SHA1 Message Date
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
11 changed files with 978 additions and 651 deletions
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
Generated
+911 -599
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -12,21 +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 = "4.5.2", 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"
prefix-trie = "0.3.0"
ipnet = "2.9.0"
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:
+5 -3
View File
@@ -31,7 +31,7 @@ pub struct Host {
}
impl Host {
pub fn new(vm_net_type: NetType) -> Result<Host> {
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(
match vm_net_type {
@@ -39,7 +39,7 @@ impl Host {
NetType::Host => Mode::Host(Default::default()),
},
Options {
enable_isolation: Some(true),
enable_isolation: Some(enable_isolation),
..Default::default()
},
)
@@ -74,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,
+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;
}
+7 -7
View File
@@ -10,30 +10,30 @@ use crate::vm::VM;
use anyhow::Result;
use ipnet::Ipv4Net;
use mac_address::MacAddress;
use prefix_trie::PrefixSet;
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(
impl Proxy<'_> {
pub fn new<'proxy>(
vm_fd: RawFd,
vm_mac_address: MacAddress,
vm_net_type: NetType,
allow: PrefixSet<Ipv4Net>,
) -> Result<Proxy> {
) -> Result<Proxy<'proxy>> {
let vm = VM::new(vm_fd)?;
let host = Host::new(vm_net_type)?;
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 {
+7 -3
View File
@@ -8,7 +8,7 @@ use smoltcp::wire::{
};
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
@@ -72,7 +72,11 @@ impl Proxy {
// Also allow all traffic to the user-specified CIDRs
let dst_net = Ipv4Net::from(dst_addr);
if self.allow.get_spm(&dst_net).is_some() {
// 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(());
}
}
@@ -82,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"