mirror of https://github.com/ekzhang/bore.git
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:
parent
634af3f6af
commit
99fc4f7ddb
15
README.md
15
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
|
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
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 } => {
|
||||||
|
|
|
@ -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(()),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue