Merge branch 'whyvl:master' into master

This commit is contained in:
VastBlast 2025-05-23 19:52:45 -04:00 committed by GitHub
commit 7923074c5a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 136 additions and 78 deletions

View file

@ -1,4 +1,5 @@
# wireproxy
[![ISC licensed](https://img.shields.io/badge/license-ISC-blue)](./LICENSE)
[![Build status](https://github.com/octeep/wireproxy/actions/workflows/build.yml/badge.svg)](https://github.com/octeep/wireproxy/actions)
[![Documentation](https://img.shields.io/badge/godoc-wireproxy-blue)](https://pkg.go.dev/github.com/octeep/wireproxy)
@ -6,12 +7,14 @@
A wireguard client that exposes itself as a socks5/http proxy or tunnels.
# What is this
`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
to connect to certain sites via a wireguard peer, but can't be bothered to setup a new network
interface for whatever reasons.
# Why you might want this
- You simply want to use wireguard as a way to proxy some traffic.
- You don't want root permission just to change wireguard settings.
@ -23,20 +26,30 @@ anything.
Users who want something similar but for Amnezia VPN can use [this fork](https://github.com/artem-russkikh/wireproxy-awg)
of wireproxy by [@artem-russkikh](https://github.com/artem-russkikh).
# Sponsor
This project is supported by [IPRoyal](https://iproyal.com/?r=795836). You can get premium quality proxies at unbeatable prices
with a discount using [this referral link](https://iproyal.com/?r=795836)! 🚀
![IPRoyal](/assets/iproyal.png)
# Feature
- TCP static routing for client and server
- SOCKS5/HTTP proxy (currently only CONNECT is supported)
# TODO
- UDP Support in SOCKS5
- UDP static routing
# Usage
```
```bash
./wireproxy [-c path to config]
```
```
```bash
usage: wireproxy [-h|--help] [-c|--config "<value>"] [-s|--silent]
[-d|--daemon] [-i|--info "<value>"] [-v|--version]
[-n|--configtest]
@ -54,21 +67,29 @@ Arguments:
-v --version Print version
-n --configtest Configtest mode. Only check the configuration file for
validity.
```
# Build instruction
```
```bash
git clone https://github.com/octeep/wireproxy
cd wireproxy
make
```
# Install
```bash
go install github.com/pufferffish/wireproxy/cmd/wireproxy@v1.0.9 # or @latest
```
# 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
```
```ini
# The [Interface] and [Peer] configurations follow the same semantics and meaning
# of a wg-quick configuration. To understand what these fields mean, please refer to:
# https://wiki.archlinux.org/title/WireGuard#Persistent_configuration
@ -135,7 +156,8 @@ BindAddress = 127.0.0.1:25345
Alternatively, if you already have a wireguard config, you can import it in the
wireproxy config file like this:
```
```ini
WGConfig = <path to the wireguard config>
# Same semantics as above
@ -151,7 +173,8 @@ WGConfig = <path to the wireguard config>
Having multiple peers is also supported. `AllowedIPs` would need to be specified
such that wireproxy would know which peer to forward to.
```
```ini
[Interface]
Address = 10.254.254.40/32
PrivateKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
@ -183,7 +206,8 @@ Target = service-three.servicenet:80
```
Wireproxy can also allow peers to connect to it:
```
```ini
[Interface]
ListenPort = 5400
...
@ -193,7 +217,9 @@ PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=
AllowedIPs = 10.254.254.100/32
# Note there is no Endpoint defined here.
```
# Health endpoint
Wireproxy supports exposing a health endpoint for monitoring purposes.
The argument `--info/-i` specifies an address and port (e.g. `localhost:9080`), which exposes a HTTP server that provides health status metric of the server.
@ -204,7 +230,8 @@ Currently two endpoints are implemented:
`/readyz`: This responds with a json which shows the last time a pong is received from an IP specified with `CheckAlive`. When `CheckAlive` is set, a ping is sent out to addresses in `CheckAlive` per `CheckAliveInterval` seconds (defaults to 5) via wireguard. If a pong has not been received from one of the addresses within the last `CheckAliveInterval` seconds (+2 seconds for some leeway to account for latency), then it would respond with a 503, otherwise a 200.
For example:
```
```ini
[Interface]
PrivateKey = censored
Address = 10.2.0.2/32
@ -220,8 +247,10 @@ Endpoint = 149.34.244.174:51820
[Socks5]
BindAddress = 127.0.0.1:25344
```
`/readyz` would respond with
```
```text
< HTTP/1.1 503 Service Unavailable
< Date: Thu, 11 Apr 2024 00:54:59 GMT
< Content-Length: 35
@ -231,15 +260,18 @@ BindAddress = 127.0.0.1:25344
```
And for:
```
```ini
[Interface]
PrivateKey = censored
Address = 10.2.0.2/32
DNS = 10.2.0.1
CheckAlive = 1.1.1.1
```
`/readyz` would respond with
```
```text
< HTTP/1.1 200 OK
< Date: Thu, 11 Apr 2024 00:56:21 GMT
< Content-Length: 23
@ -253,4 +285,5 @@ If nothing is set for `CheckAlive`, an empty JSON object with 200 will be the re
The peer which the ICMP ping packet is routed to depends on the `AllowedIPs` set for each peers.
# Stargazers over time
[![Stargazers over time](https://starchart.cc/octeep/wireproxy.svg)](https://starchart.cc/octeep/wireproxy)

View file

@ -1,11 +1,12 @@
# 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
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.
@ -25,9 +26,11 @@ 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
```
```ini
# Link to the Downloaded config
WGConfig = /Users/jonny/vpntabs/ProtonUS.adblock.server.conf
@ -43,24 +46,27 @@ BindAddress = 127.0.0.1:25344 # Update the port here for each new server
```
## 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.
```
```bash
#!/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
<?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">
@ -70,7 +76,7 @@ name and the paths should be set correctly:
<key>Program</key>
<string>/Users/jonny/vpntabs/ProtonUS.adblock.sh</string>
<key>RunAtLoad</key>
<true/>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
@ -82,6 +88,7 @@ To enable it, run
`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.

BIN
assets/iproyal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -332,7 +332,8 @@ func ParsePeers(cfg *ini.File, peers *[]PeerConfig) error {
peer.PreSharedKey = value
}
if value, err := parseString(section, "Endpoint"); err == nil {
if sectionKey, err := section.GetKey("Endpoint"); err == nil {
value := sectionKey.String()
decoded, err = resolveIPPAndPort(strings.ToLower(value))
if err != nil {
return err

3
go.mod
View file

@ -9,9 +9,8 @@ require (
github.com/akamensky/argparse v1.4.0
github.com/go-ini/ini v1.67.0
github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a
github.com/sourcegraph/conc v0.3.0
github.com/things-go/go-socks5 v0.0.5
golang.org/x/net v0.23.0
golang.org/x/net v0.33.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
suah.dev/protect v1.2.3
)

6
go.sum
View file

@ -12,16 +12,14 @@ github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a h1:dz+a1M
github.com/landlock-lsm/go-landlock v0.0.0-20240216195629-efb66220540a/go.mod h1:1NY/VPO8xm3hXw3f+M65z+PJDLUaZA5cu7OfanxoUzY=
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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/things-go/go-socks5 v0.0.5 h1:qvKaGcBkfDrUL33SchHN93srAmYGzb4CxSM2DPYufe8=
github.com/things-go/go-socks5 v0.0.5/go.mod h1:mtzInf8v5xmsBpHZVbIw2YQYhc4K0jRwzfsH64Uh0IQ=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

26
http.go
View file

@ -10,8 +10,6 @@ import (
"net"
"net/http"
"strings"
"github.com/sourcegraph/conc"
)
const proxyAuthHeaderKey = "Proxy-Authorization"
@ -32,7 +30,7 @@ func (s *HTTPServer) authenticate(req *http.Request) (int, error) {
auth := req.Header.Get(proxyAuthHeaderKey)
if auth == "" {
return http.StatusProxyAuthRequired, fmt.Errorf(http.StatusText(http.StatusProxyAuthRequired))
return http.StatusProxyAuthRequired, fmt.Errorf("%s", http.StatusText(http.StatusProxyAuthRequired))
}
enc := strings.TrimPrefix(auth, "Basic ")
@ -131,17 +129,19 @@ func (s *HTTPServer) serve(conn net.Conn) {
log.Println("dial proxy failed: peer nil")
return
}
go func() {
wg := conc.NewWaitGroup()
wg.Go(func() {
_, err = io.Copy(conn, peer)
_ = conn.Close()
})
wg.Go(func() {
_, err = io.Copy(peer, conn)
_ = peer.Close()
})
wg.Wait()
defer conn.Close()
defer peer.Close()
_, _ = io.Copy(conn, peer)
}()
go func() {
defer conn.Close()
defer peer.Close()
_, _ = io.Copy(peer, conn)
}()
}

21
rc.d/README.md Normal file
View file

@ -0,0 +1,21 @@
# Running wireproxy with rc.d
If you're on a rc.d-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 `/bin/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` file from this directory to `/usr/local/etc/rc.d`.
2. If necessary, customize the unit.
Edit the parts with `procname`, `command`, `wireproxy_conf` to point to the executable and the configuration file.
4. Add the following lines to `/etc/rc.conf` to enable wireproxy
`wireproxy_enable="YES"`
5. Start wireproxy service and check status
```
sudo service wireproxy start
sudo service wireproxy status
```

30
rc.d/wireproxy Normal file
View file

@ -0,0 +1,30 @@
#!/bin/sh
#
# PROVIDE: wireproxy
# REQUIRE: DAEMON
# KEYWORD: nojail
#
#
# Add the following lines to /etc/rc.conf to enable wireproxy:
#
#wireproxy_enable="YES"
#
. /etc/rc.subr
name=wireproxy
rcvar=wireproxy_enable
load_rc_config $name
procname="/bin/wireproxy"
wireproxy_enable=${wireproxy_enable:-"NO"}
wireproxy_bin=/bin/wireproxy
wireproxy_conf=/etc/wireproxy.conf
command=${wireproxy_bin}
command_args="-s -d -c ${wireproxy_conf}"
run_rc_command "$1"

View file

@ -24,7 +24,6 @@ import (
"sync"
"time"
"github.com/sourcegraph/conc"
"github.com/things-go/go-socks5"
"github.com/things-go/go-socks5/bufferpool"
@ -190,6 +189,9 @@ func (c CredentialValidator) Valid(username, password string) bool {
// connForward copy data from `from` to `to`
func connForward(from io.ReadWriteCloser, to io.ReadWriteCloser) {
defer from.Close()
defer to.Close()
_, err := io.Copy(to, from)
if err != nil {
errorLogger.Printf("Cannot forward traffic: %s\n", err.Error())
@ -212,20 +214,8 @@ func tcpClientForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
return
}
go func() {
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
}()
go connForward(sconn, conn)
go connForward(conn, sconn)
}
// STDIOTcpForward starts a new connection via wireguard and forward traffic from `conn`
@ -250,18 +240,8 @@ func STDIOTcpForward(vt *VirtualTun, raddr *addressPort) {
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
}()
go connForward(os.Stdin, sconn)
go connForward(sconn, stdout)
}
// SpawnRoutine spawns a local TCP server which acts as a proxy to the specified target
@ -311,20 +291,9 @@ func tcpServerForward(vt *VirtualTun, raddr *addressPort, conn net.Conn) {
return
}
go func() {
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
}()
go connForward(sconn, conn)
go connForward(conn, sconn)
}
// SpawnRoutine spawns a TCP server on wireguard which acts as a proxy to the specified target