From 53dad89514018243fceb1e55ca0faef01ba13a3e Mon Sep 17 00:00:00 2001 From: confor Date: Mon, 14 Apr 2025 16:36:05 -0400 Subject: [PATCH] use IpAddr type for validation and add error messages From: https://github.com/ekzhang/bore/pull/162#discussion_r2042195219 --- src/main.rs | 20 +++++++++++++++++++- src/server.rs | 16 +++++++++++----- tests/e2e_test.rs | 9 +++++---- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 56f9e1c..873cde5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use std::net::IpAddr; use anyhow::Result; use bore_cli::{client::Client, server::Server}; use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand}; @@ -84,7 +85,24 @@ async fn run(command: Command) -> Result<()> { .error(ErrorKind::InvalidValue, "port range is empty") .exit(); } - Server::new(port_range, secret.as_deref(), control_addr, tunnels_addr).listen().await?; + + let ipaddr_control = control_addr.parse::(); + if ipaddr_control.is_err() { + Args::command() + .error(ErrorKind::InvalidValue, "invalid ip address for control server") + .exit(); + } + + let ipaddr_tunnels = tunnels_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?; } } diff --git a/src/server.rs b/src/server.rs index 1c46d8f..cbce41f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,6 +1,7 @@ //! Server implementation for the `bore` service. use std::{io, ops::RangeInclusive, sync::Arc, time::Duration}; +use std::net::IpAddr; use anyhow::Result; use dashmap::DashMap; @@ -25,15 +26,20 @@ pub struct Server { conns: Arc>, /// IP address for the control server. Bore clients must reach this address. - control_addr: String, + control_addr: IpAddr, /// IP address where tunnels will listen on. - tunnels_addr: String, + tunnels_addr: IpAddr, } impl Server { /// Create a new server with a specified minimum port number. - pub fn new(port_range: RangeInclusive, secret: Option<&str>, control_addr: String, tunnels_addr: String) -> Self { + pub fn new( + port_range: RangeInclusive, + secret: Option<&str>, + control_addr: IpAddr, + tunnels_addr: IpAddr, + ) -> Self { assert!(!port_range.is_empty(), "must provide at least one port"); Server { port_range, @@ -47,7 +53,7 @@ impl Server { /// Start the server, listening for new connections. pub async fn listen(self) -> Result<()> { let this = Arc::new(self); - let listener = TcpListener::bind((this.control_addr.as_ref(), CONTROL_PORT)).await?; + let listener = TcpListener::bind((this.control_addr, CONTROL_PORT)).await?; info!(?this.control_addr, "server listening"); loop { @@ -69,7 +75,7 @@ impl Server { async fn create_listener(&self, port: u16) -> Result { let try_bind = |port: u16| async move { - TcpListener::bind((self.tunnels_addr.as_ref(), port)) + TcpListener::bind((self.tunnels_addr, port)) .await .map_err(|err| match err.kind() { io::ErrorKind::AddrInUse => "port already in use", diff --git a/tests/e2e_test.rs b/tests/e2e_test.rs index 76505b0..c73d2be 100644 --- a/tests/e2e_test.rs +++ b/tests/e2e_test.rs @@ -1,6 +1,7 @@ #![allow(clippy::items_after_test_module)] use std::net::SocketAddr; +use std::net::IpAddr; use std::time::Duration; use anyhow::{anyhow, Result}; @@ -23,8 +24,8 @@ async fn spawn_server(secret: Option<&str>) { Server::new( 1024..=65535, secret, - "0.0.0.0".to_string(), - "0.0.0.0".to_string(), + "0.0.0.0".parse::().unwrap(), + "0.0.0.0".parse::().unwrap(), ) .listen(), ); @@ -136,7 +137,7 @@ fn empty_port_range() { let _ = Server::new( min_port..=max_port, None, - "0.0.0.0".to_string(), - "0.0.0.0".to_string(), + "0.0.0.0".parse::().unwrap(), + "0.0.0.0".parse::().unwrap(), ); }