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 <ekzhang1@gmail.com>
This commit is contained in:
Antonio Mika 2022-04-11 23:45:07 -04:00 committed by GitHub
parent 634af3f6af
commit 99fc4f7ddb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 13 deletions

View File

@ -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 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. The full options are shown below.
@ -59,14 +59,15 @@ USAGE:
bore local [OPTIONS] --to <TO> <LOCAL_PORT> bore local [OPTIONS] --to <TO> <LOCAL_PORT>
ARGS: ARGS:
<LOCAL_PORT> The local port to listen on <LOCAL_PORT> The local port to expose
OPTIONS: OPTIONS:
-h, --help Print help information -h, --help Print help information
-p, --port <PORT> Optional port on the remote server to select [default: 0] -l, --local-host <HOST> The local host to expose [default: localhost]
-s, --secret <SECRET> Optional secret for authentication -p, --port <PORT> Optional port on the remote server to select [default: 0]
-t, --to <TO> Address of the remote server to expose local ports to -s, --secret <SECRET> Optional secret for authentication
-V, --version Print version information -t, --to <TO> Address of the remote server to expose local ports to
-V, --version Print version information
``` ```
### Self-Hosting ### Self-Hosting

View File

@ -21,6 +21,9 @@ pub struct Client {
/// Destination address of the server. /// Destination address of the server.
to: String, to: String,
// Local host that is forwarded.
local_host: String,
/// Local port that is forwarded. /// Local port that is forwarded.
local_port: u16, local_port: u16,
@ -33,7 +36,13 @@ pub struct Client {
impl Client { impl Client {
/// Create a new client. /// Create a new client.
pub async fn new(local_port: u16, to: &str, port: u16, secret: Option<&str>) -> Result<Self> { pub async fn new(
local_host: &str,
local_port: u16,
to: &str,
port: u16,
secret: Option<&str>,
) -> Result<Self> {
let mut stream = BufReader::new(connect_with_timeout(to, CONTROL_PORT).await?); let mut stream = BufReader::new(connect_with_timeout(to, CONTROL_PORT).await?);
let auth = secret.map(Authenticator::new); let auth = secret.map(Authenticator::new);
@ -57,6 +66,7 @@ impl Client {
Ok(Client { Ok(Client {
conn: Some(stream), conn: Some(stream),
to: to.to_string(), to: to.to_string(),
local_host: local_host.to_string(),
local_port, local_port,
remote_port, remote_port,
auth, auth,
@ -106,7 +116,7 @@ impl Client {
} }
send_json(&mut remote_conn, ClientMessage::Accept(id)).await?; 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?; proxy(local_conn, remote_conn).await?;
Ok(()) Ok(())
} }

View File

@ -14,9 +14,13 @@ struct Args {
enum Command { enum Command {
/// Starts a local proxy to the remote server. /// Starts a local proxy to the remote server.
Local { Local {
/// The local port to listen on. /// The local port to expose.
local_port: u16, 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. /// Address of the remote server to expose local ports to.
#[clap(short, long)] #[clap(short, long)]
to: String, to: String,
@ -49,12 +53,13 @@ async fn main() -> Result<()> {
let args = Args::parse(); let args = Args::parse();
match args.command { match args.command {
Command::Local { Command::Local {
local_host,
local_port, local_port,
to, to,
port, port,
secret, 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?; client.listen().await?;
} }
Command::Server { min_port, secret } => { Command::Server { min_port, secret } => {

View File

@ -24,7 +24,8 @@ async fn spawn_server(secret: Option<&str>) {
/// Spawns a client with randomly assigned ports, returning the listener and remote address. /// Spawns a client with randomly assigned ports, returning the listener and remote address.
async fn spawn_client(secret: Option<&str>) -> Result<(TcpListener, SocketAddr)> { async fn spawn_client(secret: Option<&str>) -> Result<(TcpListener, SocketAddr)> {
let listener = TcpListener::bind("localhost:0").await?; 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(); let remote_addr = ([0, 0, 0, 0], client.remote_port()).into();
tokio::spawn(client.listen()); tokio::spawn(client.listen());
Ok((listener, remote_addr)) Ok((listener, remote_addr))
@ -83,7 +84,7 @@ async fn mismatched_secret(
async fn invalid_address() -> Result<()> { async fn invalid_address() -> Result<()> {
// We don't need the serial guard for this test because it doesn't create a server. // 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<()> { 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}")), Ok(_) => Err(anyhow!("expected error for {to}, use_secret={use_secret}")),
Err(_) => Ok(()), Err(_) => Ok(()),
} }