Allow configurable control server bind address

This commit adds the ability to bind the control server to a specific network
interface via an additional flag `--control-addr`.

By default it listens on `0.0.0.0` which is the previous behaviour.
This commit is contained in:
confor
2025-04-14 00:59:38 -04:00
parent b23beb98a2
commit aa0d6e0ae5
2 changed files with 14 additions and 6 deletions

View File

@@ -47,6 +47,10 @@ enum Command {
/// Optional secret for authentication. /// Optional secret for authentication.
#[clap(short, long, env = "BORE_SECRET", hide_env_values = true)] #[clap(short, long, env = "BORE_SECRET", hide_env_values = true)]
secret: Option<String>, secret: Option<String>,
/// IP address for the control server. Bore clients must reach this address.
#[clap(long, default_value = "0.0.0.0")]
control_addr: String,
}, },
} }
@@ -67,6 +71,7 @@ async fn run(command: Command) -> Result<()> {
min_port, min_port,
max_port, max_port,
secret, secret,
control_addr,
} => { } => {
let port_range = min_port..=max_port; let port_range = min_port..=max_port;
if port_range.is_empty() { if port_range.is_empty() {
@@ -74,7 +79,7 @@ async fn run(command: Command) -> Result<()> {
.error(ErrorKind::InvalidValue, "port range is empty") .error(ErrorKind::InvalidValue, "port range is empty")
.exit(); .exit();
} }
Server::new(port_range, secret.as_deref()).listen().await?; Server::new(port_range, secret.as_deref(), control_addr).listen().await?;
} }
} }

View File

@@ -1,6 +1,6 @@
//! Server implementation for the `bore` service. //! Server implementation for the `bore` service.
use std::{io, net::SocketAddr, ops::RangeInclusive, sync::Arc, time::Duration}; use std::{io, ops::RangeInclusive, sync::Arc, time::Duration};
use anyhow::Result; use anyhow::Result;
use dashmap::DashMap; use dashmap::DashMap;
@@ -23,25 +23,28 @@ pub struct Server {
/// Concurrent map of IDs to incoming connections. /// Concurrent map of IDs to incoming connections.
conns: Arc<DashMap<Uuid, TcpStream>>, conns: Arc<DashMap<Uuid, TcpStream>>,
/// IP address for the control server. Bore clients must reach this address.
control_addr: String,
} }
impl Server { impl Server {
/// Create a new server with a specified minimum port number. /// Create a new server with a specified minimum port number.
pub fn new(port_range: RangeInclusive<u16>, secret: Option<&str>) -> Self { pub fn new(port_range: RangeInclusive<u16>, secret: Option<&str>, control_addr: String) -> Self {
assert!(!port_range.is_empty(), "must provide at least one port"); assert!(!port_range.is_empty(), "must provide at least one port");
Server { Server {
port_range, port_range,
conns: Arc::new(DashMap::new()), conns: Arc::new(DashMap::new()),
auth: secret.map(Authenticator::new), auth: secret.map(Authenticator::new),
control_addr: control_addr,
} }
} }
/// Start the server, listening for new connections. /// Start the server, listening for new connections.
pub async fn listen(self) -> Result<()> { pub async fn listen(self) -> Result<()> {
let this = Arc::new(self); let this = Arc::new(self);
let addr = SocketAddr::from(([0, 0, 0, 0], CONTROL_PORT)); let listener = TcpListener::bind((this.control_addr.as_ref(), CONTROL_PORT)).await?;
let listener = TcpListener::bind(&addr).await?; info!(?this.control_addr, "server listening");
info!(?addr, "server listening");
loop { loop {
let (stream, addr) = listener.accept().await?; let (stream, addr) = listener.accept().await?;