Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9714bde99 | ||
|
|
bffb13f4c3 | ||
|
|
2c8b0d7b9b | ||
|
|
70db0f727f | ||
|
|
32ce704189 | ||
|
|
20bf08e41a |
40
.github/workflows/test.yml
vendored
40
.github/workflows/test.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: Test
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Test wireproxy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setting up Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.19
|
|
||||||
- name: Install dependencies
|
|
||||||
run: sudo apt install wireguard curl
|
|
||||||
- name: Building wireproxy
|
|
||||||
run: |
|
|
||||||
git tag dev
|
|
||||||
make
|
|
||||||
- name: Generate test config
|
|
||||||
run: ./test_config.sh
|
|
||||||
- name: Start wireproxy
|
|
||||||
run: ./wireproxy -c test.conf & sleep 1
|
|
||||||
- name: Test socks5
|
|
||||||
run: curl --proxy socks5://localhost:64423 http://zx2c4.com/ip | grep -q "demo.wireguard.com"
|
|
||||||
- name: Test http
|
|
||||||
run: curl --proxy http://localhost:64424 http://zx2c4.com/ip | grep -q "demo.wireguard.com"
|
|
||||||
- name: Test http with password
|
|
||||||
run: curl --proxy http://peter:hunter123@localhost:64424 http://zx2c4.com/ip | grep -q "demo.wireguard.com"
|
|
||||||
- name: Test http with wrong password
|
|
||||||
run: |
|
|
||||||
set +e
|
|
||||||
curl -s --fail --proxy http://peter:wrongpass@localhost:64425 http://zx2c4.com/ip
|
|
||||||
if [[ $? == 0 ]]; then exit 1; fi
|
|
||||||
2
.github/workflows/wireproxy.yml
vendored
2
.github/workflows/wireproxy.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Git clone WireProxy
|
- name: Git clone WireProxy
|
||||||
run: |
|
run: |
|
||||||
git clone https://github.com/pufferffish/wireproxy.git ${{ env.workdir }}
|
git clone https://github.com/octeep/wireproxy.git ${{ env.workdir }}
|
||||||
cp ./.github/wireproxy-releaser.yml ${{ env.workdir }}/.goreleaser.yml
|
cp ./.github/wireproxy-releaser.yml ${{ env.workdir }}/.goreleaser.yml
|
||||||
|
|
||||||
- name: Set up GoReleaser
|
- name: Set up GoReleaser
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,3 @@
|
|||||||
*.sw?
|
*.sw?
|
||||||
/.idea
|
/.idea
|
||||||
.goreleaser.yml
|
.goreleaser.yml
|
||||||
*.conf
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ FROM golang:1.18 as build
|
|||||||
WORKDIR /usr/src/wireproxy
|
WORKDIR /usr/src/wireproxy
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN make
|
RUN CGO_ENABLED=0 go build ./cmd/wireproxy
|
||||||
|
|
||||||
# Now copy it into our base image.
|
# Now copy it into our base image.
|
||||||
FROM gcr.io/distroless/static-debian11:nonroot
|
FROM gcr.io/distroless/static-debian11:nonroot
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -1,14 +1,12 @@
|
|||||||
export GO ?= go
|
export GO ?= go
|
||||||
export CGO_ENABLED = 0
|
|
||||||
|
|
||||||
TAG := $(shell git describe --always --tags $(git rev-list --tags --max-count=1) --match v*)
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: wireproxy
|
all: wireproxy
|
||||||
|
|
||||||
.PHONY: wireproxy
|
.PHONY: wireproxy
|
||||||
wireproxy:
|
wireproxy:
|
||||||
${GO} build -trimpath -ldflags "-s -w -X 'main.version=${TAG}'" ./cmd/wireproxy
|
tag="$$(git describe --tag 2>/dev/null)" && \
|
||||||
|
${GO} build -ldflags "-X 'main.version=$$tag'" ./cmd/wireproxy
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -3,11 +3,11 @@
|
|||||||
[](https://github.com/octeep/wireproxy/actions)
|
[](https://github.com/octeep/wireproxy/actions)
|
||||||
[](https://pkg.go.dev/github.com/octeep/wireproxy)
|
[](https://pkg.go.dev/github.com/octeep/wireproxy)
|
||||||
|
|
||||||
A wireguard client that exposes itself as a socks5/http proxy or tunnels.
|
A wireguard client that exposes itself as a socks5 proxy or tunnels.
|
||||||
|
|
||||||
# What is this
|
# What is this
|
||||||
`wireproxy` is a completely userspace application that connects to a wireguard peer,
|
`wireproxy` is a completely userspace application that connects to a wireguard peer,
|
||||||
and exposes a socks5/http proxy or tunnels on the machine. This can be useful if you need
|
and exposes a socks5 proxy or tunnels on the machine. This can be useful if you need
|
||||||
to connect to certain sites via a wireguard peer, but can't be bothered to setup a new network
|
to connect to certain sites via a wireguard peer, but can't be bothered to setup a new network
|
||||||
interface for whatever reasons.
|
interface for whatever reasons.
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ anything.
|
|||||||
|
|
||||||
# Feature
|
# Feature
|
||||||
- TCP static routing for client and server
|
- TCP static routing for client and server
|
||||||
- SOCKS5/HTTP proxy (currently only CONNECT is supported)
|
- SOCKS5 proxy (currently only CONNECT is supported)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
- UDP Support in SOCKS5
|
- UDP Support in SOCKS5
|
||||||
@@ -34,8 +34,8 @@ anything.
|
|||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: wireproxy [-h|--help] [-c|--config "<value>"] [-s|--silent]
|
usage: wireproxy [-h|--help] -c|--config "<value>" [-d|--daemon]
|
||||||
[-d|--daemon] [-v|--version] [-n|--configtest]
|
[-n|--configtest]
|
||||||
|
|
||||||
Userspace wireguard client for proxying
|
Userspace wireguard client for proxying
|
||||||
|
|
||||||
@@ -43,9 +43,7 @@ Arguments:
|
|||||||
|
|
||||||
-h --help Print help information
|
-h --help Print help information
|
||||||
-c --config Path of configuration file
|
-c --config Path of configuration file
|
||||||
-s --silent Silent mode
|
|
||||||
-d --daemon Make wireproxy run in background
|
-d --daemon Make wireproxy run in background
|
||||||
-v --version Print version
|
|
||||||
-n --configtest Configtest mode. Only check the configuration file for
|
-n --configtest Configtest mode. Only check the configuration file for
|
||||||
validity.
|
validity.
|
||||||
```
|
```
|
||||||
@@ -100,16 +98,6 @@ BindAddress = 127.0.0.1:25344
|
|||||||
#Username = ...
|
#Username = ...
|
||||||
# Avoid using spaces in the password field
|
# Avoid using spaces in the password field
|
||||||
#Password = ...
|
#Password = ...
|
||||||
|
|
||||||
# http creates a http proxy on your LAN, and all traffic would be routed via wireguard.
|
|
||||||
[http]
|
|
||||||
BindAddress = 127.0.0.1:25345
|
|
||||||
|
|
||||||
# HTTP authentication parameters, specifying username and password enables
|
|
||||||
# proxy authentication.
|
|
||||||
#Username = ...
|
|
||||||
# Avoid using spaces in the password field
|
|
||||||
#Password = ...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, if you already have a wireguard config, you can import it in the
|
Alternatively, if you already have a wireguard config, you can import it in the
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/akamensky/argparse"
|
"github.com/akamensky/argparse"
|
||||||
"github.com/octeep/wireproxy"
|
"github.com/octeep/wireproxy"
|
||||||
"golang.zx2c4.com/wireguard/device"
|
|
||||||
"suah.dev/protect"
|
"suah.dev/protect"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -64,7 +63,6 @@ func main() {
|
|||||||
parser := argparse.NewParser("wireproxy", "Userspace wireguard client for proxying")
|
parser := argparse.NewParser("wireproxy", "Userspace wireguard client for proxying")
|
||||||
|
|
||||||
config := parser.String("c", "config", &argparse.Options{Help: "Path of configuration file"})
|
config := parser.String("c", "config", &argparse.Options{Help: "Path of configuration file"})
|
||||||
silent := parser.Flag("s", "silent", &argparse.Options{Help: "Silent mode"})
|
|
||||||
daemon := parser.Flag("d", "daemon", &argparse.Options{Help: "Make wireproxy run in background"})
|
daemon := parser.Flag("d", "daemon", &argparse.Options{Help: "Make wireproxy run in background"})
|
||||||
printVerison := parser.Flag("v", "version", &argparse.Options{Help: "Print version"})
|
printVerison := parser.Flag("v", "version", &argparse.Options{Help: "Print version"})
|
||||||
configTest := parser.Flag("n", "configtest", &argparse.Options{Help: "Configtest mode. Only check the configuration file for validity."})
|
configTest := parser.Flag("n", "configtest", &argparse.Options{Help: "Configtest mode. Only check the configuration file for validity."})
|
||||||
@@ -116,15 +114,10 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logLevel := device.LogLevelVerbose
|
|
||||||
if *silent {
|
|
||||||
logLevel = device.LogLevelSilent
|
|
||||||
}
|
|
||||||
|
|
||||||
// no file access is allowed from now on, only networking
|
// no file access is allowed from now on, only networking
|
||||||
pledgeOrPanic("stdio inet dns")
|
pledgeOrPanic("stdio inet dns")
|
||||||
|
|
||||||
tnet, err := wireproxy.StartWireguard(conf.Device, logLevel)
|
tnet, err := wireproxy.StartWireguard(conf.Device)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
29
config.go
29
config.go
@@ -45,12 +45,6 @@ type Socks5Config struct {
|
|||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPConfig struct {
|
|
||||||
BindAddress string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Device *DeviceConfig
|
Device *DeviceConfig
|
||||||
Routines []RoutineSpawner
|
Routines []RoutineSpawner
|
||||||
@@ -336,24 +330,6 @@ func parseSocks5Config(section *ini.Section) (RoutineSpawner, error) {
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseHTTPConfig(section *ini.Section) (RoutineSpawner, error) {
|
|
||||||
config := &HTTPConfig{}
|
|
||||||
|
|
||||||
bindAddress, err := parseString(section, "BindAddress")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config.BindAddress = bindAddress
|
|
||||||
|
|
||||||
username, _ := parseString(section, "Username")
|
|
||||||
config.Username = username
|
|
||||||
|
|
||||||
password, _ := parseString(section, "Password")
|
|
||||||
config.Password = password
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes a function that parses an individual section into a config, and apply it on all
|
// Takes a function that parses an individual section into a config, and apply it on all
|
||||||
// specified sections
|
// specified sections
|
||||||
func parseRoutinesConfig(routines *[]RoutineSpawner, cfg *ini.File, sectionName string, f func(*ini.Section) (RoutineSpawner, error)) error {
|
func parseRoutinesConfig(routines *[]RoutineSpawner, cfg *ini.File, sectionName string, f func(*ini.Section) (RoutineSpawner, error)) error {
|
||||||
@@ -428,11 +404,6 @@ func ParseConfig(path string) (*Configuration, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = parseRoutinesConfig(&routinesSpawners, cfg, "http", parseHTTPConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Configuration{
|
return &Configuration{
|
||||||
Device: device,
|
Device: device,
|
||||||
Routines: routinesSpawners,
|
Routines: routinesSpawners,
|
||||||
|
|||||||
9
go.mod
9
go.mod
@@ -5,18 +5,21 @@ go 1.18
|
|||||||
require (
|
require (
|
||||||
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
||||||
github.com/akamensky/argparse v1.3.1
|
github.com/akamensky/argparse v1.3.1
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
|
||||||
github.com/go-ini/ini v1.66.4
|
github.com/go-ini/ini v1.66.4
|
||||||
|
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
|
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
|
||||||
suah.dev/protect v1.2.0
|
suah.dev/protect v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.0.1 // indirect
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/stretchr/testify v1.8.0 // indirect
|
github.com/stretchr/testify v1.8.0 // indirect
|
||||||
|
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect
|
||||||
|
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||||
golang.org/x/sys v0.5.0 // indirect
|
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 // indirect
|
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 // indirect
|
||||||
|
|||||||
18
go.sum
18
go.sum
@@ -2,8 +2,6 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZ
|
|||||||
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
|
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
|
||||||
github.com/akamensky/argparse v1.3.1 h1:kP6+OyvR0fuBH6UhbE6yh/nskrDEIQgEA1SUXDPjx4g=
|
github.com/akamensky/argparse v1.3.1 h1:kP6+OyvR0fuBH6UhbE6yh/nskrDEIQgEA1SUXDPjx4g=
|
||||||
github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -11,6 +9,8 @@ github.com/go-ini/ini v1.66.4 h1:dKjMqkcbkzfddhIhyglTPgMoJnkvmG+bSLrU9cTHc5M=
|
|||||||
github.com/go-ini/ini v1.66.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.66.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -18,13 +18,19 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf h1:7PflaKRtU4np/epFxRXlFhlzLXZzKFrH5/I4so5Ove0=
|
||||||
|
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM=
|
||||||
|
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6 h1:8DkPbOq/EPxbD5VJajKuvssiYZJSrlpeetcGfrBoBVE=
|
||||||
|
github.com/txthinking/socks5 v0.0.0-20220615051428-39268faee3e6/go.mod h1:7NloQcrxaZYKURWph5HLxVDlIwMHJXCPkeWPtpftsIg=
|
||||||
|
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe h1:gMWxZxBFRAXqoGkwkYlPX2zvyyKNWJpxOxCrjqJkm5A=
|
||||||
|
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe/go.mod h1:WgqbSEmUYSjEV3B1qmee/PpP2NYEz4bL9/+mF1ma+s4=
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
|
|||||||
156
http.go
156
http.go
@@ -1,156 +0,0 @@
|
|||||||
package wireproxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const proxyAuthHeaderKey = "Proxy-Authorization"
|
|
||||||
|
|
||||||
type HTTPServer struct {
|
|
||||||
config *HTTPConfig
|
|
||||||
|
|
||||||
auth CredentialValidator
|
|
||||||
dial func(network, address string) (net.Conn, error)
|
|
||||||
|
|
||||||
authRequired bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPServer) authenticate(req *http.Request) (int, error) {
|
|
||||||
if !s.authRequired {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := req.Header.Get(proxyAuthHeaderKey)
|
|
||||||
if auth != "" {
|
|
||||||
enc := strings.TrimPrefix(auth, "Basic ")
|
|
||||||
str, err := base64.StdEncoding.DecodeString(enc)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusNotAcceptable, fmt.Errorf("decode username and password failed: %w", err)
|
|
||||||
}
|
|
||||||
pairs := bytes.SplitN(str, []byte(":"), 2)
|
|
||||||
if len(pairs) != 2 {
|
|
||||||
return http.StatusLengthRequired, fmt.Errorf("username and password format invalid")
|
|
||||||
}
|
|
||||||
if s.auth.Valid(string(pairs[0]), string(pairs[1])) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
return http.StatusUnauthorized, fmt.Errorf("username and password not matching")
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.StatusProxyAuthRequired, fmt.Errorf(http.StatusText(http.StatusProxyAuthRequired))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPServer) handleConn(req *http.Request, conn net.Conn) (peer net.Conn, err error) {
|
|
||||||
addr := req.Host
|
|
||||||
if !strings.Contains(addr, ":") {
|
|
||||||
port := "443"
|
|
||||||
addr = net.JoinHostPort(addr, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer, err = s.dial("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return peer, fmt.Errorf("tun tcp dial failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
|
|
||||||
if err != nil {
|
|
||||||
peer.Close()
|
|
||||||
peer = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPServer) handle(req *http.Request) (peer net.Conn, err error) {
|
|
||||||
addr := req.Host
|
|
||||||
if !strings.Contains(addr, ":") {
|
|
||||||
port := "80"
|
|
||||||
addr = net.JoinHostPort(addr, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer, err = s.dial("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return peer, fmt.Errorf("tun tcp dial failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = req.Write(peer)
|
|
||||||
if err != nil {
|
|
||||||
peer.Close()
|
|
||||||
peer = nil
|
|
||||||
return peer, fmt.Errorf("conn write failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPServer) serve(conn net.Conn) error {
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
var rd io.Reader = bufio.NewReader(conn)
|
|
||||||
req, err := http.ReadRequest(rd.(*bufio.Reader))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("read request failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := s.authenticate(req)
|
|
||||||
if err != nil {
|
|
||||||
_ = responseWith(req, code).Write(conn)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var peer net.Conn
|
|
||||||
switch req.Method {
|
|
||||||
case http.MethodConnect:
|
|
||||||
peer, err = s.handleConn(req, conn)
|
|
||||||
case http.MethodGet:
|
|
||||||
peer, err = s.handle(req)
|
|
||||||
default:
|
|
||||||
_ = responseWith(req, http.StatusMethodNotAllowed).Write(conn)
|
|
||||||
return fmt.Errorf("unsupported protocol: %s", req.Method)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dial proxy failed: %w", err)
|
|
||||||
}
|
|
||||||
if peer == nil {
|
|
||||||
return fmt.Errorf("dial proxy failed: peer nil")
|
|
||||||
}
|
|
||||||
defer peer.Close()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer peer.Close()
|
|
||||||
defer conn.Close()
|
|
||||||
_, _ = io.Copy(conn, peer)
|
|
||||||
}()
|
|
||||||
_, err = io.Copy(peer, conn)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenAndServe is used to create a listener and serve on it
|
|
||||||
func (s *HTTPServer) ListenAndServe(network, addr string) error {
|
|
||||||
server, err := net.Listen("tcp", s.config.BindAddress)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("listen tcp failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
conn, err := server.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("accept request failed: %w", err)
|
|
||||||
}
|
|
||||||
go func(conn net.Conn) {
|
|
||||||
err = s.serve(conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
routine.go
46
routine.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/txthinking/socks5"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -11,9 +12,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/armon/go-socks5"
|
|
||||||
|
|
||||||
"golang.zx2c4.com/wireguard/tun/netstack"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,12 +24,6 @@ type CredentialValidator struct {
|
|||||||
password string
|
password string
|
||||||
}
|
}
|
||||||
|
|
||||||
// VirtualTun stores a reference to netstack network and DNS configuration
|
|
||||||
type VirtualTun struct {
|
|
||||||
Tnet *netstack.Net
|
|
||||||
SystemDNS bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoutineSpawner spawns a routine (e.g. socks5, tcp static routes) after the configuration is parsed
|
// RoutineSpawner spawns a routine (e.g. socks5, tcp static routes) after the configuration is parsed
|
||||||
type RoutineSpawner interface {
|
type RoutineSpawner interface {
|
||||||
SpawnRoutine(vt *VirtualTun)
|
SpawnRoutine(vt *VirtualTun)
|
||||||
@@ -45,10 +37,10 @@ type addressPort struct {
|
|||||||
// LookupAddr lookups a hostname.
|
// LookupAddr lookups a hostname.
|
||||||
// DNS traffic may or may not be routed depending on VirtualTun's setting
|
// DNS traffic may or may not be routed depending on VirtualTun's setting
|
||||||
func (d VirtualTun) LookupAddr(ctx context.Context, name string) ([]string, error) {
|
func (d VirtualTun) LookupAddr(ctx context.Context, name string) ([]string, error) {
|
||||||
if d.SystemDNS {
|
if d.systemDNS {
|
||||||
return net.DefaultResolver.LookupHost(ctx, name)
|
return net.DefaultResolver.LookupHost(ctx, name)
|
||||||
} else {
|
} else {
|
||||||
return d.Tnet.LookupContextHost(ctx, name)
|
return d.tnet.LookupContextHost(ctx, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,34 +113,12 @@ func (d VirtualTun) resolveToAddrPort(endpoint *addressPort) (*netip.AddrPort, e
|
|||||||
|
|
||||||
// SpawnRoutine spawns a socks5 server.
|
// SpawnRoutine spawns a socks5 server.
|
||||||
func (config *Socks5Config) SpawnRoutine(vt *VirtualTun) {
|
func (config *Socks5Config) SpawnRoutine(vt *VirtualTun) {
|
||||||
conf := &socks5.Config{Dial: vt.Tnet.DialContext, Resolver: vt}
|
server, err := socks5.NewClassicServer(config.BindAddress, "0.0.0.0", config.Username, config.Password, 15, 15)
|
||||||
if username := config.Username; username != "" {
|
|
||||||
validator := CredentialValidator{username: username}
|
|
||||||
validator.password = config.Password
|
|
||||||
conf.Credentials = validator
|
|
||||||
}
|
|
||||||
server, err := socks5.New(conf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
err = server.ListenAndServe(vt)
|
||||||
if err := server.ListenAndServe("tcp", config.BindAddress); err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpawnRoutine spawns a http server.
|
|
||||||
func (config *HTTPConfig) SpawnRoutine(vt *VirtualTun) {
|
|
||||||
http := &HTTPServer{
|
|
||||||
config: config,
|
|
||||||
dial: vt.Tnet.Dial,
|
|
||||||
auth: CredentialValidator{config.Username, config.Password},
|
|
||||||
}
|
|
||||||
if config.Username != "" || config.Password != "" {
|
|
||||||
http.authRequired = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := http.ListenAndServe("tcp", config.BindAddress); err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +152,7 @@ func tcpClientForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
|
|||||||
|
|
||||||
tcpAddr := TCPAddrFromAddrPort(*target)
|
tcpAddr := TCPAddrFromAddrPort(*target)
|
||||||
|
|
||||||
sconn, err := vt.Tnet.DialTCP(tcpAddr)
|
sconn, err := vt.tnet.DialTCP(tcpAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorLogger.Printf("TCP Client Tunnel to %s: %s\n", target, err.Error())
|
errorLogger.Printf("TCP Client Tunnel to %s: %s\n", target, err.Error())
|
||||||
return
|
return
|
||||||
@@ -241,7 +211,7 @@ func (conf *TCPServerTunnelConfig) SpawnRoutine(vt *VirtualTun) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addr := &net.TCPAddr{Port: conf.ListenPort}
|
addr := &net.TCPAddr{Port: conf.ListenPort}
|
||||||
server, err := vt.Tnet.ListenTCP(addr)
|
server, err := vt.tnet.ListenTCP(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
exec 3<>/dev/tcp/demo.wireguard.com/42912
|
|
||||||
privatekey="$(wg genkey)"
|
|
||||||
wg pubkey <<<"$privatekey" >&3
|
|
||||||
IFS=: read -r status server_pubkey server_port internal_ip <&3
|
|
||||||
[[ $status == OK ]]
|
|
||||||
cat >test.conf <<EOL
|
|
||||||
[Interface]
|
|
||||||
Address = $internal_ip/32
|
|
||||||
PrivateKey = $privatekey
|
|
||||||
DNS = 8.8.8.8
|
|
||||||
|
|
||||||
[Peer]
|
|
||||||
PublicKey = $server_pubkey
|
|
||||||
Endpoint = demo.wireguard.com:$server_port
|
|
||||||
|
|
||||||
[Socks5]
|
|
||||||
BindAddress = 127.0.0.1:64423
|
|
||||||
|
|
||||||
[http]
|
|
||||||
BindAddress = 127.0.0.1:64424
|
|
||||||
|
|
||||||
[http]
|
|
||||||
BindAddress = 127.0.0.1:64425
|
|
||||||
Username = peter
|
|
||||||
Password = hunter123
|
|
||||||
EOL
|
|
||||||
179
tunnel.go
Normal file
179
tunnel.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package wireproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
"github.com/txthinking/socks5"
|
||||||
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VirtualTun stores a reference to netstack network and DNS configuration
|
||||||
|
type VirtualTun struct {
|
||||||
|
tnet *netstack.Net
|
||||||
|
systemDNS bool
|
||||||
|
mappedPortToNatEntry map[uint16]string
|
||||||
|
natEntryToMappedPort *cache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
type NatEntry struct {
|
||||||
|
key string
|
||||||
|
srcAddr net.Addr
|
||||||
|
mappedPort uint16
|
||||||
|
conn *gonet.UDPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *VirtualTun) connect(w io.Writer, r *socks5.Request) (net.Conn, error) {
|
||||||
|
if socks5.Debug {
|
||||||
|
log.Println("Call:", r.Address())
|
||||||
|
}
|
||||||
|
tmp, err := d.tnet.Dial("tcp", r.Address())
|
||||||
|
if err != nil {
|
||||||
|
var p *socks5.Reply
|
||||||
|
if r.Atyp == socks5.ATYPIPv4 || r.Atyp == socks5.ATYPDomain {
|
||||||
|
p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00})
|
||||||
|
} else {
|
||||||
|
p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00})
|
||||||
|
}
|
||||||
|
if _, err := p.WriteTo(w); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a, addr, port, err := socks5.ParseAddress(tmp.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
var p *socks5.Reply
|
||||||
|
if r.Atyp == socks5.ATYPIPv4 || r.Atyp == socks5.ATYPDomain {
|
||||||
|
p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00})
|
||||||
|
} else {
|
||||||
|
p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00})
|
||||||
|
}
|
||||||
|
if _, err := p.WriteTo(w); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p := socks5.NewReply(socks5.RepSuccess, a, addr, port)
|
||||||
|
if _, err := p.WriteTo(w); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *VirtualTun) TCPHandle(s *socks5.Server, c *net.TCPConn, r *socks5.Request) error {
|
||||||
|
if r.Cmd == socks5.CmdConnect {
|
||||||
|
rc, err := d.connect(c, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
go func() {
|
||||||
|
var bf [1024 * 2]byte
|
||||||
|
for {
|
||||||
|
if s.TCPTimeout != 0 {
|
||||||
|
if err := rc.SetDeadline(time.Now().Add(time.Duration(s.TCPTimeout) * time.Second)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i, err := rc.Read(bf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := c.Write(bf[0:i]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var bf [1024 * 2]byte
|
||||||
|
for {
|
||||||
|
if s.TCPTimeout != 0 {
|
||||||
|
if err := c.SetDeadline(time.Now().Add(time.Duration(s.TCPTimeout) * time.Second)); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i, err := c.Read(bf[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if _, err := rc.Write(bf[0:i]); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Cmd == socks5.CmdUDP {
|
||||||
|
caddr, err := r.UDP(c, s.ServerAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srcAddr := caddr.String()
|
||||||
|
mappedPort := uint16(caddr.Port)
|
||||||
|
tries := 0
|
||||||
|
for _, occupied := d.mappedPortToNatEntry[mappedPort]; occupied; mappedPort++ {
|
||||||
|
tries++
|
||||||
|
if tries > 65535 {
|
||||||
|
return fmt.Errorf("nat table is full")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
laddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", mappedPort))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conn, err := d.tnet.ListenUDP(laddr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("fic")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
entry := &NatEntry{
|
||||||
|
key: srcAddr,
|
||||||
|
srcAddr: caddr,
|
||||||
|
conn: conn,
|
||||||
|
mappedPort: mappedPort,
|
||||||
|
}
|
||||||
|
d.mappedPortToNatEntry[mappedPort] = srcAddr
|
||||||
|
d.natEntryToMappedPort.Set(srcAddr, entry, 0)
|
||||||
|
go func() {
|
||||||
|
buf := make([]byte, 65536)
|
||||||
|
for n, from, err := conn.ReadFrom(buf); err == nil; n, from, err = conn.ReadFrom(buf) {
|
||||||
|
a, addr, port, err := socks5.ParseAddress(from.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
d.natEntryToMappedPort.Set(srcAddr, entry, 0)
|
||||||
|
d1 := socks5.NewDatagram(a, addr, port, buf[0:n])
|
||||||
|
if _, err := s.UDPConn.WriteToUDP(d1.Bytes(), caddr); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = conn.Close()
|
||||||
|
d.natEntryToMappedPort.Delete(srcAddr)
|
||||||
|
}()
|
||||||
|
fmt.Printf("%s udp mapped to port %d\n", srcAddr, mappedPort)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return socks5.ErrUnsupportCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *VirtualTun) UDPHandle(server *socks5.Server, addr *net.UDPAddr, datagram *socks5.Datagram) error {
|
||||||
|
srcAddr := addr.String()
|
||||||
|
entry, ok := d.natEntryToMappedPort.Get(srcAddr)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("this udp address %s is not associated", srcAddr)
|
||||||
|
}
|
||||||
|
natEntry := entry.(*NatEntry)
|
||||||
|
// refresh timeout
|
||||||
|
d.natEntryToMappedPort.Set(srcAddr, entry, 0)
|
||||||
|
raddr, err := net.ResolveUDPAddr("udp", datagram.Address())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = natEntry.conn.WriteTo(datagram.Data, raddr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
25
util.go
25
util.go
@@ -1,25 +0,0 @@
|
|||||||
package wireproxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const space = " "
|
|
||||||
|
|
||||||
func responseWith(req *http.Request, statusCode int) *http.Response {
|
|
||||||
statusText := http.StatusText(statusCode)
|
|
||||||
body := "wireproxy:" + space + req.Proto + space + strconv.Itoa(statusCode) + space + statusText + "\r\n"
|
|
||||||
|
|
||||||
return &http.Response{
|
|
||||||
StatusCode: statusCode,
|
|
||||||
Status: statusText,
|
|
||||||
Proto: req.Proto,
|
|
||||||
ProtoMajor: req.ProtoMajor,
|
|
||||||
ProtoMinor: req.ProtoMinor,
|
|
||||||
Header: http.Header{},
|
|
||||||
Body: io.NopCloser(bytes.NewBufferString(body)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
wireguard.go
20
wireguard.go
@@ -3,8 +3,9 @@ package wireproxy
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/MakeNowJust/heredoc/v2"
|
"github.com/MakeNowJust/heredoc/v2"
|
||||||
"golang.zx2c4.com/wireguard/conn"
|
"golang.zx2c4.com/wireguard/conn"
|
||||||
@@ -53,7 +54,7 @@ func createIPCRequest(conf *DeviceConfig) (*DeviceSetting, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StartWireguard creates a tun interface on netstack given a configuration
|
// StartWireguard creates a tun interface on netstack given a configuration
|
||||||
func StartWireguard(conf *DeviceConfig, logLevel int) (*VirtualTun, error) {
|
func StartWireguard(conf *DeviceConfig) (*VirtualTun, error) {
|
||||||
setting, err := createIPCRequest(conf)
|
setting, err := createIPCRequest(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -63,7 +64,7 @@ func StartWireguard(conf *DeviceConfig, logLevel int) (*VirtualTun, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(logLevel, ""))
|
dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, ""))
|
||||||
err = dev.IpcSet(setting.ipcRequest)
|
err = dev.IpcSet(setting.ipcRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -74,8 +75,17 @@ func StartWireguard(conf *DeviceConfig, logLevel int) (*VirtualTun, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
natTable := cache.New(30*time.Second, time.Minute)
|
||||||
|
natTableRev := make(map[uint16]string)
|
||||||
|
natTable.OnEvicted(func(srcAddr string, i interface{}) {
|
||||||
|
entry := i.(*NatEntry)
|
||||||
|
_ = entry.conn.Close()
|
||||||
|
delete(natTableRev, entry.mappedPort)
|
||||||
|
})
|
||||||
return &VirtualTun{
|
return &VirtualTun{
|
||||||
Tnet: tnet,
|
tnet: tnet,
|
||||||
SystemDNS: len(setting.dns) == 0,
|
systemDNS: len(setting.dns) == 0,
|
||||||
|
mappedPortToNatEntry: natTableRev,
|
||||||
|
natEntryToMappedPort: natTable,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user