From 6905498d60627ef189cd8cbfcace95117fc02b6f Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Wed, 10 Sep 2025 12:14:41 +0200 Subject: [PATCH] proxyprotocol on client-side can be removed on server side, and its info is then logged --- common.c | 26 ++++++++++++++++++++++---- common.h | 1 + proxyprotocol.c | 19 +++++++++++++++++++ proxyprotocol.h | 2 ++ t/run | 11 +++++++++++ t/test_pp2.cfg | 2 ++ tcp-probe.c | 9 ++++----- version.h | 2 +- 8 files changed, 62 insertions(+), 10 deletions(-) diff --git a/common.c b/common.c index 6701678..bc086e5 100644 --- a/common.c +++ b/common.c @@ -514,10 +514,21 @@ void connect_addr(struct connection *cnx, int fd_from, connect_blocking blocking cnx->q[1].fd = fd; if (cnx->proto->proxyprotocol_is_present) { - pp_write_header(cnx->proto->proxyprotocol, cnx); - /* If pp_write_header() fails, it already logs a message and there is - * nothing much we can do. The server side will probably close the - * connection */ + if (cnx->proto->proxyprotocol) { + pp_write_header(cnx->proto->proxyprotocol, cnx); + /* If pp_write_header() fails, it already logs a message and there is + * nothing much we can do. The server side will probably close the + * connection */ + } else { + /* proxyprotocol == 0 means we remove a proxyprotocol header from + * the client-side, and log PP information (as it will be lost + * after sslh) */ + int pp_len = pp_log_connection(cnx->q[1].begin_deferred_data, + cnx->q[1].deferred_data_size); + if (pp_len > 0) { + defer_skip(&cnx->q[1], pp_len); + } + } } } @@ -540,6 +551,13 @@ int defer_write(struct queue *q, void* data, ssize_t data_size) return 0; } +/* skip (remove) some data from the head of the queue */ +void defer_skip(struct queue *q, ssize_t data_size) +{ + q->deferred_data += data_size; + q->deferred_data_size -= data_size; +} + /* Store some data to write *before* what's already in the queue */ int defer_write_before(struct queue *q, void* data, ssize_t data_size) { diff --git a/common.h b/common.h index 4166b84..e56bd1e 100644 --- a/common.h +++ b/common.h @@ -184,6 +184,7 @@ int resolve_split_name(struct addrinfo **out, char* hostname, char* port); int start_listen_sockets(struct listen_endpoint *sockfd[]); int defer_write(struct queue *q, void* data, ssize_t data_size); +void defer_skip(struct queue *q, ssize_t data_size); int defer_write_before(struct queue *q, void* data, ssize_t data_size); int flush_deferred(struct queue *q); diff --git a/proxyprotocol.c b/proxyprotocol.c index 08cd847..d163ae4 100644 --- a/proxyprotocol.c +++ b/proxyprotocol.c @@ -133,6 +133,25 @@ int pp_write_header(int pp_version, struct connection* cnx) return 0; } +/* Logs the connection data in the pp header and return header length */ +int pp_log_connection(char* buffer, ssize_t buffer_len) +{ + pp_info_t pp_info; + + int header_len = pp_parse_hdr((uint8_t*)buffer, buffer_len, &pp_info); + + if (header_len > 0) { + print_message(msg_connections, "client had proxyprotocol info: %s:%d to %s:%d not forwarded to server\n", + pp_info.src_addr, pp_info.src_port, + pp_info.dst_addr, pp_info.dst_port); + } else { + print_message(msg_connections, "no proxyprotocol data found on client side, forwarding as is\n"); + header_len = 0; + } + + return header_len; +} + int pp_header_len(char* buffer, int buffer_len) { pp_info_t pp_info; diff --git a/proxyprotocol.h b/proxyprotocol.h index 39b843d..19523b6 100644 --- a/proxyprotocol.h +++ b/proxyprotocol.h @@ -6,12 +6,14 @@ int pp_write_header(int pp_version, struct connection* cnx); +int pp_log_connection(char* buffer, ssize_t buffer_len); int pp_header_len(char* buffer, int len); #else /* HAVE_PROXYPROTOCOL */ static inline int pp_write_header(int pp_version, struct connection* cnx) { return 0; } +static int pp_log_connection(char* buffer, ssize_t buffer_len) { return 0; } static inline int pp_header_len(char*, int) { return 0; } #endif /* HAVE_PROXYPROTOCOL */ diff --git a/t/run b/t/run index f2f77ef..e507b12 100755 --- a/t/run +++ b/t/run @@ -346,6 +346,17 @@ my @tests = ( expected => "ssh", }, + # test_pp2.cfg has proxyprotocol on port 8080 but + # removes it towards "regex_remove_pp" tarbet + # TODO: Log the addresses! + { + desc => "Client-side ProxyProtocol active but removed", + run => \&run_test_probe, + cfg => "test_pp2.cfg", + data => "PROXY TCP4 127.0.0.1 127.0.0.1 8080 8081\x0D\x0Aregex_remove_pp hello", + expected => "regex", + data_expected => "^regex_remove_pp hello", + }, ); diff --git a/t/test_pp2.cfg b/t/test_pp2.cfg index 749e716..b496367 100644 --- a/t/test_pp2.cfg +++ b/t/test_pp2.cfg @@ -38,6 +38,8 @@ protocols: ( { name: "ssh"; host: "localhost"; port: "9000"; }, { name: "socks5"; host: "localhost"; port: "9001"; }, + { name: "regex"; host: "localhost"; port: "9002"; + regex_patterns: [ "^regex_remove_pp" ]; proxyprotocol: 0; }, { name: "anyprot"; host: "localhost"; port: "9099"; } ); diff --git a/tcp-probe.c b/tcp-probe.c index 7fc32bd..811ac5b 100644 --- a/tcp-probe.c +++ b/tcp-probe.c @@ -50,12 +50,11 @@ int probe_client_protocol(struct connection *cnx) hexdump(msg_packets, cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size); - /* - TODO il ne faut appeler ca que si on supporte pp sur le lien - */ - - int pp_len = pp_header_len(cnx->q[1].begin_deferred_data, + size_t pp_len = 0; + if (cnx->endpoint->endpoint_cfg->proxyprotocol) { + pp_len = pp_header_len(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size); + } return probe_buffer(cnx->q[1].begin_deferred_data + pp_len, cnx->q[1].deferred_data_size - pp_len, diff --git a/version.h b/version.h index dcf9f0b..6cd6507 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION "v2.1.4-42-g4978641-dirty" +#define VERSION "v2.2.4-52-geea50a9-dirty" #endif