mirror of
https://github.com/cirruslabs/softnet.git
synced 2026-10-01 04:21:54 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a92c290be | ||
|
|
f5a1b1cdbd | ||
|
|
817dbb6e32 | ||
|
|
5f3b371e93 | ||
|
|
cd5f1d2f4f | ||
|
|
a775a92772 | ||
|
|
f38d65f98f |
+7
-5
@@ -4,17 +4,18 @@ env:
|
||||
task:
|
||||
name: Build
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-monterey-xcode:14
|
||||
image: ghcr.io/cirruslabs/macos-sonoma-xcode:latest
|
||||
install_rust_script:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
- rustup target add x86_64-apple-darwin
|
||||
build_script:
|
||||
- cargo build
|
||||
- cargo build --target aarch64-apple-darwin --target x86_64-apple-darwin
|
||||
|
||||
task:
|
||||
name: Release
|
||||
only_if: $CIRRUS_TAG != ''
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-monterey-xcode:14
|
||||
image: ghcr.io/cirruslabs/macos-sonoma-xcode:latest
|
||||
env:
|
||||
GITHUB_TOKEN: ENCRYPTED[!98ace8259c6024da912c14d5a3c5c6aac186890a8d4819fad78f3e0c41a4e0cd3a2537dd6e91493952fb056fa434be7c!]
|
||||
GORELEASER_KEY: ENCRYPTED[!9b80b6ef684ceaf40edd4c7af93014ee156c8aba7e6e5795f41c482729887b5c31f36b651491d790f1f668670888d9fd!]
|
||||
@@ -23,13 +24,14 @@ task:
|
||||
SENTRY_AUTH_TOKEN: ENCRYPTED[!c16a5cf7da5f856b4bc2f21fe8cb7aa2a6c981f851c094ed4d3025fd02ea59a58a86cee8b193a69a1fc20fa217e56ac3!]
|
||||
install_rust_script:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
- rustup target add x86_64-apple-darwin
|
||||
install_script:
|
||||
- brew install go goreleaser/tap/goreleaser-pro getsentry/tools/sentry-cli
|
||||
build_script:
|
||||
- cargo build --profile release-with-debug
|
||||
- cargo build --target aarch64-apple-darwin --target x86_64-apple-darwin --profile release-with-debug
|
||||
release_script: goreleaser
|
||||
upload_sentry_debug_files_script:
|
||||
- cd target/release-with-debug/
|
||||
- cd target/aarch64-apple-darwin/release-with-debug/
|
||||
# Generate and upload symbols
|
||||
- dsymutil softnet
|
||||
- sentry-cli debug-files upload -o $SENTRY_ORG -p $SENTRY_PROJECT softnet.dSYM/
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
/.idea
|
||||
/dist
|
||||
/target
|
||||
|
||||
+7
-9
@@ -1,29 +1,27 @@
|
||||
project_name: softnet
|
||||
|
||||
builds:
|
||||
- builder: prebuilt
|
||||
- id: softnet
|
||||
builder: prebuilt
|
||||
goamd64: [v1]
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- arm64
|
||||
- amd64
|
||||
prebuilt:
|
||||
path: "target/release-with-debug/softnet"
|
||||
path: 'target/{{- if eq .Arch "arm64" }}aarch64{{- else }}x86_64{{ end }}-apple-darwin/release-with-debug/softnet'
|
||||
|
||||
archives:
|
||||
- id: binary
|
||||
format: binary
|
||||
name_template: "{{ .ProjectName }}"
|
||||
- id: regular
|
||||
name_template: "{{ .ProjectName }}"
|
||||
name_template: "{{ .ProjectName }}-{{ .Arch }}"
|
||||
|
||||
release:
|
||||
prerelease: auto
|
||||
|
||||
brews:
|
||||
- name: softnet
|
||||
ids:
|
||||
- regular
|
||||
tap:
|
||||
repository:
|
||||
owner: cirruslabs
|
||||
name: homebrew-cli
|
||||
caveats: See the Github repository for more information
|
||||
|
||||
Generated
+13
-13
@@ -970,9 +970,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1351,7 +1351,7 @@ dependencies = [
|
||||
"sentry-anyhow",
|
||||
"smoltcp",
|
||||
"system-configuration",
|
||||
"users",
|
||||
"uzers",
|
||||
"vmnet",
|
||||
]
|
||||
|
||||
@@ -1634,16 +1634,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "users"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.0"
|
||||
@@ -1654,6 +1644,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uzers"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76d283dc7e8c901e79e32d077866eaf599156cbf427fffa8289aecc52c5c3f63"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ mac_address = "1.1.3"
|
||||
privdrop = "0.5.2"
|
||||
anyhow = { version = "1.0.66", features = ["backtrace"] }
|
||||
ip_network = "0.4.1"
|
||||
users = "0.11.0"
|
||||
uzers = "0.11.3"
|
||||
system-configuration = "0.5.0"
|
||||
num_enum = "0.5.7"
|
||||
sentry = { version = "0.29.1", features = ["debug-images"] }
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Softnet
|
||||
|
||||
Softnet is a software networking for [Tart](https://github.com/cirruslabs/tart) which provides better network isolation and alleviates DHCP shortage on production systems.
|
||||
Please check out [this blog post](https://cirrus-ci.org/blog/2022/07/07/isolating-network-between-tarts-macos-virtual-machines/) for backstory.
|
||||
|
||||
## Working model
|
||||
|
||||
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, for example
|
||||
* [`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
|
||||
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
|
||||
|
||||
@@ -30,4 +31,4 @@ For proper functioning, Softnet binary requires two things:
|
||||
|
||||
## Running
|
||||
|
||||
Softnet is started and managed automatically by Tart if `--with-softnet` flag is present when calling `tart run`.
|
||||
Softnet is started and managed automatically by Tart if `--net-softnet` flag is provided when calling `tart run`.
|
||||
|
||||
+19
-3
@@ -1,3 +1,4 @@
|
||||
use clap::ArgEnum;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
@@ -8,6 +9,18 @@ use vmnet::mode::Mode;
|
||||
use vmnet::parameters::{Parameter, ParameterKind};
|
||||
use vmnet::{Events, Options};
|
||||
|
||||
#[derive(ArgEnum, 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,10 +31,13 @@ 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) -> 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),
|
||||
..Default::default()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod dhcp_snooper;
|
||||
mod host;
|
||||
pub use host::NetType;
|
||||
mod poller;
|
||||
pub mod proxy;
|
||||
mod vm;
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -22,9 +23,9 @@ pub struct Proxy {
|
||||
}
|
||||
|
||||
impl Proxy {
|
||||
pub fn new(vm_fd: RawFd, vm_mac_address: MacAddress) -> Result<Proxy> {
|
||||
pub fn new(vm_fd: RawFd, vm_mac_address: MacAddress, vm_net_type: NetType) -> Result<Proxy> {
|
||||
let vm = VM::new(vm_fd)?;
|
||||
let host = Host::new()?;
|
||||
let host = Host::new(vm_net_type)?;
|
||||
let poller = Poller::new(vm.as_raw_fd(), host.as_raw_fd())?;
|
||||
|
||||
Ok(Proxy {
|
||||
|
||||
+6
-2
@@ -2,6 +2,7 @@ use anyhow::{anyhow, Context};
|
||||
use clap::Parser;
|
||||
use nix::sys::signal::{signal, SigHandler, Signal};
|
||||
use privdrop::PrivDrop;
|
||||
use softnet::NetType;
|
||||
use softnet::proxy::Proxy;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
@@ -15,7 +16,7 @@ use system_configuration::core_foundation::number::CFNumber;
|
||||
use system_configuration::core_foundation::string::CFString;
|
||||
use system_configuration::preferences::SCPreferences;
|
||||
use system_configuration::sys::preferences::{SCPreferencesCommitChanges, SCPreferencesSetValue};
|
||||
use users::{get_current_groupname, get_current_username, get_effective_uid};
|
||||
use uzers::{get_current_groupname, get_current_username, get_effective_uid};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Args {
|
||||
@@ -28,6 +29,9 @@ struct Args {
|
||||
#[clap(long, help = "MAC address to enforce for the VM")]
|
||||
vm_mac_address: mac_address::MacAddress,
|
||||
|
||||
#[clap(long, arg_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",
|
||||
@@ -140,7 +144,7 @@ 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)
|
||||
let mut proxy = Proxy::new(args.vm_fd as RawFd, args.vm_mac_address, args.vm_net_type)
|
||||
.context("failed to initialize proxy")?;
|
||||
|
||||
// Drop effective privileges to the user
|
||||
|
||||
Reference in New Issue
Block a user