diff --git a/README.md b/README.md index 98d673ad..9271bdd4 100755 --- a/README.md +++ b/README.md @@ -24,22 +24,23 @@ A lightweight, easy-to-use, and [performant](docs/benchmark_result.md) reverse p - [Use JSON Schema in VSCode](#use-json-schema-in-vscode) - [Config File](#config-file) - [Provider File](#provider-file) - - [Known issues](#known-issues) + - [Showcase](#showcase) + - [idlesleeper](#idlesleeper) - [Build it yourself](#build-it-yourself) ## Key Points -- Easy to use - - Effortless configuration - - Error messages is clear and detailed, easy troubleshooting -- Auto certificate obtaining and renewal (See [Supported DNS Challenge Providers](docs/dns_providers.md)) -- Auto configuration for docker containers -- Auto hot-reload on container state / config file changes -- Stop containers on idle, wake it up on traffic _(optional)_ -- HTTP(s) reserve proxy -- TCP and UDP port forwarding -- Web UI for configuration and monitoring (See [screenshots](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots)) -- Written in **[Go](https://go.dev)** +- Easy to use + - Effortless configuration + - Error messages is clear and detailed, easy troubleshooting +- Auto certificate obtaining and renewal (See [Supported DNS Challenge Providers](docs/dns_providers.md)) +- Auto configuration for docker containers +- Auto hot-reload on container state / config file changes +- Stop containers on idle, wake it up on traffic _(optional, see [showcase](#idlesleeper))_ +- HTTP(s) reserve proxy +- TCP and UDP port forwarding +- Web UI for configuration and monitoring (See [screenshots](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots)) +- Written in **[Go](https://go.dev)** [🔼Back to top](#table-of-content) @@ -49,16 +50,16 @@ A lightweight, easy-to-use, and [performant](docs/benchmark_result.md) reverse p 1. Setup DNS Records, e.g. - - A Record: `*.y.z` -> `10.0.10.1` - - AAAA Record: `*.y.z` -> `::ffff:a00:a01` + - A Record: `*.y.z` -> `10.0.10.1` + - AAAA Record: `*.y.z` -> `::ffff:a00:a01` 2. Setup `go-proxy` [See here](docs/docker.md) 3. Setup `docker-socket-proxy` (see [example](docs/docker_socket_proxy.md) other machine that is running docker (if any) 4. Configure `go-proxy` - - with text editor (e.g. Visual Studio Code) - - or with web config editor via `http://gp.y.z` + - with text editor (e.g. Visual Studio Code) + - or with web config editor via `http://gp.y.z` [🔼Back to top](#table-of-content) @@ -97,21 +98,21 @@ See [config.example.yml](config.example.yml) for more ```yaml # autocert configuration autocert: - email: # ACME Email - domains: # a list of domains for cert registration - provider: # DNS Challenge provider - options: # provider specific options - - ... + email: # ACME Email + domains: # a list of domains for cert registration + provider: # DNS Challenge provider + options: # provider specific options + - ... # reverse proxy providers configuration providers: - include: - - providers.yml - - other_file_1.yml - - ... - docker: - local: $DOCKER_HOST - remote-1: tcp://10.0.2.1:2375 - remote-2: ssh://root:1234@10.0.2.2 + include: + - providers.yml + - other_file_1.yml + - ... + docker: + local: $DOCKER_HOST + remote-1: tcp://10.0.2.1:2375 + remote-2: ssh://root:1234@10.0.2.2 ``` [🔼Back to top](#table-of-content) @@ -124,9 +125,11 @@ See [providers.example.yml](providers.example.yml) for examples [🔼Back to top](#table-of-content) -## Known issues +## Showcase -- `autocert` config is not hot-reloadable +### idlesleeper + +![idlesleeper](showcase/idlesleeper.webp) [🔼Back to top](#table-of-content) diff --git a/README_CHT.md b/README_CHT.md index cb50f1ad..32affdc9 100644 --- a/README_CHT.md +++ b/README_CHT.md @@ -22,22 +22,23 @@ - [VSCode 中使用 JSON Schema](#vscode-中使用-json-schema) - [配置文件](#配置文件) - [透過文件配置](#透過文件配置) - - [已知問題](#已知問題) + - [展示](#展示) + - [idlesleeper](#idlesleeper) - [源碼編譯](#源碼編譯) ## 重點 -- 易用 - - 不需花費太多時間就能輕鬆配置 - - 除錯簡單 -- 自動處理 HTTPS 證書(參見[可用的 DNS 供應商](docs/dns_providers.md)) -- 透過 Docker 容器自動配置 -- 容器狀態變更時自動熱重載 -- 容器閒置時自動暫停/停止,入站時自動喚醒 -- HTTP(s)反向代理 -- TCP/UDP 端口轉發 -- 用於配置和監控的前端 Web 面板([截圖](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots)) -- 使用 **[Go](https://go.dev)** 編寫 +- 易用 + - 不需花費太多時間就能輕鬆配置 + - 除錯簡單 +- 自動處理 HTTPS 證書(參見[可用的 DNS 供應商](docs/dns_providers.md)) +- 透過 Docker 容器自動配置 +- 容器狀態變更時自動熱重載 +- 容器閒置時自動暫停/停止,入站時自動喚醒 +- HTTP(s)反向代理 +- TCP/UDP 端口轉發 +- 用於配置和監控的前端 Web 面板([截圖](https://github.com/yusing/go-proxy-frontend?tab=readme-ov-file#screenshots)) +- 使用 **[Go](https://go.dev)** 編寫 [🔼 返回頂部](#目錄) @@ -47,14 +48,14 @@ 1. 設置 DNS 記錄,例如: - - A 記錄: `*.y.z` -> `10.0.10.1` - - AAAA 記錄: `*.y.z` -> `::ffff:a00:a01` + - A 記錄: `*.y.z` -> `10.0.10.1` + - AAAA 記錄: `*.y.z` -> `::ffff:a00:a01` 2. 安裝 `go-proxy` [參見這裡](docs/docker.md) 3. 配置 `go-proxy` - - 使用文本編輯器 (推薦 Visual Studio Code [參見 VSCode 使用 schema](#vscode-中使用-json-schema)) - - 或通過 `http://gp.y.z` 使用網頁配置編輯器 + - 使用文本編輯器 (推薦 Visual Studio Code [參見 VSCode 使用 schema](#vscode-中使用-json-schema)) + - 或通過 `http://gp.y.z` 使用網頁配置編輯器 [🔼 返回頂部](#目錄) @@ -93,21 +94,21 @@ ```yaml # autocert 配置 autocert: - email: # ACME 電子郵件 - domains: # 域名列表 - provider: # DNS 供應商 - options: # 供應商個別配置 - - ... + email: # ACME 電子郵件 + domains: # 域名列表 + provider: # DNS 供應商 + options: # 供應商個別配置 + - ... # 配置文件 / docker providers: - include: - - providers.yml - - other_file_1.yml - - ... - docker: - local: $DOCKER_HOST - remote-1: tcp://10.0.2.1:2375 - remote-2: ssh://root:1234@10.0.2.2 + include: + - providers.yml + - other_file_1.yml + - ... + docker: + local: $DOCKER_HOST + remote-1: tcp://10.0.2.1:2375 + remote-2: ssh://root:1234@10.0.2.2 ``` [🔼 返回頂部](#目錄) @@ -120,9 +121,11 @@ providers: [🔼 返回頂部](#目錄) -## 已知問題 +## 展示 -- `autocert` 配置不能熱重載 +### idlesleeper + +![idlesleeper](showcase/idlesleeper.webp) [🔼 返回頂部](#目錄) diff --git a/docs/docker.md b/docs/docker.md index 07334fea..2c1aa06a 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -20,9 +20,9 @@ 1. Install `wget` if not already - - Ubuntu based: `sudo apt install -y wget` - - Fedora based: `sudo yum install -y wget` - - Arch based: `sudo pacman -Sy wget` + - Ubuntu based: `sudo apt install -y wget` + - Fedora based: `sudo yum install -y wget` + - Arch based: `sudo pacman -Sy wget` 2. Run setup script @@ -57,20 +57,20 @@ ```yaml autocert: - email: john.doe@x.y.z # ACME Email - domains: # a list of domains for cert registration - - x.y.z - provider: cloudflare - options: - - auth_token: c1234565789-abcdefghijklmnopqrst # your zone API token + email: john.doe@x.y.z # ACME Email + domains: # a list of domains for cert registration + - x.y.z + provider: cloudflare + options: + - auth_token: c1234565789-abcdefghijklmnopqrst # your zone API token ``` To use **existing certificate**, set path for cert and key in `config.yml`, e.g. ```yaml autocert: - cert_path: /app/certs/cert.crt - key_path: /app/certs/priv.key + cert_path: /app/certs/cert.crt + key_path: /app/certs/priv.key ``` 5. Modify `compose.yml` to fit your needs @@ -85,31 +85,31 @@ ### Syntax -| Label | Description | Default | Accepted values | -| ------------------------ | --------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------- | -| `proxy.aliases` | comma separated aliases for subdomain and label matching | `container_name` | any | -| `proxy.exclude` | to be excluded from `go-proxy` | false | boolean | -| `proxy.idle_timeout` | time for idle (no traffic) before put it into sleep **(http/s only)** | empty **(disabled)** | `number[unit]...`, e.g. `1m30s` | -| `proxy.wake_timeout` | time to wait for container to start before responding a loading page | empty | `number[unit]...` | -| `proxy.stop_method` | method to stop after `idle_timeout` | `stop` | `stop`, `pause`, `kill` | -| `proxy.stop_timeout` | time to wait for stop command | `10s` | `number[unit]...` | -| `proxy.stop_signal` | signal sent to container for `stop` and `kill` methods | docker's default | `SIGINT`, `SIGTERM`, `SIGHUP`, `SIGQUIT` and those without **SIG** prefix | -| `proxy..` | set field for specific alias | N/A | N/A | -| `proxy.$.` | set field for specific alias at index (starting from **1**) | N/A | N/A | -| `proxy.*.` | set field for all aliases | N/A | N/A | +| Label | Description | Example | Default | Accepted values | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --------------------------- | ------------------------------------------------------------------------- | +| `proxy.aliases` | comma separated aliases for subdomain and label matching | `gitlab,gitlab-reg,gitlab-ssh` | `container_name` | any | +| `proxy.exclude` | to be excluded from `go-proxy` | | false | boolean | +| `proxy.idle_timeout` | time for idle (no traffic) before put it into sleep **(http/s only)**
_**NOTE: idlewatcher will only be enabled containers that has non-empty `idle_timeout`**_ | `1h` | empty or `0` **(disabled)** | `number[unit]...`, e.g. `1m30s` | +| `proxy.wake_timeout` | time to wait for target site to be ready | | `10s` | `number[unit]...` | +| `proxy.stop_method` | method to stop after `idle_timeout` | | `stop` | `stop`, `pause`, `kill` | +| `proxy.stop_timeout` | time to wait for stop command | | `10s` | `number[unit]...` | +| `proxy.stop_signal` | signal sent to container for `stop` and `kill` methods | | docker's default | `SIGINT`, `SIGTERM`, `SIGHUP`, `SIGQUIT` and those without **SIG** prefix | +| `proxy..` | set field for specific alias | `proxy.gitlab-ssh.scheme` | N/A | N/A | +| `proxy.$.` | set field for specific alias at index (starting from **1**) | `proxy.$3.port` | N/A | N/A | +| `proxy.*.` | set field for all aliases | `proxy.*.set_headers` | N/A | N/A | ### Fields -| Field | Description | Default | Allowed Values / Syntax | -| --------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `scheme` | proxy protocol |
  • `http` for numeric port
  • `tcp` for `x:y` port
| `http`, `https`, `tcp`, `udp` | -| `host` | proxy host |
  • Docker: docker client IP / hostname
  • File: `localhost`
| IP address, hostname | -| `port` | proxy port **(http/s)** | first port in `ports:` | number in range of `1 - 65535` | -| `port` **(required)** | proxy port **(tcp/udp)** | N/A | `x:y`
  • x: port for `go-proxy` to listen on
  • y: port or [_service name_](../src/common/constants.go#L55) of target container
| -| `no_tls_verify` | whether skip tls verify **(https only)** | `false` | boolean | -| `path_patterns` | proxy path patterns **(http/s only)**
only requests that matched a pattern will be proxied | empty **(proxy all requests)** | yaml style list[1](#list-example) of path patterns ([syntax](https://pkg.go.dev/net/http#hdr-Patterns-ServeMux)) | -| `set_headers` | header to set **(http/s only)** | empty | yaml style key-value mapping[2](#key-value-mapping-example) of header-value pairs | -| `hide_headers` | header to hide **(http/s only)** | empty | yaml style list[1](#list-example) of headers | +| Field | Description | Default | Allowed Values / Syntax | +| --------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `scheme` | proxy protocol |
  • `http` for numeric port
  • `tcp` for `x:y` port
| `http`, `https`, `tcp`, `udp` | +| `host` | proxy host |
  • Docker: docker client IP / hostname
  • File: `localhost`
| IP address, hostname | +| `port` | proxy port **(http/s)** | first port returned from docker | number in range of `1 - 65535` | +| `port` **(required)** | proxy port **(tcp/udp)** | N/A | `x:y`
  • **x**: port for `go-proxy` to listen on.
    **x** can be 0, which means listen on a random port
  • **y**: port or [_service name_](../src/common/constants.go#L55) of target container
| +| `no_tls_verify` | whether skip tls verify **(https only)** | `false` | boolean | +| `path_patterns` | proxy path patterns **(http/s only)**
only requests that matched a pattern will be proxied | empty **(proxy all requests)** | yaml style list[1](#list-example) of ([path patterns](https://pkg.go.dev/net/http#hdr-Patterns-ServeMux)) | +| `set_headers` | header to set **(http/s only)** | empty | yaml style key-value mapping[2](#key-value-mapping-example) of header-value pairs | +| `hide_headers` | header to hide **(http/s only)** | empty | yaml style list[1](#list-example) of headers | [🔼Back to top](#table-of-content) @@ -134,11 +134,11 @@ File Provider ```yaml service_a: - host: service_a.internal - set_headers: - # do not duplicate header keys, as it is not allowed in YAML - X-Custom-Header1: value1, value2 - X-Custom-Header2: value3 + host: service_a.internal + set_headers: + # do not duplicate header keys, as it is not allowed in YAML + X-Custom-Header1: value1, value2 + X-Custom-Header2: value3 ``` [🔼Back to top](#table-of-content) @@ -164,52 +164,52 @@ File Provider ```yaml service_a: - host: service_a.internal - path_patterns: - - GET / - - POST /auth - hide_headers: - - X-Custom-Header1 - - X-Custom-Header2 + host: service_a.internal + path_patterns: + - GET / + - POST /auth + hide_headers: + - X-Custom-Header1 + - X-Custom-Header2 ``` [🔼Back to top](#table-of-content) ## Troubleshooting -- Container not showing up in proxies list +- Container not showing up in proxies list - Please check that either `ports` or label `proxy..port` is declared, e.g. + Please check that either `ports` or label `proxy..port` is declared, e.g. - ```yaml - services: - nginx-1: # Option 1 - ... - ports: - - 80 - nginx-2: # Option 2 - ... - container_name: nginx-2 - network_mode: host - labels: - proxy.nginx-2.port: 80 - ``` + ```yaml + services: + nginx-1: # Option 1 + ... + ports: + - 80 + nginx-2: # Option 2 + ... + container_name: nginx-2 + network_mode: host + labels: + proxy.nginx-2.port: 80 + ``` -- Firewall issues +- Firewall issues - If you are using `ufw` with vpn that drop all inbound traffic except vpn, run below: + If you are using `ufw` with vpn that drop all inbound traffic except vpn, run below: - `sudo ufw allow from 172.16.0.0/16 to 100.64.0.0/10` + `sudo ufw allow from 172.16.0.0/16 to 100.64.0.0/10` - Explaination: + Explaination: - Docker network is usually `172.16.0.0/16` + Docker network is usually `172.16.0.0/16` - Tailscale is used as an example, `100.64.0.0/10` will be the CIDR + Tailscale is used as an example, `100.64.0.0/10` will be the CIDR - You can also list CIDRs of all docker bridge networks by: + You can also list CIDRs of all docker bridge networks by: - `docker network inspect $(docker network ls | awk '$3 == "bridge" { print $1}') | jq -r '.[] | .Name + " " + .IPAM.Config[0].Subnet' -` + `docker network inspect $(docker network ls | awk '$3 == "bridge" { print $1}') | jq -r '.[] | .Name + " " + .IPAM.Config[0].Subnet' -` [🔼Back to top](#table-of-content) @@ -219,97 +219,97 @@ More examples in [here](examples/) ```yaml volumes: - adg-work: - adg-conf: - mc-data: - palworld: - nginx: + adg-work: + adg-conf: + mc-data: + palworld: + nginx: services: - adg: - image: adguard/adguardhome - restart: unless-stopped - labels: - - proxy.aliases=adg,adg-dns,adg-setup - - proxy.$1.port=80 - - proxy.$2.scheme=udp - - proxy.$2.port=20000:dns - - proxy.$3.port=3000 - volumes: - - adg-work:/opt/adguardhome/work - - adg-conf:/opt/adguardhome/conf - ports: - - 80 - - 3000 - - 53/udp - mc: - image: itzg/minecraft-server - tty: true - stdin_open: true - container_name: mc - restart: unless-stopped - ports: - - 25565 - labels: - - proxy.mc.port=20001:25565 - environment: - - EULA=TRUE - volumes: - - mc-data:/data - palworld: - image: thijsvanloef/palworld-server-docker:latest - restart: unless-stopped - container_name: pal - stop_grace_period: 30s - ports: - - 8211/udp - - 27015/udp - labels: - - proxy.aliases=pal1,pal2 - - proxy.*.scheme=udp - - proxy.$1.port=20002:8211 - - proxy.$2.port=20003:27015 - environment: ... - volumes: - - palworld:/palworld - nginx: - image: nginx - container_name: nginx - volumes: - - nginx:/usr/share/nginx/html - ports: - - 80 - labels: - proxy.idle_timeout: 1m - go-proxy: - image: ghcr.io/yusing/go-proxy:latest - container_name: go-proxy - restart: always - network_mode: host - volumes: - - ./config:/app/config - - /var/run/docker.sock:/var/run/docker.sock - go-proxy-frontend: - image: ghcr.io/yusing/go-proxy-frontend:latest - container_name: go-proxy-frontend - restart: unless-stopped - network_mode: host - labels: - - proxy.aliases=gp - - proxy.gp.port=3000 - depends_on: - - go-proxy + adg: + image: adguard/adguardhome + restart: unless-stopped + labels: + - proxy.aliases=adg,adg-dns,adg-setup + - proxy.$1.port=80 + - proxy.$2.scheme=udp + - proxy.$2.port=20000:dns + - proxy.$3.port=3000 + volumes: + - adg-work:/opt/adguardhome/work + - adg-conf:/opt/adguardhome/conf + ports: + - 80 + - 3000 + - 53/udp + mc: + image: itzg/minecraft-server + tty: true + stdin_open: true + container_name: mc + restart: unless-stopped + ports: + - 25565 + labels: + - proxy.mc.port=20001:25565 + environment: + - EULA=TRUE + volumes: + - mc-data:/data + palworld: + image: thijsvanloef/palworld-server-docker:latest + restart: unless-stopped + container_name: pal + stop_grace_period: 30s + ports: + - 8211/udp + - 27015/udp + labels: + - proxy.aliases=pal1,pal2 + - proxy.*.scheme=udp + - proxy.$1.port=20002:8211 + - proxy.$2.port=20003:27015 + environment: ... + volumes: + - palworld:/palworld + nginx: + image: nginx + container_name: nginx + volumes: + - nginx:/usr/share/nginx/html + ports: + - 80 + labels: + proxy.idle_timeout: 1m + go-proxy: + image: ghcr.io/yusing/go-proxy:latest + container_name: go-proxy + restart: always + network_mode: host + volumes: + - ./config:/app/config + - /var/run/docker.sock:/var/run/docker.sock + go-proxy-frontend: + image: ghcr.io/yusing/go-proxy-frontend:latest + container_name: go-proxy-frontend + restart: unless-stopped + network_mode: host + labels: + - proxy.aliases=gp + - proxy.gp.port=3000 + depends_on: + - go-proxy ``` [🔼Back to top](#table-of-content) ### Services URLs for above examples -- `gp.yourdomain.com`: go-proxy web panel -- `adg-setup.yourdomain.com`: adguard setup (first time setup) -- `adg.yourdomain.com`: adguard dashboard -- `nginx.yourdomain.com`: nginx -- `yourdomain.com:2000`: adguard dns (udp) -- `yourdomain.com:20001`: minecraft server -- `yourdomain.com:20002`: palworld server +- `gp.yourdomain.com`: go-proxy web panel +- `adg-setup.yourdomain.com`: adguard setup (first time setup) +- `adg.yourdomain.com`: adguard dashboard +- `nginx.yourdomain.com`: nginx +- `yourdomain.com:2000`: adguard dns (udp) +- `yourdomain.com:20001`: minecraft server +- `yourdomain.com:20002`: palworld server [🔼Back to top](#table-of-content) diff --git a/providers.example.yml b/providers.example.yml index daaec919..e3d22b91 100644 --- a/providers.example.yml +++ b/providers.example.yml @@ -1,22 +1,22 @@ example: # matching `app.y.z` - scheme: https - host: 10.0.0.1 - port: 80 - path_patterns: # Check https://pkg.go.dev/net/http#hdr-Patterns-ServeMux for syntax - - GET / # accept any GET request - - POST /auth # for /auth and /auth/* accept only POST - - GET /home/{$} - - /b/{bucket}/o/{any} - no_tls_verify: false - set_headers: - HEADER_A: VALUE_A, VALUE_B - HEADER_B: VALUE_C - hide_headers: - - HEADER_C - - HEADER_D -app1: - host: some_host + scheme: https + host: 10.0.0.1 + port: 80 + path_patterns: # Check https://pkg.go.dev/net/http#hdr-Patterns-ServeMux for syntax + - GET / # accept any GET request + - POST /auth # for /auth and /auth/* accept only POST + - GET /home/{$} + - /b/{bucket}/o/{any} + no_tls_verify: false + set_headers: + HEADER_A: VALUE_A, VALUE_B + HEADER_B: VALUE_C + hide_headers: + - HEADER_C + - HEADER_D +app1: # app1 -> localhost:8080 + port: 8080 app2: - scheme: tcp - host: 10.0.0.2 - port: 20000:tcp + scheme: tcp + host: 10.0.0.2 + port: 20000:tcp diff --git a/schema/providers.schema.json b/schema/providers.schema.json index 32d6f93e..3e08599a 100644 --- a/schema/providers.schema.json +++ b/schema/providers.schema.json @@ -75,7 +75,10 @@ "scheme": { "anyOf": [ { - "enum": ["http", "https"] + "enum": [ + "http", + "https" + ] }, { "type": "null" @@ -87,7 +90,7 @@ "then": { "properties": { "port": { - "markdownDescription": "Proxy port from **1** to **65535**", + "markdownDescription": "Proxy port from **0** to **65535**", "oneOf": [ { "type": "string", @@ -96,7 +99,7 @@ }, { "type": "integer", - "minimum": 1, + "minimum": 0, "maximum": 65535 } ] @@ -160,7 +163,9 @@ "not": true } }, - "required": ["port"] + "required": [ + "port" + ] } }, { @@ -192,4 +197,4 @@ } }, "additionalProperties": false -} +} \ No newline at end of file diff --git a/showcase/idlesleeper.webp b/showcase/idlesleeper.webp new file mode 100644 index 00000000..6d63758e Binary files /dev/null and b/showcase/idlesleeper.webp differ diff --git a/src/route/tcp_route.go b/src/route/tcp_route.go index b7861943..48da2539 100755 --- a/src/route/tcp_route.go +++ b/src/route/tcp_route.go @@ -7,6 +7,7 @@ import ( "sync" "time" + T "github.com/yusing/go-proxy/proxy/fields" U "github.com/yusing/go-proxy/utils" ) @@ -35,6 +36,8 @@ func (route *TCPRoute) Setup() error { if err != nil { return err } + //! this read the allocated port from orginal ':0' + route.Port.ListeningPort = T.Port(in.Addr().(*net.TCPAddr).Port) route.listener = in return nil } diff --git a/src/route/udp_route.go b/src/route/udp_route.go index eb0a4303..3961fb09 100755 --- a/src/route/udp_route.go +++ b/src/route/udp_route.go @@ -5,6 +5,7 @@ import ( "io" "net" + T "github.com/yusing/go-proxy/proxy/fields" U "github.com/yusing/go-proxy/utils" F "github.com/yusing/go-proxy/utils/functional" ) @@ -50,6 +51,9 @@ func (route *UDPRoute) Setup() error { return err } + //! this read the allocated listeningPort from orginal ':0' + route.Port.ListeningPort = T.Port(laddr.Port) + route.listeningConn = source route.targetAddr = raddr return nil diff --git a/src/utils/string.go b/src/utils/string.go index 7e62e89d..5938d857 100644 --- a/src/utils/string.go +++ b/src/utils/string.go @@ -1,6 +1,10 @@ package utils -import "strings" +import ( + "net/url" + "strconv" + "strings" +) func CommaSeperatedList(s string) []string { res := strings.Split(s, ",") @@ -9,3 +13,11 @@ func CommaSeperatedList(s string) []string { } return res } + +func ExtractPort(fullURL string) (int, error) { + url, err := url.Parse(fullURL) + if err != nil { + return 0, err + } + return strconv.Atoi(url.Port()) +}