mirror of
https://github.com/whyvl/wireproxy.git
synced 2025-06-27 16:48:01 +02:00
Merge branch 'whyvl:master' into master
This commit is contained in:
commit
7923074c5a
10 changed files with 136 additions and 78 deletions
57
README.md
57
README.md
|
@ -1,4 +1,5 @@
|
|||
# wireproxy
|
||||
|
||||
[](./LICENSE)
|
||||
[](https://github.com/octeep/wireproxy/actions)
|
||||
[](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)! 🚀
|
||||
|
||||

|
||||
|
||||
# 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
|
||||
|
||||
[](https://starchart.cc/octeep/wireproxy)
|
||||
|
|
|
@ -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
BIN
assets/iproyal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -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
3
go.mod
|
@ -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
6
go.sum
|
@ -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
26
http.go
|
@ -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
21
rc.d/README.md
Normal 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
30
rc.d/wireproxy
Normal 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"
|
51
routine.go
51
routine.go
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue