11 Commits

Author SHA1 Message Date
Evsyukov Denis
a2d7aecb6f fix: improvements in memory consumption (#100)
* fix: must close the connection after processing

I think it should help to close #80

* feat: migration to github.com/things-go/go-socks5

- preallocate config slices
- not used interfaces in consumer
- do not allocate new variables in loops

* feat: close connection after full processing

* feat: correct process sigint signal

* feat: improve build system

* fix: http proxy

* feat: update golangci-lint-action to v3.7.0

* feat: correct process routines

* fix: close http conn correctly

* feat: update golangci-lint-action to v4

* fix: goreleaser used clean now
2024-02-11 12:45:43 +00:00
guangwu
49f568810c fix: typo (#93)
Signed-off-by: guoguangwu <guoguangwu@magic-shield.com>
2024-02-09 10:57:11 +00:00
dependabot[bot]
af973227e9 Bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#98)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 11:33:21 +08:00
Jonah Brüchert
0f4d79dea8 Fix build on go 1.21 by updating wireguard-go (#91) 2023-10-18 03:21:11 +01:00
Johan
d1a455e87d Remove interface address subnet length check (#86)
Resolves #82
2023-08-17 23:10:38 +01:00
François Guerraz
5f76f777d5 Use io.Copy instead of io.CopyBuffer (#85) 2023-08-17 22:40:19 +01:00
Jonah Brüchert
d2f7768c51 Update dependencies (#79)
* Update dependencies

gvisor was not updated to the latest version, because it did not
compile.

* actions: Update go version to 1.20

* docker: Update go version to 1.20
2023-08-17 11:42:52 +01:00
villepeh
05c8493981 Provide an example systemd service file (#77)
* Create README.md

* Create wireproxy.service

* Update README.md
2023-07-15 20:39:33 +01:00
Jonah Brüchert
31e6afd75d Allow to use wireproxy as endpoint (#74)
This is useful for running wireguard endpoints in unprivileged
containers.
2023-07-15 20:39:24 +01:00
François Guerraz
aa207764b2 Implement STDIOTunnel (#70) 2023-06-14 03:17:32 +01:00
Mike Dacre
edf63253df Update README with Firefox VPN tabs instructions (#73)
* Update README with Firefox VPN tabs instructions

* move instructions to another file

---------

Co-authored-by: octeep <github@bandersnatch.anonaddy.com>
2023-06-14 03:04:06 +01:00
17 changed files with 485 additions and 176 deletions

View File

@@ -6,17 +6,18 @@ on:
pull_request: pull_request:
branches: branches:
- '**' - '**'
workflow_dispatch:
jobs: jobs:
windowsAmd64Build: windowsAmd64Build:
name: Build Windows amd64 Version name: Build Windows amd64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Windows amd64 Version - name: Building Windows amd64 Version
run: | run: |
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o WireProxy_amd64.exe -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o WireProxy_amd64.exe -v ./cmd/wireproxy
@@ -24,7 +25,7 @@ jobs:
mv WireProxy_amd64.exe wireproxy.exe mv WireProxy_amd64.exe wireproxy.exe
cp wireproxy.exe release_windows_amd64/wireproxy.exe cp wireproxy.exe release_windows_amd64/wireproxy.exe
- name: Upload Windows amd64 Version - name: Upload Windows amd64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_windows_amd64 name: WireProxy_windows_amd64
path: release_windows_amd64 path: release_windows_amd64
@@ -32,11 +33,11 @@ jobs:
name: Build Windows arm64 Version name: Build Windows arm64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Windows arm64 Version - name: Building Windows arm64 Version
run: | run: |
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o WireProxy_arm64.exe -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o WireProxy_arm64.exe -v ./cmd/wireproxy
@@ -44,7 +45,7 @@ jobs:
mv WireProxy_arm64.exe wireproxy.exe mv WireProxy_arm64.exe wireproxy.exe
cp wireproxy.exe release_windows_arm64/wireproxy.exe cp wireproxy.exe release_windows_arm64/wireproxy.exe
- name: Upload Windows arm64 Version - name: Upload Windows arm64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_windows_arm64 name: WireProxy_windows_arm64
path: release_windows_arm64 path: release_windows_arm64
@@ -52,11 +53,11 @@ jobs:
name: Build Linux amd64 Version name: Build Linux amd64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Linux amd64 Version - name: Building Linux amd64 Version
run: | run: |
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o WireProxy_amd64 -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o WireProxy_amd64 -v ./cmd/wireproxy
@@ -64,7 +65,7 @@ jobs:
mv WireProxy_amd64 wireproxy mv WireProxy_amd64 wireproxy
cp wireproxy release_linux_amd64/wireproxy cp wireproxy release_linux_amd64/wireproxy
- name: Upload Linux amd64 Version - name: Upload Linux amd64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_linux_amd64 name: WireProxy_linux_amd64
path: release_linux_amd64 path: release_linux_amd64
@@ -72,11 +73,11 @@ jobs:
name: Build Linux arm64 Version name: Build Linux arm64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Linux arm64 Version - name: Building Linux arm64 Version
run: | run: |
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o WireProxy_arm64 -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o WireProxy_arm64 -v ./cmd/wireproxy
@@ -84,7 +85,7 @@ jobs:
mv WireProxy_arm64 wireproxy mv WireProxy_arm64 wireproxy
cp wireproxy release_linux_arm64/wireproxy cp wireproxy release_linux_arm64/wireproxy
- name: Upload Linux arm64 Version - name: Upload Linux arm64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_linux_arm64 name: WireProxy_linux_arm64
path: release_linux_arm64 path: release_linux_arm64
@@ -92,11 +93,11 @@ jobs:
name: Build Linux s390x Version name: Build Linux s390x Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Linux s390x Version - name: Building Linux s390x Version
run: | run: |
CGO_ENABLED=0 GOOS=linux GOARCH=s390x go build -o WireProxy_s390x -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=linux GOARCH=s390x go build -o WireProxy_s390x -v ./cmd/wireproxy
@@ -104,7 +105,7 @@ jobs:
mv WireProxy_s390x wireproxy mv WireProxy_s390x wireproxy
cp wireproxy release_linux_s390x/wireproxy cp wireproxy release_linux_s390x/wireproxy
- name: Upload Linux s390x Version - name: Upload Linux s390x Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_linux_s390x name: WireProxy_linux_s390x
path: release_linux_s390x path: release_linux_s390x
@@ -112,11 +113,11 @@ jobs:
name: Build Darwin amd64 Version name: Build Darwin amd64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Darwin amd64 Version - name: Building Darwin amd64 Version
run: | run: |
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o WireProxy_amd64 -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o WireProxy_amd64 -v ./cmd/wireproxy
@@ -124,7 +125,7 @@ jobs:
mv WireProxy_amd64 wireproxy mv WireProxy_amd64 wireproxy
cp wireproxy release_darwin_amd64/wireproxy cp wireproxy release_darwin_amd64/wireproxy
- name: Upload Darwin amd64 Version - name: Upload Darwin amd64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_darwin_amd64 name: WireProxy_darwin_amd64
path: release_darwin_amd64 path: release_darwin_amd64
@@ -132,11 +133,11 @@ jobs:
name: Build Darwin arm64 Version name: Build Darwin arm64 Version
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Building Darwin arm64 Version - name: Building Darwin arm64 Version
run: | run: |
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o WireProxy_arm64 -v ./cmd/wireproxy CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o WireProxy_arm64 -v ./cmd/wireproxy
@@ -144,7 +145,7 @@ jobs:
mv WireProxy_arm64 wireproxy mv WireProxy_arm64 wireproxy
cp wireproxy release_darwin_arm64/wireproxy cp wireproxy release_darwin_arm64/wireproxy
- name: Upload Darwin arm64 Version - name: Upload Darwin arm64 Version
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
with: with:
name: WireProxy_darwin_arm64 name: WireProxy_darwin_arm64
path: release_darwin_arm64 path: release_darwin_arm64

View File

@@ -28,26 +28,26 @@ jobs:
steps: steps:
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v2.0.0 uses: docker/setup-buildx-action@v3.0.0
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
# Needed for buildx gha cache to work # Needed for buildx gha cache to work
- name: Expose GitHub Runtime - name: Expose GitHub Runtime
uses: crazy-max/ghaction-github-runtime@v2 uses: crazy-max/ghaction-github-runtime@v3
- name: Build container - name: Build container
env: env:

View File

@@ -6,6 +6,8 @@ on:
pull_request: pull_request:
branches: branches:
- '**' - '**'
workflow_dispatch:
permissions: permissions:
contents: read contents: read
jobs: jobs:
@@ -13,9 +15,11 @@ jobs:
name: lint name: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v5
with: with:
go-version: '1.19' go-version: '1.21'
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v4
with:
version: latest

View File

@@ -6,17 +6,18 @@ on:
pull_request: pull_request:
branches: branches:
- '**' - '**'
workflow_dispatch:
jobs: jobs:
test: test:
name: Test wireproxy name: Test wireproxy
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setting up Go - name: Setting up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.19 go-version: "1.21"
- name: Install dependencies - name: Install dependencies
run: sudo apt install wireguard curl run: sudo apt install wireguard curl
- name: Building wireproxy - name: Building wireproxy

View File

@@ -28,17 +28,17 @@ jobs:
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
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: "1.19" go-version: "1.21"
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2 uses: goreleaser/goreleaser-action@v5
with: with:
distribution: goreleaser distribution: goreleaser
workdir: ${{ env.workdir }} workdir: ${{ env.workdir }}
version: latest version: latest
args: release --rm-dist args: release --clean
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,5 +1,5 @@
# Start by building the application. # Start by building the application.
FROM golang:1.18 as build FROM docker.io/golang:1.21 as build
WORKDIR /usr/src/wireproxy WORKDIR /usr/src/wireproxy
COPY . . COPY . .
@@ -14,6 +14,6 @@ VOLUME [ "/etc/wireproxy"]
ENTRYPOINT [ "/usr/bin/wireproxy" ] ENTRYPOINT [ "/usr/bin/wireproxy" ]
CMD [ "--config", "/etc/wireproxy/config" ] CMD [ "--config", "/etc/wireproxy/config" ]
LABEL org.opencontainers.image.title wireproxy LABEL org.opencontainers.image.title="wireproxy"
LABEL org.opencontainers.image.description "Wireguard client that exposes itself as a socks5 proxy" LABEL org.opencontainers.image.description="Wireguard client that exposes itself as a socks5 proxy"
LABEL org.opencontainers.image.licenses ISC LABEL org.opencontainers.image.licenses="ISC"

View File

@@ -57,6 +57,9 @@ cd wireproxy
make make
``` ```
# Use with VPN
Instructions for using wireproxy with Firefox container tabs and auto-start on MacOS can be found [here](/UseWithVPN.md).
# Sample config file # Sample config file
``` ```
# The [Interface] and [Peer] configurations follow the same semantics and meaning # The [Interface] and [Peer] configurations follow the same semantics and meaning
@@ -91,6 +94,16 @@ Target = play.cubecraft.net:25565
ListenPort = 3422 ListenPort = 3422
Target = localhost:25545 Target = localhost:25545
# STDIOTunnel is a tunnel connecting the standard input and output of the wireproxy
# process to the specified TCP target via wireguard.
# This is especially useful to use wireproxy as a ProxyCommand parameter in openssh
# For example:
# ssh -o ProxyCommand='wireproxy -c myconfig.conf' ssh.myserver.net
# Flow:
# Piped command -->(wireguard)--> ssh.myserver.net:22
[STDIOTunnel]
Target = ssh.myserver.net:22
# Socks5 creates a socks5 proxy on your LAN, and all traffic would be routed via wireguard. # Socks5 creates a socks5 proxy on your LAN, and all traffic would be routed via wireguard.
[Socks5] [Socks5]
BindAddress = 127.0.0.1:25344 BindAddress = 127.0.0.1:25344
@@ -161,10 +174,17 @@ ListenPort = 5080
Target = service-three.servicenet:80 Target = service-three.servicenet:80
``` ```
## Donation Wireproxy can also allow peers to connect to it:
<noscript><a href="https://liberapay.com/octeep/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript> ```
[Interface]
ListenPort = 5400
...
[Peer]
PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=
AllowedIPs = 10.254.254.100/32
# Note there is no Endpoint defined here.
```
## Stargazers over time # Stargazers over time
[![Stargazers over time](https://starchart.cc/octeep/wireproxy.svg)](https://starchart.cc/octeep/wireproxy) [![Stargazers over time](https://starchart.cc/octeep/wireproxy.svg)](https://starchart.cc/octeep/wireproxy)

89
UseWithVPN.md Normal file
View File

@@ -0,0 +1,89 @@
# Getting a Wireguard Server
You can create your own wireguard server using a host service like DigitalOcean,
or you can get a VPN service that provides WireGuard configs.
I recommend ProtonVPN, because it is highly secure and has a great WireGuard
config generator.
Simply go to https://account.protonvpn.com/downloads and scroll down to the
wireguard section to generate your configs, then paste into the appropriate
section below.
# Simple Setup for multiple SOCKS configs for firefox
Create a folder for your configs and startup scripts. Can be the same place as
this code. That path you will use below. For reference this text uses
`/Users/jonny/vpntabs`
For each VPN you want to run, you will download your wireguard config and name
it appropriately (e.g. `ProtonUS.adblock.server.conf`) and then create two new
files from those below with similar names (e.g. `ProtonUS.adblock.conf` and
`ProtonUS.adblock.sh`)
You will also create a launch script, the reference below is only for macOS. The
naming should also be similar (e.g.
`/Users/jonny/Library/LaunchAgents/com.ProtonUS.adblock.plist`)
## Config File
Make sure you use a unique port for every separate server
I recommend you set proxy authentication, you can use the same user/pass for all
```
# Link to the Downloaded config
WGConfig = /Users/jonny/vpntabs/ProtonUS.adblock.server.conf
# Used for firefox containers
[Socks5]
BindAddress = 127.0.0.1:25344 # Update the port here for each new server
# Socks5 authentication parameters, specifying username and password enables
# proxy authentication.
#Username = ...
# Avoid using spaces in the password field
#Password = ...
```
## Startup Script File
This is a bash script to facilitate startup, not strictly essential, but adds
ease.
Note, you MUST update the first path to wherever you installed this code to.
Make sure you use the path for the config file above, not the one you downloaded
from e.g. protonvpn.
```
#!/bin/bash
/Users/jonny/wireproxy/wireproxy -c /Users/jonny/vpntabs/ProtonUS.adblock.conf
```
## MacOS LaunchAgent
To make it run every time you start your computer, you can create a launch agent
in `$HOME/Library/LaunchAgents`. Name reference above.
That file should contain the following, the label should be the same as the file
name and the paths should be set correctly:
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.ProtonUS.adblock</string>
<key>Program</key>
<string>/Users/jonny/vpntabs/ProtonUS.adblock.sh</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
```
To enable it, run
`launchctl load ~/Library/LaunchAgents/com.ProtonUS.adblock.plist` and
`launchtl start ~/Library/LaunchAgents/com.PortonUS.adblock.plist`
# Firefox Setup
You will need to enable the Multi Account Container Tabs extension and a proxy extension, I
recommend Sideberry, but Container Proxy also works.
Create a container to be dedicated to this VPN, and then add the IP, port,
username, and password from above.

View File

@@ -1,13 +1,16 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"os/signal"
"syscall"
"github.com/akamensky/argparse" "github.com/akamensky/argparse"
"github.com/octeep/wireproxy" "github.com/pufferffish/wireproxy"
"golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/device"
"suah.dev/protect" "suah.dev/protect"
) )
@@ -45,6 +48,15 @@ func executablePath() string {
} }
func main() { func main() {
s := make(chan os.Signal, 1)
signal.Notify(s, syscall.SIGINT, syscall.SIGQUIT)
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-s
cancel()
}()
exePath := executablePath() exePath := executablePath()
unveilOrPanic("/", "r") unveilOrPanic("/", "r")
unveilOrPanic(exePath, "x") unveilOrPanic(exePath, "x")
@@ -116,6 +128,10 @@ func main() {
return return
} }
// Wireguard doesn't allow configuring which FD to use for logging
// https://github.com/WireGuard/wireguard-go/blob/master/device/logger.go#L39
// so redirect STDOUT to STDERR, we don't want to print anything to STDOUT anyways
os.Stdout = os.NewFile(uintptr(syscall.Stderr), "/dev/stderr")
logLevel := device.LogLevelVerbose logLevel := device.LogLevelVerbose
if *silent { if *silent {
logLevel = device.LogLevelSilent logLevel = device.LogLevelSilent
@@ -133,5 +149,5 @@ func main() {
go spawner.SpawnRoutine(tnet) go spawner.SpawnRoutine(tnet)
} }
select {} // sleep eternally <-ctx.Done()
} }

View File

@@ -15,7 +15,7 @@ import (
type PeerConfig struct { type PeerConfig struct {
PublicKey string PublicKey string
PreSharedKey string PreSharedKey string
Endpoint string Endpoint *string
KeepAlive int KeepAlive int
AllowedIPs []netip.Prefix AllowedIPs []netip.Prefix
} }
@@ -27,6 +27,7 @@ type DeviceConfig struct {
Peers []PeerConfig Peers []PeerConfig
DNS []netip.Addr DNS []netip.Addr
MTU int MTU int
ListenPort *int
} }
type TCPClientTunnelConfig struct { type TCPClientTunnelConfig struct {
@@ -34,6 +35,10 @@ type TCPClientTunnelConfig struct {
Target string Target string
} }
type STDIOTunnelConfig struct {
Target string
}
type TCPServerTunnelConfig struct { type TCPServerTunnelConfig struct {
ListenPort int ListenPort int
Target string Target string
@@ -120,8 +125,9 @@ func parseNetIP(section *ini.Section, keyName string) ([]netip.Addr, error) {
return []netip.Addr{}, nil return []netip.Addr{}, nil
} }
var ips []netip.Addr keys := key.StringsWithShadows(",")
for _, str := range key.StringsWithShadows(",") { var ips = make([]netip.Addr, 0, len(keys))
for _, str := range keys {
str = strings.TrimSpace(str) str = strings.TrimSpace(str)
ip, err := netip.ParseAddr(str) ip, err := netip.ParseAddr(str)
if err != nil { if err != nil {
@@ -138,18 +144,15 @@ func parseCIDRNetIP(section *ini.Section, keyName string) ([]netip.Addr, error)
return []netip.Addr{}, nil return []netip.Addr{}, nil
} }
var ips []netip.Addr keys := key.StringsWithShadows(",")
for _, str := range key.StringsWithShadows(",") { var ips = make([]netip.Addr, 0, len(keys))
for _, str := range keys {
prefix, err := netip.ParsePrefix(str) prefix, err := netip.ParsePrefix(str)
if err != nil { if err != nil {
return nil, err return nil, err
} }
addr := prefix.Addr() addr := prefix.Addr()
if prefix.Bits() != addr.BitLen() {
return nil, errors.New("interface address subnet should be /32 for IPv4 and /128 for IPv6")
}
ips = append(ips, addr) ips = append(ips, addr)
} }
return ips, nil return ips, nil
@@ -161,8 +164,9 @@ func parseAllowedIPs(section *ini.Section) ([]netip.Prefix, error) {
return []netip.Prefix{}, nil return []netip.Prefix{}, nil
} }
var ips []netip.Prefix keys := key.StringsWithShadows(",")
for _, str := range key.StringsWithShadows(",") { var ips = make([]netip.Prefix, 0, len(keys))
for _, str := range keys {
prefix, err := netip.ParsePrefix(str) prefix, err := netip.ParsePrefix(str)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -225,10 +229,18 @@ func ParseInterface(cfg *ini.File, device *DeviceConfig) error {
device.MTU = value device.MTU = value
} }
if sectionKey, err := section.GetKey("ListenPort"); err == nil {
value, err := sectionKey.Int()
if err != nil {
return err
}
device.ListenPort = &value
}
return nil return nil
} }
// ParsePeer parses the [Peer] section and extract the information into `peers` // ParsePeers parses the [Peer] section and extract the information into `peers`
func ParsePeers(cfg *ini.File, peers *[]PeerConfig) error { func ParsePeers(cfg *ini.File, peers *[]PeerConfig) error {
sections, err := cfg.SectionsByName("Peer") sections, err := cfg.SectionsByName("Peer")
if len(sections) < 1 || err != nil { if len(sections) < 1 || err != nil {
@@ -255,15 +267,14 @@ func ParsePeers(cfg *ini.File, peers *[]PeerConfig) error {
peer.PreSharedKey = value peer.PreSharedKey = value
} }
decoded, err = parseString(section, "Endpoint") if sectionKey, err := section.GetKey("Endpoint"); err == nil {
value := sectionKey.String()
decoded, err = resolveIPPAndPort(strings.ToLower(value))
if err != nil { if err != nil {
return err return err
} }
decoded, err = resolveIPPAndPort(decoded) peer.Endpoint = &decoded
if err != nil {
return err
} }
peer.Endpoint = decoded
if sectionKey, err := section.GetKey("PersistentKeepalive"); err == nil { if sectionKey, err := section.GetKey("PersistentKeepalive"); err == nil {
value, err := sectionKey.Int() value, err := sectionKey.Int()
@@ -300,6 +311,17 @@ func parseTCPClientTunnelConfig(section *ini.Section) (RoutineSpawner, error) {
return config, nil return config, nil
} }
func parseSTDIOTunnelConfig(section *ini.Section) (RoutineSpawner, error) {
config := &STDIOTunnelConfig{}
targetSection, err := parseString(section, "Target")
if err != nil {
return nil, err
}
config.Target = targetSection
return config, nil
}
func parseTCPServerTunnelConfig(section *ini.Section) (RoutineSpawner, error) { func parseTCPServerTunnelConfig(section *ini.Section) (RoutineSpawner, error) {
config := &TCPServerTunnelConfig{} config := &TCPServerTunnelConfig{}
@@ -418,6 +440,11 @@ func ParseConfig(path string) (*Configuration, error) {
return nil, err return nil, err
} }
err = parseRoutinesConfig(&routinesSpawners, cfg, "STDIOTunnel", parseSTDIOTunnelConfig)
if err != nil {
return nil, err
}
err = parseRoutinesConfig(&routinesSpawners, cfg, "TCPServerTunnel", parseTCPServerTunnelConfig) err = parseRoutinesConfig(&routinesSpawners, cfg, "TCPServerTunnel", parseTCPServerTunnelConfig)
if err != nil { if err != nil {
return nil, err return nil, err

32
go.mod
View File

@@ -1,23 +1,25 @@
module github.com/octeep/wireproxy module github.com/pufferffish/wireproxy
go 1.18 go 1.21.1
toolchain go1.21.6
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.4.0
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/go-ini/ini v1.67.0
github.com/go-ini/ini v1.66.4 github.com/things-go/go-socks5 v0.0.5
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
suah.dev/protect v1.2.0 suah.dev/protect v1.2.3
) )
require ( require (
github.com/google/btree v1.0.1 // indirect github.com/google/btree v1.1.2 // indirect
github.com/stretchr/testify v1.8.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.7.0 // indirect golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/sys v0.17.0 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect golang.org/x/time v0.5.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 // indirect gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 // indirect
) )

62
go.sum
View File

@@ -1,41 +1,37 @@
github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A= github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A=
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.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= github.com/akamensky/argparse v1.4.0/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.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=
github.com/go-ini/ini v1.66.4 h1:dKjMqkcbkzfddhIhyglTPgMoJnkvmG+bSLrU9cTHc5M= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.66.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/things-go/go-socks5 v0.0.5 h1:qvKaGcBkfDrUL33SchHN93srAmYGzb4CxSM2DPYufe8=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= github.com/things-go/go-socks5 v0.0.5/go.mod h1:mtzInf8v5xmsBpHZVbIw2YQYhc4K0jRwzfsH64Uh0IQ=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b h1:qgrKnOfe1zyURRNdmDlGbN32i38Zjmw0B1+TMdHcOvg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b/go.mod h1:6y4CqPAy54NwiN4nC8K+R1eMpQDB1P2d25qmunh2RSA= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 h1:cv/zaNV0nr1mJzaeo4S5mHIm5va1W0/9J3/5prlsuRM= gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=
suah.dev/protect v1.2.0 h1:4G4V43yVYXCjLFzaE9QJR0fLo3rf5vNBS9YxyoI19DU= suah.dev/protect v1.2.3 h1:aHeoNwZ9YPp64hrYaN0g0djNE1eRujgH63CrfRrUKdc=
suah.dev/protect v1.2.0/go.mod h1:Ocn1yqUskqe/is6N2bxQxtT+fegbvQsOFyHbJAQu9XE= suah.dev/protect v1.2.3/go.mod h1:n1R3XIbsnryKX7C1PO88i5Wgo0v8OTXm9K9FIKt4rfs=

58
http.go
View File

@@ -10,6 +10,8 @@ import (
"net" "net"
"net/http" "net/http"
"strings" "strings"
"github.com/sourcegraph/conc"
) )
const proxyAuthHeaderKey = "Proxy-Authorization" const proxyAuthHeaderKey = "Proxy-Authorization"
@@ -62,7 +64,7 @@ func (s *HTTPServer) handleConn(req *http.Request, conn net.Conn) (peer net.Conn
_, err = conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")) _, err = conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
if err != nil { if err != nil {
peer.Close() _ = peer.Close()
peer = nil peer = nil
} }
@@ -83,7 +85,7 @@ func (s *HTTPServer) handle(req *http.Request) (peer net.Conn, err error) {
err = req.Write(peer) err = req.Write(peer)
if err != nil { if err != nil {
peer.Close() _ = peer.Close()
peer = nil peer = nil
return peer, fmt.Errorf("conn write failed: %w", err) return peer, fmt.Errorf("conn write failed: %w", err)
} }
@@ -91,19 +93,19 @@ func (s *HTTPServer) handle(req *http.Request) (peer net.Conn, err error) {
return return
} }
func (s *HTTPServer) serve(conn net.Conn) error { func (s *HTTPServer) serve(conn net.Conn) {
defer conn.Close() var rd = bufio.NewReader(conn)
req, err := http.ReadRequest(rd)
var rd io.Reader = bufio.NewReader(conn)
req, err := http.ReadRequest(rd.(*bufio.Reader))
if err != nil { if err != nil {
return fmt.Errorf("read request failed: %w", err) log.Printf("read request failed: %s\n", err)
return
} }
code, err := s.authenticate(req) code, err := s.authenticate(req)
if err != nil { if err != nil {
_ = responseWith(req, code).Write(conn) _ = responseWith(req, code).Write(conn)
return err log.Println(err)
return
} }
var peer net.Conn var peer net.Conn
@@ -114,43 +116,47 @@ func (s *HTTPServer) serve(conn net.Conn) error {
peer, err = s.handle(req) peer, err = s.handle(req)
default: default:
_ = responseWith(req, http.StatusMethodNotAllowed).Write(conn) _ = responseWith(req, http.StatusMethodNotAllowed).Write(conn)
return fmt.Errorf("unsupported protocol: %s", req.Method) log.Printf("unsupported protocol: %s\n", req.Method)
return
} }
if err != nil { if err != nil {
return fmt.Errorf("dial proxy failed: %w", err) log.Printf("dial proxy failed: %s\n", err)
return
} }
if peer == nil { if peer == nil {
return fmt.Errorf("dial proxy failed: peer nil") log.Println("dial proxy failed: peer nil")
return
} }
defer peer.Close()
go func() { go func() {
defer peer.Close() wg := conc.NewWaitGroup()
defer conn.Close() wg.Go(func() {
_, _ = io.Copy(conn, peer) _, err = io.Copy(conn, peer)
}() _ = conn.Close()
})
wg.Go(func() {
_, err = io.Copy(peer, conn) _, err = io.Copy(peer, conn)
_ = peer.Close()
return err })
wg.Wait()
}()
} }
// ListenAndServe is used to create a listener and serve on it // ListenAndServe is used to create a listener and serve on it
func (s *HTTPServer) ListenAndServe(network, addr string) error { func (s *HTTPServer) ListenAndServe(network, addr string) error {
server, err := net.Listen("tcp", s.config.BindAddress) server, err := net.Listen(network, addr)
if err != nil { if err != nil {
return fmt.Errorf("listen tcp failed: %w", err) return fmt.Errorf("listen tcp failed: %w", err)
} }
defer func(server net.Listener) {
_ = server.Close()
}(server)
for { for {
conn, err := server.Accept() conn, err := server.Accept()
if err != nil { if err != nil {
return fmt.Errorf("accept request failed: %w", err) return fmt.Errorf("accept request failed: %w", err)
} }
go func(conn net.Conn) { go func(conn net.Conn) {
err = s.serve(conn) s.serve(conn)
if err != nil {
log.Println(err)
}
}(conn) }(conn)
} }
} }

View File

@@ -11,10 +11,13 @@ import (
"os" "os"
"strconv" "strconv"
"github.com/armon/go-socks5" "github.com/sourcegraph/conc"
"github.com/things-go/go-socks5"
"github.com/things-go/go-socks5/bufferpool"
"net/netip"
"golang.zx2c4.com/wireguard/tun/netstack" "golang.zx2c4.com/wireguard/tun/netstack"
"net/netip"
) )
// errorLogger is the logger to print error message // errorLogger is the logger to print error message
@@ -47,9 +50,8 @@ type addressPort struct {
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 {
return d.Tnet.LookupContextHost(ctx, name)
} }
return d.Tnet.LookupContextHost(ctx, name)
} }
// ResolveAddrWithContext resolves a hostname and returns an AddrPort. // ResolveAddrWithContext resolves a hostname and returns an AddrPort.
@@ -121,17 +123,24 @@ 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} var authMethods []socks5.Authenticator
if username := config.Username; username != "" { if username := config.Username; username != "" {
validator := CredentialValidator{username: username} authMethods = append(authMethods, socks5.UserPassAuthenticator{
validator.password = config.Password Credentials: socks5.StaticCredentials{username: config.Password},
conf.Credentials = validator })
} else {
authMethods = append(authMethods, socks5.NoAuthAuthenticator{})
} }
server, err := socks5.New(conf)
if err != nil { options := []socks5.Option{
log.Fatal(err) socks5.WithDial(vt.Tnet.DialContext),
socks5.WithResolver(vt),
socks5.WithAuthMethods(authMethods),
socks5.WithBufferPool(bufferpool.NewPool(256 * 1024)),
} }
server := socks5.NewServer(options...)
if err := server.ListenAndServe("tcp", config.BindAddress); err != nil { if err := server.ListenAndServe("tcp", config.BindAddress); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -161,15 +170,12 @@ func (c CredentialValidator) Valid(username, password string) bool {
return u&p == 1 return u&p == 1
} }
// connForward copy data from `from` to `to`, then close both stream. // connForward copy data from `from` to `to`
func connForward(bufSize int, from io.ReadWriteCloser, to io.ReadWriteCloser) { func connForward(from io.ReadWriteCloser, to io.ReadWriteCloser) {
buf := make([]byte, bufSize) _, err := io.Copy(to, from)
_, err := io.CopyBuffer(to, from, buf)
if err != nil { if err != nil {
errorLogger.Printf("Cannot forward traffic: %s\n", err.Error()) errorLogger.Printf("Cannot forward traffic: %s\n", err.Error())
} }
_ = from.Close()
_ = to.Close()
} }
// tcpClientForward starts a new connection via wireguard and forward traffic from `conn` // tcpClientForward starts a new connection via wireguard and forward traffic from `conn`
@@ -188,8 +194,56 @@ func tcpClientForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
return return
} }
go connForward(1024, sconn, conn) go func() {
go connForward(1024, conn, sconn) wg := conc.NewWaitGroup()
wg.Go(func() {
connForward(sconn, conn)
})
wg.Go(func() {
connForward(conn, sconn)
})
wg.Wait()
_ = sconn.Close()
_ = conn.Close()
sconn = nil
conn = nil
}()
}
// STDIOTcpForward starts a new connection via wireguard and forward traffic from `conn`
func STDIOTcpForward(vt *VirtualTun, raddr *addressPort) {
target, err := vt.resolveToAddrPort(raddr)
if err != nil {
errorLogger.Printf("Name resolution error for %s: %s\n", raddr.address, err.Error())
return
}
// os.Stdout has previously been remapped to stderr, se we can't use it
stdout, err := os.OpenFile("/dev/stdout", os.O_WRONLY, 0)
if err != nil {
errorLogger.Printf("Failed to open /dev/stdout: %s\n", err.Error())
return
}
tcpAddr := TCPAddrFromAddrPort(*target)
sconn, err := vt.Tnet.DialTCP(tcpAddr)
if err != nil {
errorLogger.Printf("TCP Client Tunnel to %s (%s): %s\n", target, tcpAddr, err.Error())
return
}
go func() {
wg := conc.NewWaitGroup()
wg.Go(func() {
connForward(os.Stdin, sconn)
})
wg.Go(func() {
connForward(sconn, stdout)
})
wg.Wait()
_ = sconn.Close()
sconn = nil
}()
} }
// SpawnRoutine spawns a local TCP server which acts as a proxy to the specified target // SpawnRoutine spawns a local TCP server which acts as a proxy to the specified target
@@ -213,6 +267,16 @@ func (conf *TCPClientTunnelConfig) SpawnRoutine(vt *VirtualTun) {
} }
} }
// SpawnRoutine connects to the specified target and plumbs it to STDIN / STDOUT
func (conf *STDIOTunnelConfig) SpawnRoutine(vt *VirtualTun) {
raddr, err := parseAddressPort(conf.Target)
if err != nil {
log.Fatal(err)
}
go STDIOTcpForward(vt, raddr)
}
// tcpServerForward starts a new connection locally and forward traffic from `conn` // tcpServerForward starts a new connection locally and forward traffic from `conn`
func tcpServerForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) { func tcpServerForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
target, err := vt.resolveToAddrPort(raddr) target, err := vt.resolveToAddrPort(raddr)
@@ -229,8 +293,20 @@ func tcpServerForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
return return
} }
go connForward(1024, sconn, conn) go func() {
go connForward(1024, conn, sconn) gr := conc.NewWaitGroup()
gr.Go(func() {
connForward(sconn, conn)
})
gr.Go(func() {
connForward(conn, sconn)
})
gr.Wait()
_ = sconn.Close()
_ = conn.Close()
sconn = nil
conn = nil
}()
} }
// SpawnRoutine spawns a TCP server on wireguard which acts as a proxy to the specified target // SpawnRoutine spawns a TCP server on wireguard which acts as a proxy to the specified target

47
systemd/README.md Normal file
View File

@@ -0,0 +1,47 @@
# Running wireproxy with systemd
If you're on a systemd-based distro, you'll most likely want to run Wireproxy as a systemd unit.
The provided systemd unit assumes you have the wireproxy executable installed on `/opt/wireproxy/wireproxy` and a configuration file stored at `/etc/wireproxy.conf`. These paths can be customized by editing the unit file.
# Setting up the unit
1. Copy the `wireproxy.service` file from this directory to `/etc/systemd/system/`, or use the following cURL command to download it:
```bash
sudo curl https://raw.githubusercontent.com/pufferffish/wireproxy/master/systemd/wireproxy.service > /etc/systemd/system/wireproxy.service
```
2. If necessary, customize the unit.
Edit the parts with `ExecStartPre=` and `ExecStart=` to point to the executable and the configuration file. For example, if wireproxy is installed on `/usr/bin` and the configuration file is located in `/opt/myfiles/wireproxy.conf` do the following change:
```service
ExecStartPre=/usr/bin/wireproxy -n -c /opt/myfiles/wireproxy.conf
ExecStart=/usr/bin/wireproxy -c /opt/myfiles/wireproxy.conf
```
#### 2.2 Drop root privileges (optional, but recommended)
Without any modifications, this Wireproxy service will run as root. You might want to drop those privileges. One way to do this is to simply create a system account for Wireproxy (or just use your own user account to run it instead).
```bash
sudo useradd --comment "Wireproxy tunnel" --system wireproxy
```
Then uncomment these lines from the wireproxy.service:
```service
#User=wireproxy
#Group=wireproxy
```
Caveats:
1) Make sure `wireproxy` user can read the wireproxy configuration file.
2) Also note that unprivileged user cannot bind to ports below 1024 by default.
4. Reload systemd and enable the unit.
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now wireproxy.service
```
5. Make sure it's working correctly.
Finally, check out the unit status to confirm `wireproxy.service` has started without problems. You can use commands like `systemctl status wireproxy.service` and/or `sudo journalctl -u wireproxy.service`.
# Additional notes
If you want to disable the extensive logging that's done by Wireproxy, simply add `-s` parameter to `ExecStart=`. This will enable the silent mode that was implemented with [pull/67](https://github.com/pufferffish/wireproxy/pull/67).

18
systemd/wireproxy.service Normal file
View File

@@ -0,0 +1,18 @@
[Unit]
Description=Wireproxy socks5/http tunnel
Wants=network-online.target
After=network-online.target
[Service]
#Uncomment and/or change these if you don't want to run Wireproxy as root
#User=wireproxy
#Group=wireproxy
Type=simple
Restart=on-failure
RestartSec=30s
ExecStartPre=/opt/wireproxy/wireproxy -n -c /etc/wireproxy.conf
ExecStart=/opt/wireproxy/wireproxy -c /etc/wireproxy.conf
SyslogIdentifier=wireproxy
[Install]
WantedBy=multi-user.target

View File

@@ -26,15 +26,21 @@ func createIPCRequest(conf *DeviceConfig) (*DeviceSetting, error) {
request.WriteString(fmt.Sprintf("private_key=%s\n", conf.SecretKey)) request.WriteString(fmt.Sprintf("private_key=%s\n", conf.SecretKey))
if conf.ListenPort != nil {
request.WriteString(fmt.Sprintf("listen_port=%d\n", *conf.ListenPort))
}
for _, peer := range conf.Peers { for _, peer := range conf.Peers {
request.WriteString(fmt.Sprintf(heredoc.Doc(` request.WriteString(fmt.Sprintf(heredoc.Doc(`
public_key=%s public_key=%s
endpoint=%s
persistent_keepalive_interval=%d persistent_keepalive_interval=%d
preshared_key=%s preshared_key=%s
`), `),
peer.PublicKey, peer.Endpoint, peer.KeepAlive, peer.PreSharedKey, peer.PublicKey, peer.KeepAlive, peer.PreSharedKey,
)) ))
if peer.Endpoint != nil {
request.WriteString(fmt.Sprintf("endpoint=%s\n", *peer.Endpoint))
}
if len(peer.AllowedIPs) > 0 { if len(peer.AllowedIPs) > 0 {
for _, ip := range peer.AllowedIPs { for _, ip := range peer.AllowedIPs {