Basic vsock proxying implementation

Currently just connecting to the host's session bus
This commit is contained in:
Val Packett 2025-07-04 21:52:14 -03:00
parent 11a682e19f
commit 14ce212e81
12 changed files with 1807 additions and 34 deletions

View file

@ -4,3 +4,12 @@ version = "0.1.0"
edition = "2024"
[dependencies]
sidebus-common = { workspace = true }
busd = "0.4.0"
clap = { version = "4.5.40", features = ["derive"] }
eyre = "0.6.12"
tokio = { version = "1.46.0", features = ["full"] }
tokio-vsock = "0.7.1"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
zbus = { version = "5.7.1", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] }

View file

@ -1,3 +1,33 @@
fn main() {
println!("Hello, world!");
mod vsock;
use clap::Parser;
use tracing::info;
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct BrokerCli {}
#[tokio::main]
async fn main() -> eyre::Result<()> {
tracing_subscriber::fmt::init();
let _cli = BrokerCli::parse();
vsock::ListenerBuilder::new(vsock::VsockAddr::new(vsock::VMADDR_CID_HOST, 4269))
.with_label("VM Bus")
.listen(async |client| {
let session_bus = zbus::connection::Builder::session()
.unwrap()
.p2p() /* i.e. "raw connection, don't send Hello" */
.build()
.await
.unwrap();
info!(guid = %session_bus.server_guid(), "connected to session bus");
let client_conn = client.build(session_bus.server_guid().into()).await?;
sidebus_common::raw::splice_conns(client_conn, session_bus).await;
Ok(())
})
.await?;
Ok(())
}

View file

@ -0,0 +1,71 @@
pub use tokio_vsock::{
VMADDR_CID_ANY, VMADDR_CID_HOST, VMADDR_CID_HYPERVISOR, VMADDR_CID_LOCAL, VsockAddr,
};
use tracing::{Instrument, debug, error, info, info_span};
pub struct ConnectionBuilder {
socket: tokio_vsock::VsockStream,
remote_addr: VsockAddr,
}
impl ConnectionBuilder {
pub fn remote_addr(&self) -> &VsockAddr {
&self.remote_addr
}
pub async fn build<'a>(self, guid: zbus::Guid<'a>) -> eyre::Result<zbus::Connection> {
zbus::connection::Builder::vsock_stream(self.socket)
.server(guid)
.unwrap()
.p2p()
.auth_mechanism(zbus::AuthMechanism::Anonymous)
.build()
.await
.map_err(|e| e.into())
}
}
pub struct ListenerBuilder {
addr: VsockAddr,
label: Option<&'static str>,
}
impl ListenerBuilder {
pub fn new(addr: VsockAddr) -> Self {
ListenerBuilder { addr, label: None }
}
pub fn with_label(self, label: &'static str) -> Self {
ListenerBuilder {
label: Some(label),
..self
}
}
#[tracing::instrument(skip(self, on_accept), fields(addr = %self.addr, label = self.label))]
pub async fn listen<F>(self, on_accept: impl Fn(ConnectionBuilder) -> F) -> eyre::Result<()>
where
F: Future<Output = eyre::Result<()>> + Send + 'static,
{
let vsock_listener = tokio_vsock::VsockListener::bind(self.addr)?;
info!("listening");
while let Ok((socket, remote_addr)) = vsock_listener.accept().await {
// TODO: add remote_addr filtering facility
info!(%remote_addr, "accepted client");
let f = on_accept(ConnectionBuilder {
socket,
remote_addr,
});
tokio::spawn(
async {
match f.await {
Ok(()) => debug!("done with client"),
Err(err) => error!(%err, "error dealing with client"),
}
}
.instrument(info_span!("serve", %remote_addr)),
);
}
Ok(())
}
}