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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# Log files
*.log
*.stderr
*.pprof

# Local benchmark outputs
benchmark/socks5_rudp/out/
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ SPP is a versatile, high-performance network proxy and traffic-forwarding tool w
* Reverse Proxy (NAT traversal / intranet penetration)
* SOCKS5 Forward Proxy (supports both TCP and UDP / UDP ASSOCIATE, with optional username/password auth)
* SOCKS5 Reverse Proxy (supports both TCP and UDP / UDP ASSOCIATE)
* HTTP/HTTPS Forward Proxy (supports CONNECT tunneling and standard HTTP, with optional Basic auth)
* HTTP/HTTPS Reverse Proxy (supports CONNECT tunneling and standard HTTP, with optional Basic auth)
* Shadowsocks SIP003 Plugin support ([spp-shadowsocks-plugin](https://github.com/esrrhs/spp-shadowsocks-plugin))
* **Protocol Multiplexing & Conversion**: Proxy traffic from one protocol (e.g. TCP) over another internal transit protocol (e.g. QUIC, KCP, RUDP, or RICMP). Multiple `-fromaddr`/`-proxyproto` pairs each get an Inputer↔Outputer pair, all sharing one logical session to the server.
* **Multi-Path Underlay**: Client can open multiple main pipes (e.g. `-proto tcp -server host:8888 -proto rudp -server host:8889`). Traffic prefers the highest-throughput path; unhealthy pipes are greyed out, probed, and re-enabled when they recover.
Expand Down Expand Up @@ -71,6 +73,13 @@ Both sides must use the **same** `-key` (auth) and `-encrypt` (wire crypto). Cho
-key 'your-auth-key' -encrypt 'your-encrypt-key'
```

* **Start HTTP/HTTPS Proxy** (open HTTP/HTTPS proxy on local port 8080, supports CONNECT tunneling and standard HTTP, with optional username/password auth):
```bash
./spp -type http_client -server www.server.com:8888 \
-fromaddr :8080 -proxyproto tcp \
-key 'your-auth-key' -encrypt 'your-encrypt-key'
```

Optional: `-name` is only a log tag (not used for auth).
Encryption off: omit `-encrypt` or set it empty. Auth (`-key`) is always required.

Expand All @@ -90,7 +99,7 @@ Encryption off: omit `-encrypt` or set it empty. Auth (`-key`) is always require

### 3. Using Configuration Files

One-shot generate a multi-path server config plus one client config per mode (forward / reverse / socks5 / reverse socks5), with shared random keys:
One-shot generate a multi-path server config plus one client config per mode (forward / reverse / socks5 / reverse socks5 / http / reverse http), with shared random keys:

```bash
./spp -genconfig
Expand All @@ -103,6 +112,8 @@ Files written:
- `config_reverse_proxy_client.json` — reverse proxy
- `config_socks5_client.json` — SOCKS5
- `config_reverse_socks5_client.json` — reverse SOCKS5
- `config_http_client.json` — HTTP/HTTPS proxy
- `config_reverse_http_client.json` — reverse HTTP/HTTPS proxy

Each client also dials **all** main channels. Then start the pair you need:

Expand Down
44 changes: 38 additions & 6 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ This document provides a comprehensive guide on configuring, running, and deploy
- [2. Reverse Proxy](#2-reverse-proxy)
- [3. SOCKS5 Forward Proxy](#3-socks5-forward-proxy)
- [4. SOCKS5 Reverse Proxy](#4-socks5-reverse-proxy)
- [5. Shadowsocks Plugin](#5-shadowsocks-plugin)
- [5. HTTP/HTTPS Forward Proxy](#5-httphttps-forward-proxy)
- [6. HTTP/HTTPS Reverse Proxy](#6-httphttps-reverse-proxy)
- [7. Shadowsocks Plugin](#7-shadowsocks-plugin)
- [Protocol Multiplexing and Conversion](#protocol-multiplexing-and-conversion)
- [Configuration File](#configuration-file)
- [Configuration File Schema](#configuration-file-schema)
Expand All @@ -32,7 +34,7 @@ This document provides a comprehensive guide on configuring, running, and deploy
SPP is designed to route and forward network traffic across diverse network environments and protocol boundaries. It supports:
- **Proxy Protocols**: TCP, UDP
- **Transit Protocols**: TCP, UDP, RUDP (Reliable UDP), RICMP (Reliable ICMP), RHTTP (Reliable HTTP), KCP, QUIC
- **Proxy Types**: Forward Proxy, Reverse Proxy, SOCKS5 Forward Proxy, SOCKS5 Reverse Proxy, Shadowsocks plugin mode
- **Proxy Types**: Forward Proxy, Reverse Proxy, SOCKS5 Forward Proxy, SOCKS5 Reverse Proxy, HTTP/HTTPS Forward Proxy, HTTP/HTTPS Reverse Proxy, Shadowsocks plugin mode

---

Expand Down Expand Up @@ -128,7 +130,35 @@ Opens a SOCKS5 proxy server on the remote SPP server's port `8080`. Both TCP (`C
./spp -name "rev_socks5" -type reverse_socks5_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp
```

### 5. Shadowsocks Plugin
### 5. HTTP/HTTPS Forward Proxy

Starts an HTTP/HTTPS proxy server on the local machine on port `8080`. Supports standard HTTP methods (`GET`, `POST`, etc.) and HTTPS tunneling (`CONNECT`).

```bash
./spp -name "http" -type http_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp
```

With optional Basic authentication (returns `407 Proxy Authentication Required` if unauthenticated):

```bash
./spp -name "http_auth" -type http_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp -username myuser -password mypass
```

### 6. HTTP/HTTPS Reverse Proxy

Opens an HTTP/HTTPS proxy server on the remote SPP server's port `8080`. Traffic sent to the remote server's HTTP proxy port is proxied through the client network.

```bash
./spp -name "rev_http" -type reverse_http_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp
```

With optional Basic authentication:

```bash
./spp -name "rev_http_auth" -type reverse_http_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp -username myuser -password mypass
```

### 7. Shadowsocks Plugin

SPP can function as a SIP003 plugin for Shadowsocks:
- [spp-shadowsocks-plugin](https://github.com/esrrhs/spp-shadowsocks-plugin)
Expand Down Expand Up @@ -191,6 +221,8 @@ Writes these files (shared random auth/encrypt keys):
| `config_reverse_proxy_client.json` | Reverse proxy |
| `config_socks5_client.json` | SOCKS5 on `:1080` |
| `config_reverse_socks5_client.json` | Reverse SOCKS5 on `:1080` |
| `config_http_client.json` | HTTP/HTTPS proxy on `:8081` |
| `config_reverse_http_client.json` | Reverse HTTP/HTTPS proxy on `:8081` |

Client configs dial the same full set of underlay addresses. Defaults: AEAD `chacha20`, compression `zstd` / threshold `128`.

Expand All @@ -203,14 +235,14 @@ Then:

```bash
./spp -config config_server.json
./spp -config config_proxy_client.json # or reverse / socks5 / reverse_socks5
./spp -config config_proxy_client.json # or reverse / socks5 / reverse_socks5 / http / reverse_http
```

### Configuration File Schema

| Field | Type | Description |
| :--- | :--- | :--- |
| `type` | string | `server`, `proxy_client`, `reverse_proxy_client`, `socks5_client`, `reverse_socks5_client` |
| `type` | string | `server`, `proxy_client`, `reverse_proxy_client`, `socks5_client`, `reverse_socks5_client`, `http_client`, `reverse_http_client` |
| `proto` | array of string | Internal transit protocols (e.g. `["tcp"]`, `["kcp"]`, `["quic"]`) |
| `proxyproto` | array of string | Proxy protocols (e.g. `["tcp"]`, `["udp"]`) |
| `listen` | array of string | Server listening addresses (e.g. `[":8888"]`) |
Expand Down Expand Up @@ -280,7 +312,7 @@ Run:
```text
Usage of spp:
-type string
Role type: server, proxy_client, reverse_proxy_client, socks5_client, reverse_socks5_client
Role type: server, proxy_client, reverse_proxy_client, socks5_client, reverse_socks5_client, http_client, reverse_http_client
-config string
Path to json configuration file
-proto value
Expand Down
12 changes: 12 additions & 0 deletions configgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ var clientModes = []struct {
{Type: "reverse_proxy_client", File: "config_reverse_proxy_client.json", Name: "reverse_proxy_client"},
{Type: "socks5_client", File: "config_socks5_client.json", Name: "socks5_client"},
{Type: "reverse_socks5_client", File: "config_reverse_socks5_client.json", Name: "reverse_socks5_client"},
{Type: "http_client", File: "config_http_client.json", Name: "http_client"},
{Type: "reverse_http_client", File: "config_reverse_http_client.json", Name: "reverse_http_client"},
}

func randomSecret() (string, error) {
Expand Down Expand Up @@ -157,6 +159,14 @@ func defaultClientConfig(clientType, key, encrypt string) (ConfigFile, error) {
cfg.Name = "reverse_socks5_client"
cfg.ProxyProto = []string{"tcp"}
cfg.FromAddr = []string{":1080"}
case "http_client":
cfg.Name = "http_client"
cfg.ProxyProto = []string{"tcp"}
cfg.FromAddr = []string{":8081"}
case "reverse_http_client":
cfg.Name = "reverse_http_client"
cfg.ProxyProto = []string{"tcp"}
cfg.FromAddr = []string{":8081"}
default:
return ConfigFile{}, fmt.Errorf("unsupported client type: %s", clientType)
}
Expand Down Expand Up @@ -230,6 +240,8 @@ func generateConfigs(outdir string, force bool) error {
fmt.Printf("start reverse proxy: ./spp -config %s\n", filepath.Join(outdir, "config_reverse_proxy_client.json"))
fmt.Printf("start socks5 proxy: ./spp -config %s\n", filepath.Join(outdir, "config_socks5_client.json"))
fmt.Printf("start reverse socks5: ./spp -config %s\n", filepath.Join(outdir, "config_reverse_socks5_client.json"))
fmt.Printf("start http proxy: ./spp -config %s\n", filepath.Join(outdir, "config_http_client.json"))
fmt.Printf("start reverse http proxy: ./spp -config %s\n", filepath.Join(outdir, "config_reverse_http_client.json"))
_ = paths
return nil
}
12 changes: 8 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func main() {
outdir := flag.String("outdir", ".", "output directory for -genconfig")
force := flag.Bool("force", false, "overwrite existing files when using -genconfig")

t := flag.String("type", "", "type: server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client")
t := flag.String("type", "", "type: server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client/http_client/reverse_http_client")
var protos protoFlags
flag.Var(&protos, "proto", "main proto type: "+fmt.Sprintf("%v", network.SupportReliableProtos()))
var proxyproto proxyprotoFlags
Expand Down Expand Up @@ -291,8 +291,10 @@ func main() {
*t != "reverse_proxy_client" &&
*t != "socks5_client" &&
*t != "reverse_socks5_client" &&
*t != "http_client" &&
*t != "reverse_http_client" &&
*t != "server" {
fmt.Println("[type] must be server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client")
fmt.Println("[type] must be server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client/http_client/reverse_http_client")
fmt.Println()
flag.Usage()
return
Expand Down Expand Up @@ -322,7 +324,9 @@ func main() {
}

if *t == "socks5_client" ||
*t == "reverse_socks5_client" {
*t == "reverse_socks5_client" ||
*t == "http_client" ||
*t == "reverse_http_client" {
if !(len(fromaddr) == len(proxyproto)) {
fmt.Println("[fromaddr] [proxyproto] len must be equal")
fmt.Println()
Expand All @@ -332,7 +336,7 @@ func main() {

for i := range proxyproto {
if len(fromaddr[i]) == 0 || len(servers) == 0 {
fmt.Println("[socks5_client] or [reverse_socks5_client] need [server] [fromaddr] [proxyproto]")
fmt.Println("[socks5_client] or [reverse_socks5_client] or [http_client] or [reverse_http_client] need [server] [fromaddr] [proxyproto]")
fmt.Println()
flag.Usage()
return
Expand Down
6 changes: 4 additions & 2 deletions proxy/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,13 +601,15 @@ func (c *Client) processSession(wg *thread.Group, sess *ServerConn) error {
func (c *Client) iniService(wg *thread.Group, serverConn *ServerConn) error {
services := c.buildLoginServices()
switch c.clienttype {
case CLIENT_TYPE_PROXY, CLIENT_TYPE_SOCKS5, CLIENT_TYPE_SS_PROXY:
case CLIENT_TYPE_PROXY, CLIENT_TYPE_SOCKS5, CLIENT_TYPE_SS_PROXY, CLIENT_TYPE_HTTP:
for i, svc := range services {
var input *Inputer
var err error
switch c.clienttype {
case CLIENT_TYPE_SOCKS5:
input, err = NewSocks5Inputer(wg, svc.Proxyproto.String(), svc.Fromaddr, c.clienttype, c.config, &serverConn.ProxyConn, i)
case CLIENT_TYPE_HTTP:
input, err = NewHttpInputer(wg, svc.Proxyproto.String(), svc.Fromaddr, c.clienttype, c.config, &serverConn.ProxyConn, i)
default:
input, err = NewInputer(wg, svc.Proxyproto.String(), svc.Fromaddr, c.clienttype, c.config, &serverConn.ProxyConn, svc.Toaddr, i)
}
Expand All @@ -618,7 +620,7 @@ func (c *Client) iniService(wg *thread.Group, serverConn *ServerConn) error {
serverConn.appendInput(input)
loggo.Info("iniService client input[%d] %s %s -> %s", i, svc.Proxyproto.String(), svc.Fromaddr, svc.Toaddr)
}
case CLIENT_TYPE_REVERSE_PROXY, CLIENT_TYPE_REVERSE_SOCKS5:
case CLIENT_TYPE_REVERSE_PROXY, CLIENT_TYPE_REVERSE_SOCKS5, CLIENT_TYPE_REVERSE_HTTP:
for i, svc := range services {
output, err := NewOutputer(wg, svc.Proxyproto.String(), c.clienttype, c.config, &serverConn.ProxyConn, i)
if err != nil {
Expand Down
Loading
Loading