Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ This produces an executable named `spore` in the project directory.
## Quickstart
### Server (choose a public range)
```bash
./spore server --min-port 20000 --max-port 21000 --bind-addr 0.0.0.0
./spore server --min-port 20000 --max-port 21000 --bind-addr 0.0.0.0 [--control-port 7835]
```

### Client (forward local 3000; let server assign a port)
```bash
./spore local --local-host 127.0.0.1 --local-port 3000 --to <SERVER_HOST> --port 0
./spore local --local-host 127.0.0.1 --local-port 3000 --to <SERVER_HOST> --port 0 [--control-port 7835]
```
Spore prints the assigned public port (for example, `listening at <SERVER_HOST>:20345`).

Expand All @@ -34,11 +34,11 @@ python3 -m http.server 25565
```
Terminal B (server):
```bash
./spore server --min-port 20000 --max-port 21000 --bind-addr 127.0.0.1
./spore server --min-port 20000 --max-port 21000 --bind-addr 127.0.0.1 [--control-port 7835]
```
Terminal C (client):
```bash
./spore local --local-host 127.0.0.1 --local-port 25565 --to 127.0.0.1 --port 0
./spore local --local-host 127.0.0.1 --local-port 25565 --to 127.0.0.1 --port 0 [--control-port 7835]
```
Terminal D (access through tunnel):
```bash
Expand All @@ -48,8 +48,8 @@ curl -v 127.0.0.1:<ASSIGNED_PORT>/
## Authentication (optional)
Provide the same secret on both sides to restrict access:
```bash
./spore server --secret SECRET
./spore local --local-port 3000 --to <SERVER_HOST> --secret SECRET
./spore server --secret SECRET [--control-port 7835]
./spore local --local-port 3000 --to <SERVER_HOST> --secret SECRET [--control-port 7835]
```

## Interoperability
Expand All @@ -60,9 +60,9 @@ Spore is designed to speak the same control protocol as Bore. You can mix Rust B
- Pending inbound connections are stored for up to 10 seconds; if the client does not accept within that window, they are dropped.

## Troubleshooting
- "address in use" starting server: another process is listening on TCP 7835. Stop it or choose a different control port (not yet configurable in Spore).
- Client exits with `:eof`: ensure server is reachable at `--to`, secrets match (or are omitted on both), and TCP 7835 is open.
- Repeated "removed stale connection": ensure the client is running and that a remote connection arrives soon after the client starts (Spore holds pending connections for 10s).
- "address in use" starting server: another process is listening on the control port. Use `--control-port` to choose a different one or stop the existing process.
- Client exits with `:eof`: ensure server is reachable at `--to`, secrets match (or are omitted on both), and the control port is open.
- Repeated "removed stale connection": ensure the client is running and a remote connection arrives soon after the client starts (Spore holds pending connections for 10s).

## License
MIT, following the upstream project.
Expand Down
9 changes: 9 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import Config

config :logger, level: :info

# Allow overriding the control port via env var SPORE_CONTROL_PORT
spore_control_port =
case System.get_env("SPORE_CONTROL_PORT") do
nil -> 7835
str -> String.to_integer(str)
end

config :spore, control_port: spore_control_port
16 changes: 12 additions & 4 deletions lib/spore/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ defmodule Spore.CLI do
local_host: :string,
to: :string,
port: :integer,
secret: :string
secret: :string,
control_port: :integer
],
aliases: [p: :port]
)
Expand All @@ -30,6 +31,9 @@ defmodule Spore.CLI do
to = Keyword.fetch!(opts, :to)
port = Keyword.get(opts, :port, 0)
secret = Keyword.get(opts, :secret, nil)
control_port = Keyword.get(opts, :control_port, nil)

if control_port, do: Application.put_env(:spore, :control_port, control_port)

case Spore.Client.new(local_host, local_port, to, port, secret) do
{:ok, client} ->
Expand All @@ -51,7 +55,8 @@ defmodule Spore.CLI do
max_port: :integer,
secret: :string,
bind_addr: :string,
bind_tunnels: :string
bind_tunnels: :string,
control_port: :integer
]
)

Expand All @@ -60,6 +65,9 @@ defmodule Spore.CLI do
secret = Keyword.get(opts, :secret, nil)
bind_addr = Keyword.get(opts, :bind_addr, "0.0.0.0")
bind_tunnels = Keyword.get(opts, :bind_tunnels, nil)
control_port = Keyword.get(opts, :control_port, nil)

if control_port, do: Application.put_env(:spore, :control_port, control_port)

case Spore.Server.listen(
min_port: min_port,
Expand All @@ -76,8 +84,8 @@ defmodule Spore.CLI do
defp usage(io) do
IO.puts(io, """
Usage:
spore local --local-port <PORT> --to <HOST> [--local-host HOST] [--port PORT] [--secret SECRET]
spore server [--min-port N] [--max-port N] [--secret SECRET] [--bind-addr IP] [--bind-tunnels IP]
spore local --local-port <PORT> --to <HOST> [--local-host HOST] [--port PORT] [--secret SECRET] [--control-port N]
spore server [--min-port N] [--max-port N] [--secret SECRET] [--bind-addr IP] [--bind-tunnels IP] [--control-port N]
""")
end
end
6 changes: 4 additions & 2 deletions lib/spore/shared.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ defmodule Spore.Shared do
@max_frame_length 256
@network_timeout_ms 3_000

@doc "TCP port used for control connections with the server."
def control_port, do: @control_port
@doc "TCP port used for control connections with the server. Can be overridden via Application env :spore, :control_port."
def control_port do
Application.get_env(:spore, :control_port, @control_port)
end

@doc "Default timeout for initial network operations (ms)."
def network_timeout_ms, do: @network_timeout_ms
Expand Down