23 Commits

Author SHA1 Message Date
Eric Zhang
19e7da1aad Bump version to 0.5.3 2025-04-14 17:48:02 -04:00
Eric Zhang
0128459a50 Minor API changes 2025-04-14 17:44:14 -04:00
confor
299ad61030 default --bind-tunnels to --bind-addr 2025-04-14 17:18:43 -04:00
confor
6a71c9a855 Merge branch 'ekzhang:main' into main 2025-04-14 16:57:24 -04:00
confor
dd954c98e2 rename flags to bind_addr and bind_tunnels 2025-04-14 16:46:31 -04:00
confor
53dad89514 use IpAddr type for validation and add error messages
From: https://github.com/ekzhang/bore/pull/162#discussion_r2042195219
2025-04-14 16:39:09 -04:00
狗娃子
03f2e53f39 docs: update installation instructions for Linux (#152)
* docs: update installation instructions for Linux

* Nits

* More nits

---------

Co-authored-by: Eric Zhang <ekzhang1@gmail.com>
2025-04-14 10:01:33 -04:00
confor
e137357267 Fix tests and run cargo fmt 2025-04-14 01:46:33 -04:00
confor
4bdb00c385 Document new server changes 2025-04-14 01:34:52 -04:00
confor
2a2541e866 Allow configurable tunnel IP address for server
This commit introduces a new option to specify the IP address where tunnels
will listen, which may be different from the control server's IP address.

A new flag `--tunnels-addr` can specify the IP addr to bind to. Default is set
to `0.0.0.0` which is the previous behavior.
2025-04-14 01:18:03 -04:00
confor
aa0d6e0ae5 Allow configurable control server bind address
This commit adds the ability to bind the control server to a specific network
interface via an additional flag `--control-addr`.

By default it listens on `0.0.0.0` which is the previous behaviour.
2025-04-14 00:59:38 -04:00
Stefan M.
b23beb98a2 Fix Dockerfile (#151) 2025-01-10 13:31:56 -05:00
Eric Zhang
baa42d0f7b Bump version to 0.5.2 2024-12-05 13:42:39 -05:00
Silas Alberti
da86f5bbba chore: update tracing-subscriber to 0.3.18 for NO_COLOR support (#146)
This update adds support for the NO_COLOR environment variable in tracing output,
which allows suppressing ANSI color codes in log output. This is particularly
useful when running bore as a Windows service.

Fixes #65

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2024-12-05 13:33:13 -05:00
J/A
0546092ce0 Expose local port as env value (#132)
Co-authored-by: Eric Zhang <ekzhang1@gmail.com>
2024-10-16 12:32:35 -04:00
Ricardo Araújo Paes
7fec9700c4 🔧 Adding minimum and maximum port as environment variable (#136)
* 🔧 Adding minimum and maximum port as environment variable

* 🏗️ Updating `actions/*` to v4 because nodejs version is old
2024-10-15 19:50:33 -04:00
虫子樱桃
a1e1f55a29 feat:add more target in github action flow (#120)
Co-authored-by: czyt <czyt@w.cn>
2024-06-13 09:38:59 -04:00
Eric Zhang
a6045fb1a7 Bump version to 0.5.1 (#119)
* Update dependencies

* Bump version to 0.5.1

* Try to deflake tests in GitHub Actions

* Add some retries to e2e_test

* Revert cargo.lock changes

* Update only a couple deps

* Fix CI running twice :(

* Fix typo
2024-06-10 21:50:23 -04:00
Eric Zhang
82acea3477 Fix CI runners (#118)
macos-latest has been switched to use arm64 mac instances
2024-06-10 21:04:14 -04:00
kennycallado
1f81f01fe2 arm64 docker image (#114)
* Update docker.yml

Testing aarch64 build works

* Update docker.yml

Revert event to trigger the action

* Update docker.yml

reassign proper images name
2024-06-10 20:54:40 -04:00
Eric Zhang
32a7233c9d Fix clippy lint on recent Rust versions 2023-07-27 11:26:01 -04:00
Kian-Meng Ang
3ae14209a4 Fix typo, Maxmium -> Maximum (#81)
Found via `codespell -L crate`
2023-04-29 11:08:35 -04:00
Eric Zhang
f8ccbae378 Update Homebrew installation instructions (#80)
Thanks @Moulick for making the Homebrew formula and contributing the
package to Homebrew's core tap!
2023-04-28 09:57:45 -04:00
12 changed files with 156 additions and 69 deletions

View File

@@ -1,13 +1,17 @@
name: CI name: CI
on: [push, pull_request] on:
push:
branches:
- main
pull_request:
jobs: jobs:
rust: rust:
name: Build and Test name: Build and Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
@@ -22,7 +26,7 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
@@ -36,7 +40,7 @@ jobs:
name: Clippy name: Clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Docker meta - name: Docker meta
id: meta id: meta
@@ -40,9 +40,7 @@ jobs:
id: docker_build id: docker_build
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
with: with:
# This doesn't work now because of an issue in multi-platform Docker builds. platforms: linux/amd64,linux/arm64
# -> see https://github.com/rust-lang/rust/issues/97520
# platforms: linux/amd64,linux/arm64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}

View File

@@ -1,12 +1,16 @@
name: Mean Bean CI name: Mean Bean CI
on: [push, pull_request] on:
push:
branches:
- main
pull_request:
jobs: jobs:
install-cross: install-cross:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v4
with: with:
fetch-depth: 50 fetch-depth: 50
@@ -18,7 +22,7 @@ jobs:
matches: ${{ matrix.platform }} matches: ${{ matrix.platform }}
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v4
with: with:
name: cross-${{ matrix.platform }} name: cross-${{ matrix.platform }}
path: ${{ steps.cross.outputs.install_path }} path: ${{ steps.cross.outputs.install_path }}
@@ -33,11 +37,11 @@ jobs:
matrix: matrix:
channel: [stable] channel: [stable]
target: target:
- x86_64-apple-darwin - aarch64-apple-darwin
steps: steps:
- name: Setup | Checkout - name: Setup | Checkout
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: Setup | Rust - name: Setup | Rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -57,12 +61,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: install-cross needs: install-cross
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
fetch-depth: 50 fetch-depth: 50
- name: Download Cross - name: Download Cross
uses: actions/download-artifact@v1 uses: actions/download-artifact@v4
with: with:
name: cross-linux-musl name: cross-linux-musl
path: /tmp/ path: /tmp/
@@ -85,8 +89,11 @@ jobs:
matrix: matrix:
channel: [stable] channel: [stable]
target: target:
- aarch64-unknown-linux-musl
- arm-unknown-linux-musleabi
- arm-unknown-linux-gnueabi - arm-unknown-linux-gnueabi
- armv7-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf
- armv7-unknown-linux-musleabihf
- i686-unknown-linux-musl - i686-unknown-linux-musl
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
@@ -98,7 +105,7 @@ jobs:
# artifacts are downloaded first. # artifacts are downloaded first.
needs: install-cross needs: install-cross
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
fetch-depth: 50 fetch-depth: 50
- run: ci/set_rust_version.bash ${{ matrix.channel }} ${{ matrix.target }} - run: ci/set_rust_version.bash ${{ matrix.channel }} ${{ matrix.target }}

View File

@@ -16,7 +16,7 @@ jobs:
install-cross: install-cross:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v4
with: with:
fetch-depth: 50 fetch-depth: 50
@@ -28,7 +28,7 @@ jobs:
matches: ${{ matrix.platform }} matches: ${{ matrix.platform }}
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v4
with: with:
name: cross-${{ matrix.platform }} name: cross-${{ matrix.platform }}
path: ${{ steps.cross.outputs.install_path }} path: ${{ steps.cross.outputs.install_path }}
@@ -50,7 +50,7 @@ jobs:
uses: dawidd6/action-get-tag@v1 uses: dawidd6/action-get-tag@v1
- name: Setup | Checkout - name: Setup | Checkout
uses: actions/checkout@v2 uses: actions/checkout@v4
# Cache files between builds # Cache files between builds
- name: Setup | Cache Cargo - name: Setup | Cache Cargo
@@ -102,8 +102,11 @@ jobs:
strategy: strategy:
matrix: matrix:
target: target:
- aarch64-unknown-linux-musl
- arm-unknown-linux-musleabi
- arm-unknown-linux-gnueabi - arm-unknown-linux-gnueabi
- armv7-unknown-linux-gnueabihf - armv7-unknown-linux-gnueabihf
- armv7-unknown-linux-musleabihf
- i686-unknown-linux-musl - i686-unknown-linux-musl
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
steps: steps:
@@ -111,8 +114,8 @@ jobs:
id: tag id: tag
uses: dawidd6/action-get-tag@v1 uses: dawidd6/action-get-tag@v1
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions/download-artifact@v1 - uses: actions/download-artifact@v4
with: with:
name: cross-linux-musl name: cross-linux-musl
path: /tmp/ path: /tmp/
@@ -160,7 +163,7 @@ jobs:
id: tag id: tag
uses: dawidd6/action-get-tag@v1 uses: dawidd6/action-get-tag@v1
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- run: bash ci/set_rust_version.bash stable ${{ matrix.target }} - run: bash ci/set_rust_version.bash stable ${{ matrix.target }}
- run: bash ci/build.bash cargo ${{ matrix.target }} RELEASE - run: bash ci/build.bash cargo ${{ matrix.target }} RELEASE
- run: | - run: |

40
Cargo.lock generated
View File

@@ -113,7 +113,7 @@ dependencies = [
[[package]] [[package]]
name = "bore-cli" name = "bore-cli"
version = "0.5.0" version = "0.5.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
@@ -409,18 +409,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]] [[package]]
name = "hex" name = "hex"
@@ -452,7 +443,7 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [ dependencies = [
"hermit-abi 0.3.1", "hermit-abi",
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@@ -463,7 +454,7 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [ dependencies = [
"hermit-abi 0.3.1", "hermit-abi",
"io-lifetimes", "io-lifetimes",
"rustix", "rustix",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@@ -551,11 +542,11 @@ dependencies = [
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.15.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"libc", "libc",
] ]
@@ -868,10 +859,11 @@ dependencies = [
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.38" version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9cf6a813d3f40c88b0b6b6f29a5c95c6cdbf97c1f9cc53fb820200f5ad814d" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [ dependencies = [
"cfg-if",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@@ -900,20 +892,20 @@ dependencies = [
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.3" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [ dependencies = [
"lazy_static",
"log", "log",
"once_cell",
"tracing-core", "tracing-core",
] ]
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.17" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"sharded-slab", "sharded-slab",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "bore-cli" name = "bore-cli"
version = "0.5.0" version = "0.5.3"
authors = ["Eric Zhang <ekzhang1@gmail.com>"] authors = ["Eric Zhang <ekzhang1@gmail.com>"]
license = "MIT" license = "MIT"
description = "A modern, simple TCP tunnel in Rust that exposes local ports to a remote server, bypassing standard NAT connection firewalls." description = "A modern, simple TCP tunnel in Rust that exposes local ports to a remote server, bypassing standard NAT connection firewalls."
@@ -29,7 +29,7 @@ sha2 = "0.10.2"
tokio = { version = "1.17.0", features = ["rt-multi-thread", "io-util", "macros", "net", "time"] } tokio = { version = "1.17.0", features = ["rt-multi-thread", "io-util", "macros", "net", "time"] }
tokio-util = { version = "0.7.1", features = ["codec"] } tokio-util = { version = "0.7.1", features = ["codec"] }
tracing = "0.1.32" tracing = "0.1.32"
tracing-subscriber = "0.3.10" tracing-subscriber = "0.3.18"
uuid = { version = "1.2.1", features = ["serde", "v4"] } uuid = { version = "1.2.1", features = ["serde", "v4"] }
[dev-dependencies] [dev-dependencies]

View File

@@ -1,4 +1,4 @@
FROM rust:alpine as builder FROM rust:alpine AS builder
WORKDIR /home/rust/src WORKDIR /home/rust/src
RUN apk --no-cache add musl-dev RUN apk --no-cache add musl-dev
COPY . . COPY . .

View File

@@ -23,20 +23,48 @@ Similar to [localtunnel](https://github.com/localtunnel/localtunnel) and [ngrok]
## Installation ## Installation
If you're on macOS, `bore` is packaged as a Homebrew formula. ### macOS
`bore` is packaged as a Homebrew core formula.
```shell ```shell
brew install ekzhang/bore/bore brew install bore-cli
``` ```
### Linux
#### Arch Linux
`bore` is available in the AUR as `bore`.
```shell
yay -S bore # or your favorite AUR helper
```
#### Gentoo Linux
`bore` is available in the [gentoo-zh](https://github.com/microcai/gentoo-zh) overlay.
```shell
sudo eselect repository enable gentoo-zh
sudo emerge --sync gentoo-zh
sudo emerge net-proxy/bore
```
### Binary Distribution
Otherwise, the easiest way to install bore is from prebuilt binaries. These are available on the [releases page](https://github.com/ekzhang/bore/releases) for macOS, Windows, and Linux. Just unzip the appropriate file for your platform and move the `bore` executable into a folder on your PATH. Otherwise, the easiest way to install bore is from prebuilt binaries. These are available on the [releases page](https://github.com/ekzhang/bore/releases) for macOS, Windows, and Linux. Just unzip the appropriate file for your platform and move the `bore` executable into a folder on your PATH.
### Cargo
You also can build `bore` from source using [Cargo](https://doc.rust-lang.org/cargo/), the Rust package manager. This command installs the `bore` binary at a user-accessible path. You also can build `bore` from source using [Cargo](https://doc.rust-lang.org/cargo/), the Rust package manager. This command installs the `bore` binary at a user-accessible path.
```shell ```shell
cargo install bore-cli cargo install bore-cli
``` ```
### Docker
We also publish versioned Docker images for each release. The image is built for an AMD 64-bit architecture. They're tagged with the specific version and allow you to run the statically-linked `bore` binary from a minimal "scratch" container. We also publish versioned Docker images for each release. The image is built for an AMD 64-bit architecture. They're tagged with the specific version and allow you to run the statically-linked `bore` binary from a minimal "scratch" container.
```shell ```shell
@@ -65,14 +93,14 @@ Starts a local proxy to the remote server
Usage: bore local [OPTIONS] --to <TO> <LOCAL_PORT> Usage: bore local [OPTIONS] --to <TO> <LOCAL_PORT>
Arguments: Arguments:
<LOCAL_PORT> The local port to expose <LOCAL_PORT> The local port to expose [env: BORE_LOCAL_PORT=]
Options: Options:
-l, --local-host <HOST> The local host to expose [default: localhost] -l, --local-host <HOST> The local host to expose [default: localhost]
-t, --to <TO> Address of the remote server to expose local ports to [env: BORE_SERVER=] -t, --to <TO> Address of the remote server to expose local ports to [env: BORE_SERVER=]
-p, --port <PORT> Optional port on the remote server to select [default: 0] -p, --port <PORT> Optional port on the remote server to select [default: 0]
-s, --secret <SECRET> Optional secret for authentication [env: BORE_SECRET] -s, --secret <SECRET> Optional secret for authentication [env: BORE_SECRET]
-h, --help Print help information -h, --help Print help
``` ```
### Self-Hosting ### Self-Hosting
@@ -85,6 +113,8 @@ bore server
That's all it takes! After the server starts running at a given address, you can then update the `bore local` command with option `--to <ADDRESS>` to forward a local port to this remote server. That's all it takes! After the server starts running at a given address, you can then update the `bore local` command with option `--to <ADDRESS>` to forward a local port to this remote server.
It's possible to specify different IP addresses for the control server and for the tunnels. This setup is useful for cases where you might want the control server to be on a private network while allowing tunnel connections over a public interface, or vice versa.
The full options for the `bore server` command are shown below. The full options for the `bore server` command are shown below.
```shell ```shell
@@ -93,10 +123,12 @@ Runs the remote proxy server
Usage: bore server [OPTIONS] Usage: bore server [OPTIONS]
Options: Options:
--min-port <MIN_PORT> Minimum accepted TCP port number [default: 1024] --min-port <MIN_PORT> Minimum accepted TCP port number [env: BORE_MIN_PORT=] [default: 1024]
--max-port <MAX_PORT> Maximum accepted TCP port number [default: 65535] --max-port <MAX_PORT> Maximum accepted TCP port number [env: BORE_MAX_PORT=] [default: 65535]
-s, --secret <SECRET> Optional secret for authentication [env: BORE_SECRET] -s, --secret <SECRET> Optional secret for authentication [env: BORE_SECRET]
-h, --help Print help information --bind-addr <BIND_ADDR> IP address to bind to, clients must reach this [default: 0.0.0.0]
--bind-tunnels <BIND_TUNNELS> IP address where tunnels will listen on, defaults to --bind-addr
-h, --help Print help
``` ```
## Protocol ## Protocol

View File

@@ -12,5 +12,21 @@ TARGET_TRIPLE=$2
required_arg $CROSS 'CROSS' required_arg $CROSS 'CROSS'
required_arg $TARGET_TRIPLE '<Target Triple>' required_arg $TARGET_TRIPLE '<Target Triple>'
max_attempts=3
count=0
while [ $count -lt $max_attempts ]; do
$CROSS test --target $TARGET_TRIPLE $CROSS test --target $TARGET_TRIPLE
$CROSS test --target $TARGET_TRIPLE --all-features status=$?
if [ $status -eq 0 ]; then
echo "Test passed"
break
else
echo "Test failed, attempt $(($count + 1))"
fi
count=$(($count + 1))
done
if [ $status -ne 0 ]; then
echo "Test failed after $max_attempts attempts"
fi

View File

@@ -1,3 +1,5 @@
use std::net::IpAddr;
use anyhow::Result; use anyhow::Result;
use bore_cli::{client::Client, server::Server}; use bore_cli::{client::Client, server::Server};
use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand}; use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand};
@@ -14,6 +16,7 @@ enum Command {
/// Starts a local proxy to the remote server. /// Starts a local proxy to the remote server.
Local { Local {
/// The local port to expose. /// The local port to expose.
#[clap(env = "BORE_LOCAL_PORT")]
local_port: u16, local_port: u16,
/// The local host to expose. /// The local host to expose.
@@ -36,16 +39,24 @@ enum Command {
/// Runs the remote proxy server. /// Runs the remote proxy server.
Server { Server {
/// Minimum accepted TCP port number. /// Minimum accepted TCP port number.
#[clap(long, default_value_t = 1024)] #[clap(long, default_value_t = 1024, env = "BORE_MIN_PORT")]
min_port: u16, min_port: u16,
/// Maximum accepted TCP port number. /// Maximum accepted TCP port number.
#[clap(long, default_value_t = 65535)] #[clap(long, default_value_t = 65535, env = "BORE_MAX_PORT")]
max_port: u16, max_port: u16,
/// Optional secret for authentication. /// Optional secret for authentication.
#[clap(short, long, env = "BORE_SECRET", hide_env_values = true)] #[clap(short, long, env = "BORE_SECRET", hide_env_values = true)]
secret: Option<String>, secret: Option<String>,
/// IP address to bind to, clients must reach this.
#[clap(long, default_value = "0.0.0.0")]
bind_addr: IpAddr,
/// IP address where tunnels will listen on, defaults to --bind-addr.
#[clap(long)]
bind_tunnels: Option<IpAddr>,
}, },
} }
@@ -66,6 +77,8 @@ async fn run(command: Command) -> Result<()> {
min_port, min_port,
max_port, max_port,
secret, secret,
bind_addr,
bind_tunnels,
} => { } => {
let port_range = min_port..=max_port; let port_range = min_port..=max_port;
if port_range.is_empty() { if port_range.is_empty() {
@@ -73,7 +86,10 @@ async fn run(command: Command) -> Result<()> {
.error(ErrorKind::InvalidValue, "port range is empty") .error(ErrorKind::InvalidValue, "port range is empty")
.exit(); .exit();
} }
Server::new(port_range, secret.as_deref()).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?;
} }
} }

View File

@@ -1,6 +1,7 @@
//! Server implementation for the `bore` service. //! Server implementation for the `bore` service.
use std::{io, net::SocketAddr, ops::RangeInclusive, sync::Arc, time::Duration}; use std::net::{IpAddr, Ipv4Addr};
use std::{io, ops::RangeInclusive, sync::Arc, time::Duration};
use anyhow::Result; use anyhow::Result;
use dashmap::DashMap; use dashmap::DashMap;
@@ -23,6 +24,12 @@ pub struct Server {
/// Concurrent map of IDs to incoming connections. /// Concurrent map of IDs to incoming connections.
conns: Arc<DashMap<Uuid, TcpStream>>, conns: Arc<DashMap<Uuid, TcpStream>>,
/// IP address where the control server will bind to.
bind_addr: IpAddr,
/// IP address where tunnels will listen on.
bind_tunnels: IpAddr,
} }
impl Server { impl Server {
@@ -33,15 +40,26 @@ impl Server {
port_range, port_range,
conns: Arc::new(DashMap::new()), conns: Arc::new(DashMap::new()),
auth: secret.map(Authenticator::new), auth: secret.map(Authenticator::new),
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. /// Start the server, listening for new connections.
pub async fn listen(self) -> Result<()> { pub async fn listen(self) -> Result<()> {
let this = Arc::new(self); let this = Arc::new(self);
let addr = SocketAddr::from(([0, 0, 0, 0], CONTROL_PORT)); let listener = TcpListener::bind((this.bind_addr, CONTROL_PORT)).await?;
let listener = TcpListener::bind(&addr).await?; info!(addr = ?this.bind_addr, "server listening");
info!(?addr, "server listening");
loop { loop {
let (stream, addr) = listener.accept().await?; let (stream, addr) = listener.accept().await?;
@@ -62,7 +80,7 @@ impl Server {
async fn create_listener(&self, port: u16) -> Result<TcpListener, &'static str> { async fn create_listener(&self, port: u16) -> Result<TcpListener, &'static str> {
let try_bind = |port: u16| async move { let try_bind = |port: u16| async move {
TcpListener::bind(("0.0.0.0", port)) TcpListener::bind((self.bind_tunnels, port))
.await .await
.map_err(|err| match err.kind() { .map_err(|err| match err.kind() {
io::ErrorKind::AddrInUse => "port already in use", io::ErrorKind::AddrInUse => "port already in use",
@@ -120,8 +138,9 @@ impl Server {
return Ok(()); return Ok(());
} }
}; };
let host = listener.local_addr()?.ip();
let port = listener.local_addr()?.port(); let port = listener.local_addr()?.port();
info!(?port, "new client"); info!(?host, ?port, "new client");
stream.send(ServerMessage::Hello(port)).await?; stream.send(ServerMessage::Hello(port)).await?;
loop { loop {

View File

@@ -14,7 +14,7 @@ use uuid::Uuid;
/// TCP port used for control connections with the server. /// TCP port used for control connections with the server.
pub const CONTROL_PORT: u16 = 7835; pub const CONTROL_PORT: u16 = 7835;
/// Maxmium byte length for a JSON frame in the stream. /// Maximum byte length for a JSON frame in the stream.
pub const MAX_FRAME_LENGTH: usize = 256; pub const MAX_FRAME_LENGTH: usize = 256;
/// Timeout for network connections and initial protocol messages. /// Timeout for network connections and initial protocol messages.