libproxyproto - LD_PRELOAD library for adding support for proxy protocol v2
- server
LD_PRELOAD=libproxyproto.so COMMAND ARG ...
- test client
LD_PRELOAD=libproxyproto_connect.so COMMAND ARG ...
libproxyproto provides a method for applications to discover the original client IP adddress and port of proxied connections. The application must be dynamically linked.
Intermediary proxies add a binary protocol header before the application data using the proxy protocol:
https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt
Both proxy proxy protocol v1 and v2 are supported.
When the connection is accept(2)
'ed, libproxyproto:
- intercepts the call to
accept(2)
- reads the proxy protocol header
- sets the source IP address and port in the
struct sockaddr
argument ofaccept(2)
libproxyproto_connect does the same thing for calls to connect(2)
and can be used for testing.
LIBPROXYPROTO_DEBUG
: Write errors to stderr (default: disabled).
LIBPROXYPROTO_MUST_USE_PROTOCOL_HEADER
: By default, connections without the proxy protocol header are
allowed. Enabling this option drops connections without a protocol header
(default: disabled).
LIBPROXYPROTO_VERSION
: Supported proxy protocol version (default: 3):
0: proxy protocol disabled
1: proxy protocol v1 only
2: proxy protocol v2 only
3: proxy protocol v1 and v2
LIBPROXYPROTO_ADDR
: Source IP address (default: 127.0.0.1)
LIBPROXYPROTO_PORT
: Source port (default: 8080)
LIBPROXYPROTO_VERSION
: Supported proxy protocol version (default: 2):
0: proxy protocol disabled
1: proxy protocol v1
2: proxy protocol v2
# run in a shell
LD_PRELOAD=libproxyproto.so nc -vvvv -k -l 9090
# in another shell
LD_PRELOAD=libproxyproto_connect.so \
LIBPROXYPROTO_ADDR="8.8.8.8" LIBPROXYPROTO_PORT="4321" \
nc 127.0.0.1 9090
# test haproxy
# server: LD_PRELOAD=libproxyproto.so nc -vvvv -k -l 9090
defaults
mode tcp
timeout connect 4s
timeout client 30s
timeout server 30s
listen example
bind :8080
server test 127.0.0.1:9090 send-proxy-v2
To give a very rough idea of the overhead, a benchmark was run against an echo service.
This benchmark is not meant to be conclusive:
- run over the loopback
- on an old system running many other services
tcpkali -c 50 -T 10s -e1 'PROXY TCP4 127.0.0.1 127.0.0.1 \{connection.uid} 25578\r\n' -m 'PING\r\n' 127.0.0.1:1122
To run:
erlc echo.erl
# no proxy: run on port 1122
erl -noshell -eval "echo:start()"
# libproxyproto: run on port 1122
LD_PRELOAD=libproxyproto.so erl -noshell -eval "echo:start()"
# go-mmproxy: run on port 1123
erl -noshell -eval "echo:start(1123)"
sudo ./go-mmproxy -l 0.0.0.0:1122 -4 127.0.0.1:1123
-module(echo).
-export([start/0, start/1]).
start() ->
start(1122).
start(Port) ->
{ok, S} = gen_tcp:listen(Port, [
binary,
{reuseaddr, true},
{backlog, 1024}
]),
accept(S).
accept(LS) ->
{ok, S} = gen_tcp:accept(LS),
Pid = spawn(fun() -> recv(S) end),
_ = gen_tcp:controlling_process(S, Pid),
accept(LS).
recv(S) ->
receive
{tcp, S, Data} ->
gen_tcp:send(S, Data),
recv(S);
{tcp_closed, S} ->
ok;
Error ->
error_logger:error_report([{socket, S}, {error, Error}])
end.
⇅ Mbps | ↓ Mbps | ↑ Mbps | ↓ pkt/s | ↑ pkt/s | |
---|---|---|---|---|---|
noproxy | 98.238 | 2455.263 | 2456.626 | 229245.6 | 210847.5 |
libproxyproto | 94.974 | 2373.474 | 2375.247 | 221341.9 | 203862.9 |
go-mmproxy | 76.567 | 1901.043 | 1927.293 | 163515.0 | 165415.9 |
Bandwidth per channel: ⇅ Mbps Aggregate bandwidth: ↓, ↑ Mbps Packet rate estimate: ↓, ↑
connect(2), accept(2)