mirror of
https://github.com/cirruslabs/softnet.git
synced 2026-10-01 04:21:54 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba480ff4f | ||
|
|
d7699e95a9 | ||
|
|
535e03c97f | ||
|
|
d635751948 | ||
|
|
e71b32a8dd | ||
|
|
59cd9098e0 | ||
|
|
4ab3cd7e5c |
+8
-5
@@ -23,12 +23,11 @@ task:
|
||||
SENTRY_AUTH_TOKEN: ENCRYPTED[!c16a5cf7da5f856b4bc2f21fe8cb7aa2a6c981f851c094ed4d3025fd02ea59a58a86cee8b193a69a1fc20fa217e56ac3!]
|
||||
install_rust_script:
|
||||
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
install_goreleaser_script:
|
||||
- brew install go goreleaser/tap/goreleaser-pro
|
||||
install_script:
|
||||
- brew install go goreleaser/tap/goreleaser-pro getsentry/tools/sentry-cli
|
||||
build_script:
|
||||
- cargo build --profile release-with-debug
|
||||
install_sentry_cli_script:
|
||||
- brew install getsentry/tools/sentry-cli
|
||||
release_script: goreleaser
|
||||
upload_sentry_debug_files_script:
|
||||
- cd target/release-with-debug/
|
||||
# Generate and upload symbols
|
||||
@@ -37,4 +36,8 @@ task:
|
||||
# Bundle and upload sources
|
||||
- sentry-cli debug-files bundle-sources softnet.dSYM/
|
||||
- sentry-cli debug-files upload -o $SENTRY_ORG -p $SENTRY_PROJECT softnet.src.zip
|
||||
release_script: goreleaser
|
||||
create_sentry_release_script:
|
||||
- export SENTRY_RELEASE="softnet@$CIRRUS_TAG"
|
||||
- sentry-cli releases new $SENTRY_RELEASE
|
||||
- sentry-cli releases set-commits $SENTRY_RELEASE --auto
|
||||
- sentry-cli releases finalize $SENTRY_RELEASE
|
||||
|
||||
Generated
+364
-306
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -14,7 +14,7 @@ debug = true
|
||||
[dependencies]
|
||||
smoltcp = "0.8.1"
|
||||
libc = "0.2.126"
|
||||
polling = "2.2.0"
|
||||
polling = { git = "https://github.com/smol-rs/polling.git" }
|
||||
dhcproto = "0.7.0"
|
||||
vmnet = "0.1.1"
|
||||
clap = { version = "3.1.18", features = ["derive"] }
|
||||
@@ -27,3 +27,4 @@ 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"
|
||||
|
||||
+33
-4
@@ -1,5 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use num_enum::IntoPrimitive;
|
||||
use polling::os::kqueue::PollerKqueueExt;
|
||||
use polling::PollMode;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -15,6 +17,7 @@ pub struct Poller {
|
||||
enum EventKey {
|
||||
VM,
|
||||
Host,
|
||||
Interrupt,
|
||||
}
|
||||
|
||||
impl Poller {
|
||||
@@ -34,6 +37,15 @@ impl Poller {
|
||||
self.poller
|
||||
.add(self.host_fd as RawFd, self.host_interest())?;
|
||||
|
||||
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
|
||||
self.poller
|
||||
.add_filter(
|
||||
interrupt_signal,
|
||||
EventKey::Interrupt.into(),
|
||||
PollMode::Oneshot,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -45,17 +57,34 @@ impl Poller {
|
||||
self.poller
|
||||
.modify(self.host_fd as RawFd, self.host_interest())?;
|
||||
|
||||
let interrupt_signal = polling::os::kqueue::Signal(libc::SIGINT);
|
||||
self.poller.modify_filter(
|
||||
interrupt_signal,
|
||||
EventKey::Interrupt.into(),
|
||||
PollMode::Oneshot,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> Result<(bool, bool)> {
|
||||
pub fn wait(&mut self) -> Result<(bool, bool, bool)> {
|
||||
self.poller
|
||||
.wait(&mut self.events, Some(Duration::from_millis(100)))?;
|
||||
|
||||
let vm_readable = self.events.iter().any(|ev| ev.key == EventKey::VM.into());
|
||||
let host_readable = self.events.iter().any(|ev| ev.key == EventKey::Host.into());
|
||||
let vm_readable = self
|
||||
.events
|
||||
.iter()
|
||||
.any(|ev| ev.key == Into::<usize>::into(EventKey::VM));
|
||||
let host_readable = self
|
||||
.events
|
||||
.iter()
|
||||
.any(|ev| ev.key == Into::<usize>::into(EventKey::Host));
|
||||
let interrupt = self
|
||||
.events
|
||||
.iter()
|
||||
.any(|ev| ev.key == Into::<usize>::into(EventKey::Interrupt));
|
||||
|
||||
Ok((vm_readable, host_readable))
|
||||
Ok((vm_readable, host_readable, interrupt))
|
||||
}
|
||||
|
||||
fn vm_interest(&self) -> polling::Event {
|
||||
|
||||
+18
-4
@@ -16,10 +16,24 @@ impl Proxy {
|
||||
self.snoop(frame);
|
||||
}
|
||||
|
||||
self.vm
|
||||
.write(frame.as_ref())
|
||||
.map(|_| ())
|
||||
.context("failed to write to the VM")
|
||||
match self.vm.write(frame.as_ref()) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if let Some(libc::ENOBUFS) = err.raw_os_error() {
|
||||
if !self.enobufs_encountered {
|
||||
sentry::capture_message(
|
||||
"No buffer space available in VM's socket",
|
||||
sentry::Level::Warning,
|
||||
);
|
||||
self.enobufs_encountered = true;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(err).context("failed to write to the VM")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn allowed_from_host(&mut self, frame: &EthernetFrame<&[u8]>) -> Option<()> {
|
||||
|
||||
+8
-1
@@ -18,6 +18,7 @@ pub struct Proxy {
|
||||
poller: Poller,
|
||||
vm_mac_address: smoltcp::wire::EthernetAddress,
|
||||
dhcp_snooper: DhcpSnooper,
|
||||
enobufs_encountered: bool,
|
||||
}
|
||||
|
||||
impl Proxy {
|
||||
@@ -32,6 +33,7 @@ impl Proxy {
|
||||
poller,
|
||||
vm_mac_address: smoltcp::wire::EthernetAddress(vm_mac_address.bytes()),
|
||||
dhcp_snooper: Default::default(),
|
||||
enobufs_encountered: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,7 +43,7 @@ impl Proxy {
|
||||
self.poller.arm()?;
|
||||
|
||||
loop {
|
||||
let (vm_readable, host_readable) = self.poller.wait()?;
|
||||
let (vm_readable, host_readable, interrupt) = self.poller.wait()?;
|
||||
|
||||
if vm_readable {
|
||||
self.read_from_vm(buf.as_mut_slice())?;
|
||||
@@ -51,6 +53,11 @@ impl Proxy {
|
||||
self.read_from_host(buf.as_mut_slice())?;
|
||||
}
|
||||
|
||||
// Graceful termination
|
||||
if interrupt {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.poller.rearm()?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
nightly
|
||||
+12
-1
@@ -1,7 +1,9 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use clap::Parser;
|
||||
use nix::sys::signal::{signal, SigHandler, Signal};
|
||||
use privdrop::PrivDrop;
|
||||
use softnet::proxy::Proxy;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::os::raw::c_int;
|
||||
use std::os::unix::io::RawFd;
|
||||
@@ -54,13 +56,14 @@ fn main() -> ExitCode {
|
||||
|
||||
// Initialize Sentry
|
||||
let _sentry = sentry::init(sentry::ClientOptions {
|
||||
release: option_env!("CIRRUS_TAG").map(|tag| Cow::from(format!("softnet@{tag}"))),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Enrich future events with Cirrus CI-specific tags
|
||||
if let Ok(tags) = env::var("CIRRUS_SENTRY_TAGS") {
|
||||
sentry::configure_scope(|scope| {
|
||||
for (key, value) in tags.split(",").map(|tag| tag.split_once("=")).flatten() {
|
||||
for (key, value) in tags.split(',').filter_map(|tag| tag.split_once('=')) {
|
||||
scope.set_tag(key, value);
|
||||
}
|
||||
});
|
||||
@@ -82,6 +85,14 @@ fn main() -> ExitCode {
|
||||
}
|
||||
|
||||
fn try_main() -> anyhow::Result<()> {
|
||||
// The default signal(3)[1] action for SIGINT is to interrupt program,
|
||||
// but we want to handle SIGINT ourselves, so we ignore it. The kqueue(2)'s[2]
|
||||
// EVFILT_SIGNAL will receive it anyways, because it has lower precedence.
|
||||
//
|
||||
// [1]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/signal.3.html
|
||||
// [2]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
|
||||
unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }?;
|
||||
|
||||
let args: Args = Args::parse();
|
||||
|
||||
// No need to run anything, just return
|
||||
|
||||
Reference in New Issue
Block a user