diff --git a/README.md b/README.md index f5cca68..1e4e3d6 100644 --- a/README.md +++ b/README.md @@ -93,14 +93,14 @@ Starts a local proxy to the remote server Usage: bore local [OPTIONS] --to Arguments: - The local port to expose + The local port to expose [env: BORE_LOCAL_PORT=] Options: -l, --local-host The local host to expose [default: localhost] -t, --to Address of the remote server to expose local ports to [env: BORE_SERVER=] -p, --port Optional port on the remote server to select [default: 0] -s, --secret Optional secret for authentication [env: BORE_SECRET] - -h, --help Print help information + -h, --help Print help ``` ### Self-Hosting @@ -126,10 +126,9 @@ Options: --min-port Minimum accepted TCP port number [env: BORE_MIN_PORT=] [default: 1024] --max-port Maximum accepted TCP port number [env: BORE_MAX_PORT=] [default: 65535] -s, --secret Optional secret for authentication [env: BORE_SECRET] - --control-addr IP address for the control server. Bore clients must reach this address [default: 0.0.0.0] - --tunnels-addr IP address where tunnels will listen on [default: 0.0.0.0] + --bind-addr IP address to bind to, clients must reach this [default: 0.0.0.0] + --bind-tunnels IP address where tunnels will listen on, defaults to --bind-addr -h, --help Print help - ``` ## Protocol diff --git a/src/main.rs b/src/main.rs index b8b4391..71429c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use std::net::IpAddr; + use anyhow::Result; use bore_cli::{client::Client, server::Server}; use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand}; @@ -49,13 +50,13 @@ enum Command { #[clap(short, long, env = "BORE_SECRET", hide_env_values = true)] secret: Option, - /// IP address to bind to. Bore clients must reach this. + /// IP address to bind to, clients must reach this. #[clap(long, default_value = "0.0.0.0")] - bind_addr: String, + bind_addr: IpAddr, - /// IP address where tunnels will listen on. Defaults to --bind-addr. + /// IP address where tunnels will listen on, defaults to --bind-addr. #[clap(long)] - bind_tunnels: Option, + bind_tunnels: Option, }, } @@ -85,24 +86,10 @@ async fn run(command: Command) -> Result<()> { .error(ErrorKind::InvalidValue, "port range is empty") .exit(); } - - let ipaddr_control = bind_addr.parse::(); - if ipaddr_control.is_err() { - Args::command() - .error(ErrorKind::InvalidValue, "invalid ip address for control server") - .exit(); - } - - let ipaddr_tunnels = bind_tunnels.unwrap_or(bind_addr).parse::(); - if ipaddr_tunnels.is_err() { - Args::command() - .error(ErrorKind::InvalidValue, "invalid ip address for tunnel connections") - .exit(); - } - - Server::new(port_range, secret.as_deref(), ipaddr_control.unwrap(), ipaddr_tunnels.unwrap()) - .listen() - .await?; + let mut server = Server::new(port_range, secret.as_deref()); + server.set_bind_addr(bind_addr); + server.set_bind_tunnels(bind_tunnels.unwrap_or(bind_addr)); + server.listen().await?; } } diff --git a/src/server.rs b/src/server.rs index 0de063c..3c38988 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,7 +1,7 @@ //! Server implementation for the `bore` service. +use std::net::{IpAddr, Ipv4Addr}; use std::{io, ops::RangeInclusive, sync::Arc, time::Duration}; -use std::net::IpAddr; use anyhow::Result; use dashmap::DashMap; @@ -25,7 +25,7 @@ pub struct Server { /// Concurrent map of IDs to incoming connections. conns: Arc>, - /// IP address where the control server will bind to. Bore clients must reach this. + /// IP address where the control server will bind to. bind_addr: IpAddr, /// IP address where tunnels will listen on. @@ -34,27 +34,32 @@ pub struct Server { impl Server { /// Create a new server with a specified minimum port number. - pub fn new( - port_range: RangeInclusive, - secret: Option<&str>, - bind_addr: IpAddr, - bind_tunnels: IpAddr, - ) -> Self { + pub fn new(port_range: RangeInclusive, secret: Option<&str>) -> Self { assert!(!port_range.is_empty(), "must provide at least one port"); Server { port_range, conns: Arc::new(DashMap::new()), auth: secret.map(Authenticator::new), - bind_addr, - bind_tunnels, + bind_addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED), + bind_tunnels: IpAddr::V4(Ipv4Addr::UNSPECIFIED), } } + /// Set the IP address where tunnels will listen on. + pub fn set_bind_addr(&mut self, bind_addr: IpAddr) { + self.bind_addr = bind_addr; + } + + /// Set the IP address where the control server will bind to. + pub fn set_bind_tunnels(&mut self, bind_tunnels: IpAddr) { + self.bind_tunnels = bind_tunnels; + } + /// Start the server, listening for new connections. pub async fn listen(self) -> Result<()> { let this = Arc::new(self); let listener = TcpListener::bind((this.bind_addr, CONTROL_PORT)).await?; - info!(addr = ?this.bind_addr, port = CONTROL_PORT, "server listening"); + info!(addr = ?this.bind_addr, "server listening"); loop { let (stream, addr) = listener.accept().await?; diff --git a/tests/e2e_test.rs b/tests/e2e_test.rs index c73d2be..50a6739 100644 --- a/tests/e2e_test.rs +++ b/tests/e2e_test.rs @@ -1,7 +1,4 @@ -#![allow(clippy::items_after_test_module)] - use std::net::SocketAddr; -use std::net::IpAddr; use std::time::Duration; use anyhow::{anyhow, Result}; @@ -20,15 +17,7 @@ lazy_static! { /// Spawn the server, giving some time for the control port TcpListener to start. async fn spawn_server(secret: Option<&str>) { - tokio::spawn( - Server::new( - 1024..=65535, - secret, - "0.0.0.0".parse::().unwrap(), - "0.0.0.0".parse::().unwrap(), - ) - .listen(), - ); + tokio::spawn(Server::new(1024..=65535, secret).listen()); time::sleep(Duration::from_millis(50)).await; } @@ -134,10 +123,5 @@ async fn very_long_frame() -> Result<()> { fn empty_port_range() { let min_port = 5000; let max_port = 3000; - let _ = Server::new( - min_port..=max_port, - None, - "0.0.0.0".parse::().unwrap(), - "0.0.0.0".parse::().unwrap(), - ); + let _ = Server::new(min_port..=max_port, None); }