A transparent TCP to SOCKSv5/HTTP proxy on Linux written in Rust

Transparent TCP proxy with iptables -j REDIRECT or nft redirect to

moproxy

A transparent TCP to SOCKSv5/HTTP proxy on Linux written in Rust.

Features:

  • Transparent TCP proxy with iptables -j REDIRECT or nft redirect to
  • Support multiple SOCKSv5/HTTP upstream proxy servers
  • SOCKS/HTTP-layer alive & latency probe
  • Prioritize upstream proxy servers according to latency
  • Full IPv6 support
  • Multiple listen ports, each for a subset of proxy servers
  • Remote DNS resolving for TLS with SNI (extract domain name from TLS handshaking)
  • Optional try-in-parallel for TLS (try multiple proxies and choose the one first response)
  • Optional status web page (latency, traffic, etc. w/ curl-friendly output)
  • Optional Graphite and Prometheus support (to build fancy dashboard with Grafana for example)
  • Customizable proxy selection algorithm with Lua script (see conf/simple_scroe.lua).
+-----+  TCP  +-----------+       SOCKSv5   +---------+
| App |------>| iptables  |    +----------->| Proxy 1 |--->
+-----+       +-----------+    |            +---------+
            redirect |         |
+-----+           to v         |      HTTP  +---------+
| App |       //=========\\    |   +------->| Proxy 2 |--->
+-----+       ||         ||----+   |        +---------+
   |          || MOPROXY ||--------+             :
   +--------->||         ||-----------···        :
   SOCKSv5    \\=========// choose one  |   +---------+
                                        +-->| Proxy N |--->
                                            +---------+

Usage

Print usage

moproxy --help

Examples

Assume there are three SOCKSv5 servers on localhost:2001, localhost:2002, and localhost:2003, and two HTTP proxy servers listen on localhost:3128 and 192.0.2.0:3128. Following commands forward all TCP connections that connect to 80 and 443 to these proxy servers.

moproxy --port 2080 --socks5 2001 2002 2003 --http 3128 192.0.2.0:3128

# redirect local-initiated connections
nft add rule nat output tcp dport {80, 443} redirect to 2080
# redirect connections initiated by other hosts (if you are router)
nft add rule nat prerouting tcp dport {80, 443} redirect to 2080

# or the legacy iptables equivalent
iptables -t nat -A OUTPUT -p tcp -m multiport --dports 80,443 -j REDIRECT --to-port 2080
iptables -t nat -A PREROUTING -p tcp -m multiport --dports 80,443 -j REDIRECT --to-port 2080

SOCKSv5 server is also launched alongs with transparent proxy on the same port:

http_proxy=socks5h://localhost:2080 curl ifconfig.co

Server list file

You may list all proxy servers in a text file to avoid messy CLI arguments.

[server-1]
address=127.0.0.1:2001 ;required
protocol=socks5 ;required

[server-2]
address=127.0.0.1:2002
protocol=http
test dns=127.0.0.53:53 ;use remote's local dns server to caculate delay
listen ports=8001

[server-3]
address=127.0.0.1:2003
protocol=http
; server-3 serves for port 8001 & 8002, while server-2 is only for
; port 8001. server-1 accepts connections coming from any ports specified
; by CLI argument --port.
listen ports=8001,8002

[backup]
address=127.0.0.1:2002
protocol=socks5
score base=5000 ;add 5k to pull away from preferred server.

Pass the file path to moproxy via --list argument.

Signal SIGHUP will trigger the program to reload the list.

Custom proxy selection

Proxy servers are sorted by their score, which is re-calculated after each round of alive/latency probing. Server with lower score is prioritized.

The current scoring algorithm is a kind of weighted moving average of latency with penalty for recent connection errors. This can be replaced with your own algorithm written in Lua. See conf/simple_score.lua for details.

Source/destination address–based proxy selection is not directly supported. One workaround is let moproxy bind multiple ports, delegates each port to different proxy servers with listen ports in your config, then doing address-based selection on your firewall.

Monitoring

Metrics (latency, traffic, number of connections, etc.) are useful for diagnosis and customing your own proxy selection. You can access these metrics with various methods, from a simple web page, curl, to specialized tools like Graphite or Prometheus.

--stats-bind [::1]:8080 turns on the internal stats page, via HTTP, on the given IP address and port number. It returns a HTML page for web browser, or a ASCII table for curl.

The stats page only provides current metrics and a few aggregations. Graphite (via --graphite) or Prometheus (via --stats-bind then \metrics) should be used if you want a full history.

Some examples of Prometheus query (Grafana variant):

Inbound bandwith:
rate(moproxy_proxy_server_bytes_rx_total[$__range])

Total outbound traffic:
sum(increase(moproxy_proxy_server_bytes_tx_total[$__range]))

No. of connection errors per minute:
sum(increase(moproxy_proxy_server_connections_error[1m]))

Average delay for each proxy server:
avg_over_time(moproxy_proxy_server_dns_delay_seconds[$__interval])

Systemd integration

Sample service file: conf/moproxy.service

Implemented features:

  • Watchdog
  • Reloading (via SIGHUP signal)
  • Notify (type=notify, reloading, status string)

Get simple status without turing on the HTTP stats page:

$ systemctl status moproxy
> ...
> Status: "serving (7/11 upstream proxies up)"
> ...

Install

You may download the binary executable file on releases page.

Arch Linux user can install it from AUR/moproxy.

Or compile it manually:

# Install Rust
curl https://sh.rustup.rs -sSf | sh

# Clone source code
git clone https://github.com/sorz/moproxy
cd moproxy

# Build
cargo build --release
target/release/moproxy --help

# If you are in Debian
cargo install cargo-deb
cargo deb
sudo dpkg -i target/debian/*.deb
moproxy --help

Refer to conf/ for config & systemd service files.

Issues

Collection of the latest Issues

Versions

Find the latest versions by id

v0.3.10 - Dec 07, 2021

Changelog:

  • Show status of upstream proxies on systemctl status
  • Make metrics exporter /metrics compatible with OpenMetrics 1.0.0
  • Reduce binary size

Contributors:

  • @ahxxm

v0.3.9 - Apr 15, 2021

  • Fix some half-closed TCP may hang on forever
  • Fix build error on some non-Linux Unix platform (e.g. Android)
  • Adjust logging levels
  • Remove build-time dependency OpenSSL

v0.3.8 - Dec 24, 2020

  • Fix Windows build

v0.3.7 - Dec 24, 2020

Changelog:

  • Support upstream HTTP basic authentication (thanks @except)
  • Use larger shared buffers (may improve the forwarding performance)
  • Updated moproxy-web:
    • Persistent settings
    • htop-like colorful traffic amount
  • Other mirror changes

Contributors:

  • @except

v0.3.6 - Jul 30, 2020

  • Add --max-wait option to customize connection timeout
  • Support upstream SOCKSv5 username/password authentication

v0.3.5 - Jul 06, 2020

  • New web status page built with modern technology (standalone repo moproxy-web)
  • Fix config reload (SIGHUP signal) missed listen ports

v0.3.4 - Jun 17, 2020

  • Reduce surplus warning logging
  • Fix traffic variables on Lua script
  • Improve data forwarding performance (hopefully)

v0.3.3 - Apr 22, 2020

  • Feature: add Prometheus exporter
  • Fix direct-connect fallback on SOCKSv5 incoming request
  • Experimental support for non-Linux OSes

v0.3.2 - Apr 03, 2020

  • Feature: multiple listen ports

v0.3.1 - Mar 12, 2020

  • Feature: accept SOCKSv5 server along with transparent proxy (experimental)
  • Feature: better integrated with systemd (block-when-reload and wathdog support)
  • Fix dead lock when reload with proxy servers specified via inline CLI argument
  • Other minor changes

v0.3.0 - Nov 08, 2019

Rust 1.39.0 or above is required.

v0.3.0-alpha.1 to v0.3.0

  • Feature: custom scoring calculation via Lua script (experimental)
  • Give penalty for continuous connection errors on the default scoring

v0.2.7 to v0.3.0-alpha.1

  • Feature: --allow-direct, fallback to direct connecting when all proxy servers were down.
  • Bind on IPv6 address [::] by default
  • Keep stats info of servers after reloaded
  • Migrate to async/await Rust
  • Other mirror improvement

v0.3.0-alpha.1 - Sep 25, 2019

  • New feature: --allow-direct, fallback to direct connecting when all proxy servers were down.
  • Bind on IPv6 address [::] by default
  • Keep stats info of servers after reloaded
  • Migrate to async/await Rust
  • Other mirror improvement

v0.2.7 - Jul 30, 2019

Fix IPv6 support

v0.2.6 - Jul 11, 2019

  • Feature: plaintext status page for curl and Lynx (#3)
  • Fix: implement correct SOCKSv5 protocol (#2)
  • Fix: deadlock when reload server list file (a97ff1a0d20cc4ba7fc7a2b3b0f1c6903d4c33da)

v0.2.5 - Dec 18, 2018

  • Feature: allow to reload server list via SIGHUP
  • Hyper (the HTTP server) becomes optional
  • Reuse the TCP connection with Graphite server

v0.2.4 - Nov 20, 2018

  • Add connection statistics to graphite
  • Fix mirror errors

v0.2.3 - Aug 15, 2018

  • Feature: IPv6 support on local listener
  • Feature: send metrics (delay, scores, and thoughputs) to Graphite

v0.2.2 - May 13, 2018

  • Update dependences, compatible with Rust 1.26

v0.2.1 - Feb 09, 2018

  • Feature: show throughput for each single server
  • Feature: allow to set TCP congestion control algorithm for local connections

v0.2.0 - Jan 19, 2018

  • Remove --systemd
  • Improved logs
  • Other minor changes

v0.1.7 - Dec 29, 2017

  • Feature: web server can listen on UNIX domain socket.
  • Feature: show uptime on status page.
  • Fix: waiting too long on delay test sometimes.

v0.1.6 - Dec 20, 2017

  • Add systemd startup nofity support
  • Add example configuartion

Mainly for packaging, not need to update to this version if you are using v0.1.5.

v0.1.5 - Dec 19, 2017

  • Feature: throughput on status page.
  • Fix connection error in some cases with TLS support enabled.
  • Other minor improvement.

v0.1.4 - Dec 15, 2017

  • Better web console: improved traffic statistics, auto refresh, and no JS library anymore.
  • Some refactors…

v0.1.3 - Dec 11, 2017

  • Feature: remote dns for TLS with SNI (--remote-dns)
  • Feature: try multiple proxies in parallel and use fastest one (--n-parallel N)
  • Adjust score calculating

v0.1.2 - Dec 07, 2017

  • Show number of connections, traffic in bytes, and others on the web page;
  • Allow custom DNS servers used to delay probe;
  • Other minor improvements.

v0.1.1 - Nov 29, 2017

Initial release

Information - Updated Feb 11, 2022

Stars: 145
Forks: 18
Issues: 1

Repositories & Extras

pancurses is a curses library for Rust that supports both Linux and Windows

by abstracting away the backend that it uses

pancurses is a curses library for Rust that supports both Linux and Windows

Native Rust library for managing Linux Control Groups (cgroups)

This crate, curently, only supports the original, V1 hierarchy

Native Rust library for managing Linux Control Groups (cgroups)

The Rust spidev seeks to provide full access to the Linux spidev

The following is not an exhaustive demonstration of the Spidev

The Rust spidev seeks to provide full access to the Linux spidev

a minimal Linux kernel module written in rust

A recent build of Rust (latest nightly)

a minimal Linux kernel module written in rust

Rust Linux Worker

The Service executes arbitrary Linux commands on behalf of clients

Rust Linux Worker

Direct, unsafe Rust bindings for Linux's perf_event_open system call

This crate exports unsafe Rust wrappers for Linux system calls for accessing

Direct, unsafe Rust bindings for Linux's perf_event_open system call

A safe, sane Rust interface to libseccomp on Linux

Note: This is not a high-level interface; most functions/methods in this library directly correspond to a libseccomp function

A safe, sane Rust interface to libseccomp on Linux

Linux-Device-Driver-Rust

This is a twain Repo of Linux-Device-Driver is a long time work in which I rewrite all examples in

Linux-Device-Driver-Rust

Simple, performant hot-reloading for Rust

Requires Rust nightly and only works on Linux and Windows for now

Simple, performant hot-reloading for Rust
Facebook Instagram Twitter GitHub Dribbble
Privacy