Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

388 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages