wireproxy

package module
v0.0.0-...-ff4200f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 9, 2026 License: ISC Imports: 32 Imported by: 0

README

wireproxy-awg

ISC licensed Build status Documentation

AmneziaWG compatible wireguard client that exposes itself as a socks5/http proxy or tunnels. Forked from wireproxy

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.

Currently, I'm running wireproxy connected to a wireguard server in another country, and configured my browser to use wireproxy for certain sites. It's pretty useful since wireproxy is completely isolated from my network interfaces, and I don't need root to configure anything.

Users who want something similar but for Amnezia VPN can use this fork of wireproxy by @artem-russkikh.

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

./wireproxy [-c path to config]
usage: wireproxy [-h|--help] [-c|--config "<value>"] [-s|--silent]
                 [-d|--daemon] [-i|--info "<value>"] [-v|--version]
                 [-n|--configtest]

                 Userspace wireguard client for proxying

Arguments:

  -h  --help        Print help information
  -c  --config      Path of configuration file
                    Default paths: /etc/wireproxy/wireproxy.conf, $HOME/.config/wireproxy.conf
  -s  --silent      Silent mode
  -d  --daemon      Make wireproxy run in background
  -i  --info        Specify the address and port for exposing health status
  -v  --version     Print version
  -n  --configtest  Configtest mode. Only check the configuration file for
                    validity.

Build instruction

git clone https://github.com/artem-russkikh/wireproxy-awg
cd wireproxy-awg
make

Install

go install github.com/artem-russkikh/wireproxy-awg/cmd/wireproxy@v1.0.12 # or @latest

Use with VPN

Instructions for using wireproxy with Firefox container tabs and auto-start on MacOS can be found here.

Sample config file

# 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
# https://www.wireguard.com/#simple-network-interface
[Interface]
Address = 10.200.200.2/32 # The subnet should be /32 and /128 for IPv4 and v6 respectively
# MTU = 1420 (optional)
PrivateKey = uCTIK+56CPyCvwJxmU5dBfuyJvPuSXAq1FzHdnIxe1Q=
# PrivateKey = $MY_WIREGUARD_PRIVATE_KEY # Alternatively, reference environment variables
DNS = 10.200.200.1

[Peer]
PublicKey = QP+A67Z2UBrMgvNIdHv8gPel5URWNLS4B3ZQ2hQIZlg=
# PresharedKey = UItQuvLsyh50ucXHfjF0bbR4IIpVBd74lwKc8uIPXXs= (optional)
Endpoint = my.ddns.example.com:51820
# PersistentKeepalive = 25 (optional)

# TCPClientTunnel is a tunnel listening on your machine,
# and it forwards any TCP traffic received to the specified target via wireguard.
# Flow:
# <an app on your LAN> --> localhost:25565 --(wireguard)--> play.cubecraft.net:25565
[TCPClientTunnel]
BindAddress = 127.0.0.1:25565
Target = play.cubecraft.net:25565

# TCPServerTunnel is a tunnel listening on wireguard,
# and it forwards any TCP traffic received to the specified target via local network.
# Flow:
# <an app on your wireguard network> --(wireguard)--> 172.16.31.2:3422 --> localhost:25545
[TCPServerTunnel]
ListenPort = 3422
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]
BindAddress = 127.0.0.1:25344

# Socks5 authentication parameters, specifying username and password enables
# proxy authentication.
#Username = ...
# Avoid using spaces in the password field
#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 wireproxy config file like this:

WGConfig = <path to the wireguard config>

# Same semantics as above
[TCPClientTunnel]
...

[TCPServerTunnel]
...

[Socks5]
...

Having multiple peers is also supported. AllowedIPs would need to be specified such that wireproxy would know which peer to forward to.

[Interface]
Address = 10.254.254.40/32
PrivateKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=

[Peer]
Endpoint = 192.168.0.204:51820
PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=
AllowedIPs = 10.254.254.100/32
PersistentKeepalive = 25

[Peer]
PublicKey = ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=
AllowedIPs = 10.254.254.1/32, fdee:1337:c000:d00d::1/128
Endpoint = 172.16.0.185:44044
PersistentKeepalive = 25


[TCPServerTunnel]
ListenPort = 5000
Target = service-one.servicenet:5000

[TCPServerTunnel]
ListenPort = 5001
Target = service-two.servicenet:5001

[TCPServerTunnel]
ListenPort = 5080
Target = service-three.servicenet:80

Wireproxy can also allow peers to connect to it:

[Interface]
ListenPort = 5400
...

[Peer]
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.

Currently two endpoints are implemented:

/metrics: Exposes information of the wireguard daemon, this provides the same information you would get with wg show. This shows an example of what the response would look like.

/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:

[Interface]
PrivateKey = censored
Address = 10.2.0.2/32
DNS = 10.2.0.1
CheckAlive = 1.1.1.1, 3.3.3.3
CheckAliveInterval = 3

[Peer]
PublicKey = censored
AllowedIPs = 0.0.0.0/0
Endpoint = 149.34.244.174:51820

[Socks5]
BindAddress = 127.0.0.1:25344

/readyz would respond with

< HTTP/1.1 503 Service Unavailable
< Date: Thu, 11 Apr 2024 00:54:59 GMT
< Content-Length: 35
< Content-Type: text/plain; charset=utf-8
<
{"1.1.1.1":1712796899,"3.3.3.3":0}

And for:

[Interface]
PrivateKey = censored
Address = 10.2.0.2/32
DNS = 10.2.0.1
CheckAlive = 1.1.1.1

/readyz would respond with

< HTTP/1.1 200 OK
< Date: Thu, 11 Apr 2024 00:56:21 GMT
< Content-Length: 23
< Content-Type: text/plain; charset=utf-8
<
{"1.1.1.1":1712796979}

If nothing is set for CheckAlive, an empty JSON object with 200 will be the response.

The peer which the ICMP ping packet is routed to depends on the AllowedIPs set for each peers.

Stargazers over time

Stargazers over time

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseInterface

func ParseInterface(cfg *ini.File, device *DeviceConfig) error

ParseInterface parses the [Interface] section and extract the information into `device`

func ParsePeerEndpoint

func ParsePeerEndpoint(endpoint string) (host netip.Prefix, port uint16, err error)

func ParsePeers

func ParsePeers(cfg *ini.File, peers *[]PeerConfig) error

ParsePeers parses the [Peer] section and extract the information into `peers`

func TCPAddrFromAddrPort

func TCPAddrFromAddrPort(addr netip.AddrPort) *net.TCPAddr

func ValidateASecConfig

func ValidateASecConfig(config *ASecConfigType) error

Types

type ASecConfigType

type ASecConfigType struct {
	// contains filtered or unexported fields
}

func ParseASecConfig

func ParseASecConfig(section *ini.Section) (*ASecConfigType, error)

type Configuration

type Configuration struct {
	Device   *DeviceConfig
	Routines []RoutineSpawner
}

func Parse

func Parse(cfg *ini.File) (*Configuration, error)

func ParseConfig

func ParseConfig(path string) (*Configuration, error)

ParseConfig takes the path of a configuration file and parses it into Configuration

func ParseConfigString

func ParseConfigString(config string) (*Configuration, error)

ParseConfigString takes the config as a string and parses it into Configuration

type CredentialValidator

type CredentialValidator struct {
	// contains filtered or unexported fields
}

CredentialValidator stores the authentication data of a socks5 proxy

func (CredentialValidator) Valid

func (c CredentialValidator) Valid(username, password string) bool

Valid checks the authentication data in CredentialValidator and compare them to username and password in constant time.

type DeviceConfig

type DeviceConfig struct {
	SecretKey             string
	Address               []netip.Addr
	Peers                 []PeerConfig
	DNS                   []netip.Addr
	SearchDomains         []string
	MTU                   int
	ListenPort            *int
	CheckAlive            []netip.Addr
	DomainBlockingEnabled bool
	BlockedDomains        []string
	CheckAliveInterval    int
	ASecConfig            *ASecConfigType
}

DeviceConfig contains the information to initiate a wireguard connection

type DeviceSetting

type DeviceSetting struct {
	IpcRequest string
	DNS        []netip.Addr
	DeviceAddr []netip.Addr
	MTU        int
}

DeviceSetting contains the parameters for setting up a tun interface

func CreateIPCRequest

func CreateIPCRequest(conf *DeviceConfig, isUpdate bool) (*DeviceSetting, error)

CreateIPCRequest serialize the config into an IPC request and DeviceSetting

func CreatePeerIPCRequest

func CreatePeerIPCRequest(conf *DeviceConfig) (*DeviceSetting, error)

CreatePeerIPCRequest builds a UAPI string for updating peers only, based on the provided DeviceConfig.

type HTTPConfig

type HTTPConfig struct {
	BindAddress string
	Username    string
	Password    string
}

func (*HTTPConfig) SpawnRoutine

func (config *HTTPConfig) SpawnRoutine(ctx context.Context, vt *VirtualTun) error

SpawnRoutine spawns an http server.

type HTTPServer

type HTTPServer struct {
	// contains filtered or unexported fields
}

func (*HTTPServer) ListenAndServe

func (s *HTTPServer) ListenAndServe(ctx context.Context, network, addr string) error

ListenAndServe is used to create a listener and serve on it

type PeerConfig

type PeerConfig struct {
	PublicKey    string
	PreSharedKey string
	Endpoint     *string
	KeepAlive    int
	AllowedIPs   []netip.Prefix
}

func (*PeerConfig) NeedsResolution

func (p *PeerConfig) NeedsResolution() bool

NeedsResolution returns true if the peer's endpoint is a domain name that needs DNS resolution

func (*PeerConfig) UpdateEndpointIP

func (p *PeerConfig) UpdateEndpointIP(resolvedIP netip.Addr) error

UpdateEndpointIP updates the peer's endpoint with the provided resolved IP, preserving the original port.

type RoutineSpawner

type RoutineSpawner interface {
	SpawnRoutine(ctx context.Context, vt *VirtualTun) error
}

RoutineSpawner spawns a routine (e.g. socks5, tcp static routes) after the configuration is parsed

type STDIOTunnelConfig

type STDIOTunnelConfig struct {
	Target string
}

type Socks5Config

type Socks5Config struct {
	BindAddress string
	Username    string
	Password    string
}

func (*Socks5Config) SpawnRoutine

func (config *Socks5Config) SpawnRoutine(ctx context.Context, vt *VirtualTun) error

SpawnRoutine spawns a socks5 server.

type TCPClientTunnelConfig

type TCPClientTunnelConfig struct {
	BindAddress *net.TCPAddr
	Target      string
}

type TCPServerTunnelConfig

type TCPServerTunnelConfig struct {
	ListenPort int
	Target     string
}

type TUNResolver

type TUNResolver struct {
	// contains filtered or unexported fields
}

TUNResolver forwards DNS resolution through the tunnel

func (*TUNResolver) Resolve

func (r *TUNResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error)

Resolve resolves a hostname using DNS over the virtual tunnel interface. It prefers IPv4 (A records), but falls back to IPv6 (AAAA) if no A is found.

type VirtualTun

type VirtualTun struct {
	Tnet   *netstack.Net
	Dev    *device.Device
	Logger *device.Logger
	Uapi   net.Listener
	Conf   *DeviceConfig
	// PingRecord stores the last time an IP was pinged
	PingRecord     map[string]uint64
	PingRecordLock *sync.Mutex
}

VirtualTun stores a reference to netstack network and DNS configuration

func (*VirtualTun) ServeHTTP

func (d *VirtualTun) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*VirtualTun) StartPingIPs

func (d *VirtualTun) StartPingIPs()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL