From 99fc4f7ddb1da3988589bf3708473cf168cfff0c Mon Sep 17 00:00:00 2001 From: Antonio Mika Date: Mon, 11 Apr 2022 23:45:07 -0400 Subject: [PATCH] Add a configuration to allow forward to a different local host (#15) * Add a configuration to allow forward to a different local host * Minor documentation / formatting change Co-authored-by: Eric Zhang --- README.md | 15 ++++++++------- src/client.rs | 14 ++++++++++++-- src/main.rs | 9 +++++++-- tests/e2e_test.rs | 5 +++-- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5be61ef..5b32c37 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ You can forward a port on your local machine by using the `bore local` command. bore local 5000 --to bore.pub ``` -You can optionally pass in a `--port` option to pick a specific port on the remote to expose, although the command will fail if this port is not available. +You can optionally pass in a `--port` option to pick a specific port on the remote to expose, although the command will fail if this port is not available. Also, passing `--local-host` allows you to expose a different host on your local area network besides the loopback address `localhost`. The full options are shown below. @@ -59,14 +59,15 @@ USAGE: bore local [OPTIONS] --to ARGS: - The local port to listen on + The local port to expose OPTIONS: - -h, --help Print help information - -p, --port Optional port on the remote server to select [default: 0] - -s, --secret Optional secret for authentication - -t, --to Address of the remote server to expose local ports to - -V, --version Print version information + -h, --help Print help information + -l, --local-host The local host to expose [default: localhost] + -p, --port Optional port on the remote server to select [default: 0] + -s, --secret Optional secret for authentication + -t, --to Address of the remote server to expose local ports to + -V, --version Print version information ``` ### Self-Hosting diff --git a/src/client.rs b/src/client.rs index 4190ca7..2dde7d8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -21,6 +21,9 @@ pub struct Client { /// Destination address of the server. to: String, + // Local host that is forwarded. + local_host: String, + /// Local port that is forwarded. local_port: u16, @@ -33,7 +36,13 @@ pub struct Client { impl Client { /// Create a new client. - pub async fn new(local_port: u16, to: &str, port: u16, secret: Option<&str>) -> Result { + pub async fn new( + local_host: &str, + local_port: u16, + to: &str, + port: u16, + secret: Option<&str>, + ) -> Result { let mut stream = BufReader::new(connect_with_timeout(to, CONTROL_PORT).await?); let auth = secret.map(Authenticator::new); @@ -57,6 +66,7 @@ impl Client { Ok(Client { conn: Some(stream), to: to.to_string(), + local_host: local_host.to_string(), local_port, remote_port, auth, @@ -106,7 +116,7 @@ impl Client { } send_json(&mut remote_conn, ClientMessage::Accept(id)).await?; - let local_conn = connect_with_timeout("localhost", self.local_port).await?; + let local_conn = connect_with_timeout(&self.local_host, self.local_port).await?; proxy(local_conn, remote_conn).await?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 8021446..1007456 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,9 +14,13 @@ struct Args { enum Command { /// Starts a local proxy to the remote server. Local { - /// The local port to listen on. + /// The local port to expose. local_port: u16, + /// The local host to expose. + #[clap(short, long, value_name = "HOST", default_value = "localhost")] + local_host: String, + /// Address of the remote server to expose local ports to. #[clap(short, long)] to: String, @@ -49,12 +53,13 @@ async fn main() -> Result<()> { let args = Args::parse(); match args.command { Command::Local { + local_host, local_port, to, port, secret, } => { - let client = Client::new(local_port, &to, port, secret.as_deref()).await?; + let client = Client::new(&local_host, local_port, &to, port, secret.as_deref()).await?; client.listen().await?; } Command::Server { min_port, secret } => { diff --git a/tests/e2e_test.rs b/tests/e2e_test.rs index 50fa9d9..bbf751f 100644 --- a/tests/e2e_test.rs +++ b/tests/e2e_test.rs @@ -24,7 +24,8 @@ async fn spawn_server(secret: Option<&str>) { /// Spawns a client with randomly assigned ports, returning the listener and remote address. async fn spawn_client(secret: Option<&str>) -> Result<(TcpListener, SocketAddr)> { let listener = TcpListener::bind("localhost:0").await?; - let client = Client::new(listener.local_addr()?.port(), "localhost", 0, secret).await?; + let local_port = listener.local_addr()?.port(); + let client = Client::new("localhost", local_port, "localhost", 0, secret).await?; let remote_addr = ([0, 0, 0, 0], client.remote_port()).into(); tokio::spawn(client.listen()); Ok((listener, remote_addr)) @@ -83,7 +84,7 @@ async fn mismatched_secret( async fn invalid_address() -> Result<()> { // We don't need the serial guard for this test because it doesn't create a server. async fn check_address(to: &str, use_secret: bool) -> Result<()> { - match Client::new(5000, to, 0, use_secret.then(|| "a secret")).await { + match Client::new("localhost", 5000, to, 0, use_secret.then(|| "a secret")).await { Ok(_) => Err(anyhow!("expected error for {to}, use_secret={use_secret}")), Err(_) => Ok(()), }