Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
gwproxy
-------
The GNU/Weeb Proxy. A fast, multi-threaded TCP proxy for GNU/Linux with
SOCKS5, HTTP CONNECT and transparent proxy modes, and optional TLS
termination on the listener (HTTPS proxy).
Features
--------
- Plain TCP-to-TCP forwarding to a fixed --target.
- SOCKS5 proxy (RFC 1928):
- CONNECT to IPv4, IPv6 and domain-name (ATYP) targets.
- UDP ASSOCIATE: relay UDP datagrams to IPv4/IPv6 targets (on both
the epoll and io_uring loops). Datagrams to domain-name targets
are dropped (no per-datagram DNS yet), and the command is refused
when an upstream proxy is configured (UDP is not chained).
- Username/password authentication (RFC 1929), or no authentication.
- HTTP proxy:
- CONNECT tunneling.
- Forwarding of ordinary absolute-form requests
("GET http://host/path"), one request per connection.
- "Basic" proxy authentication (RFC 7617), or no authentication.
- Combined SOCKS5 + HTTP on a single listening port (auto-detected per
connection), sharing one credential store.
- Optional HTTPS proxy: terminate a client's TLS on the listener (server
role, from --tls-cert/--tls-key) and run the SOCKS5/HTTP logic on the
decrypted stream, encrypting the client-to-proxy hop. TLS is
auto-detected from the first byte, so plaintext SOCKS5/HTTP clients keep
working on the same port. Advertises the "http/1.1" ALPN protocol so an
HTTP/2-preferring client is cleanly downgraded. Built only with
--use-openssl; works on both the epoll and io_uring event loops.
- Transparent proxy: recover each connection's original destination from
the SO_ORIGINAL_DST socket option, for use behind an iptables REDIRECT
rule.
- Upstream proxy chaining: route every outgoing connection through a
next-hop SOCKS5 proxy (socks5:// local or socks5h:// remote name
resolution) or HTTP CONNECT proxy (http://), with optional
username/password auth.
- SO_MARK (fwmark) on outgoing connections, for policy routing / iptables
matching.
- Source pinning for outgoing connections: --bind-source binds them to a
chosen source address, --bind-iface to a chosen interface
(SO_BINDTODEVICE), e.g. to send all egress out of a VPN tunnel. Both
are strict (a failed bind drops the connection rather than leaking out
of the wrong path) and are overridden per connection, wholesale, by an
ACL "-j BIND" rule.
- Access-control lists (--acl-file): an iptables-style rule file with
INPUT (client) and OUTPUT (target) chains, CIDR/domain/port matches and
ACCEPT/REJECT/DNAT actions, watched and hot-reloaded on change. The
MARK and BIND modifiers normally keep matching; "--accept" makes one
terminal, so a rule can set the mark or source bind and accept in a
single match rather than repeating the same condition twice.
- Two event loops: epoll (default) and io_uring (optional, enabled at
build time and selected at run time).
- Multi-threaded workers using SO_REUSEPORT, with graceful recovery from
file-descriptor exhaustion (EMFILE/ENFILE).
- Opt-in DNS caching for SOCKS5/HTTP hostname targets (--dns-cache-secs),
bounded by --dns-cache-max-entries; cached IPs are still ACL-checked.
- Per-socket tuning: TCP_NODELAY, TCP_QUICKACK and TCP keepalive.
- Dual-stack IPv4/IPv6 listening.
- Configurable log level and log file, and an optional PID file.
Building gwproxy
----------------
sudo apt install -y git build-essential;
git clone https://github.com/GNUWeeb/gwproxy.git;
cd gwproxy;
make -j$(nproc);
./gwproxy --help;
By default gwproxy is built with the epoll event loop only. To also build
the io_uring event loop (then selectable at run time with
--event-loop=io_uring), configure first:
./configure --use-io-uring;
make -j$(nproc);
To build the optional HTTPS proxy (TLS termination on the listener), install
OpenSSL's development package and configure with --use-openssl:
sudo apt install -y libssl-dev;
./configure --use-openssl;
make -j$(nproc);
To enable PCRE2 regular-expression matches in the access-control list (the
--domain-regexp and --user-regexp rule options), install PCRE2's development
package and configure with --use-pcre:
sudo apt install -y libpcre2-dev;
./configure --use-pcre;
make -j$(nproc);
Other configure options include --debug, --sanitize (ASan/UBSan) and
--use-new-dns-resolver (which enables the -r/--raw-dns and -j/--dns-server
options). Run './configure --help' for the full list. Run 'make test' to
build and run the unit and integration test suites.
Usage
-----
Run './gwproxy --help' for the complete list of options. A few examples:
# Plain TCP forwarder: [::]:8080 -> 127.0.0.1:80
./gwproxy --bind='[::]:8080' --target=127.0.0.1:80
# SOCKS5 proxy (no authentication) on port 1080
./gwproxy --bind='[::]:1080' --as-socks5=1
# SOCKS5 proxy with username/password authentication
./gwproxy --bind='[::]:1080' --as-socks5=1 --auth-file=auth.txt
# HTTP proxy on port 8080 (handles both CONNECT tunnels and forwarding
# of ordinary "GET http://host/path" requests)
./gwproxy --bind='[::]:8080' --as-http=1
# HTTP CONNECT proxy requiring "Basic" authentication
./gwproxy --bind='[::]:8080' --as-http=1 --auth-file=auth.txt
# SOCKS5 and HTTP CONNECT on the same port, sharing one credential file
./gwproxy --bind='[::]:1080' --as-socks5=1 --as-http=1 --auth-file=auth.txt
# HTTPS proxy: terminate the client's TLS on the listener (needs a build
# with --use-openssl). Plaintext SOCKS5/HTTP clients still work on the same
# port. Try it with: curl -x https://127.0.0.1:8080 http://example.com/
./gwproxy --bind='[::]:8080' --as-http=1 --as-socks5=1 \
--tls-cert=cert.pem --tls-key=key.pem
# Chain every outgoing connection through an upstream SOCKS5 proxy
./gwproxy --bind='[::]:1080' --as-socks5=1 \
--upstream-proxy=socks5h://user:pass@1.2.3.4:1080
# Use the io_uring event loop, and set SO_MARK 100 on outgoing packets
./gwproxy --bind='[::]:1080' --as-socks5=1 --event-loop=io_uring --mark=100
# Send every outgoing connection out of the wg0 interface, from that
# tunnel's address. An ACL "-j BIND" rule replaces both of these
# wholesale for the connections it matches.
./gwproxy --bind='[::]:1080' --as-socks5=1 \
--bind-iface=wg0 --bind-source=10.7.0.2
The authentication file (--auth-file)
holds one "username:password" entry per line. The same file is used for
both SOCKS5 (RFC 1929) and HTTP CONNECT ("Basic", RFC 7617) auth; when it
is set, clients of either protocol must present valid credentials. It is
re-read automatically when the file changes.
Transparent proxy mode takes each connection's original destination from
SO_ORIGINAL_DST, so it must sit behind an iptables REDIRECT rule. gwproxy
can mark its own outgoing connections so they are excluded from the
REDIRECT (which avoids a redirect loop):
./gwproxy --bind=127.0.0.1:1080 --as-transparent=1 --mark=1
iptables -t nat -A OUTPUT -p tcp --dport 80 -m mark ! --mark 1 \
-j REDIRECT --to-ports 1080
Note that --mark requires CAP_NET_ADMIN or, since Linux 5.11, CAP_NET_RAW,
and transparent mode requires the iptables rules to be installed; both
typically need root privileges. --bind-iface (SO_BINDTODEVICE) needs no
privilege on Linux 5.7 and later -- older kernels wanted CAP_NET_RAW -- and
--bind-source needs none as long as the address is configured locally.
Contributing
------------
This project is maintained by Ammar Faizi <ammarfaizi2@gnuweeb.org>.
Send your patches to "GNU/Weeb Mailing List" <gwml@vger.gnuweeb.org>.
--
Ammar Faizi