mirror of
https://github.com/yrutschle/sslh.git
synced 2025-04-08 05:10:05 +03:00
add support for proxyprotocol v1 on backend server side
This commit is contained in:
parent
951b708f61
commit
24c3bb07a0
34
common.c
34
common.c
@ -18,6 +18,7 @@
|
||||
#include "probe.h"
|
||||
#include "log.h"
|
||||
#include "sslh-conf.h"
|
||||
#include "proxyprotocol.h"
|
||||
|
||||
#if HAVE_LIBCAP
|
||||
#include <sys/capability.h>
|
||||
@ -480,8 +481,11 @@ static int connect_unix(struct connection *cnx, int fd_from, connect_blocking bl
|
||||
/*
|
||||
* Connect to the first backend server address that works and updates the *cnx
|
||||
* object accordingly (in cnx->q[1].fd). Set that to -1 in case of failure.
|
||||
*
|
||||
* If transparent proxying is on, use fd_from peer address on external address
|
||||
* of new file descriptor. */
|
||||
* of new file descriptor.
|
||||
* If proxyprotocol is used, write header on new backend server connection
|
||||
* */
|
||||
void connect_addr(struct connection *cnx, int fd_from, connect_blocking blocking)
|
||||
{
|
||||
int fd;
|
||||
@ -492,6 +496,13 @@ void connect_addr(struct connection *cnx, int fd_from, connect_blocking blocking
|
||||
fd = connect_inet(cnx, fd_from, blocking);
|
||||
}
|
||||
cnx->q[1].fd = fd;
|
||||
|
||||
if (cnx->proto->proxyprotocol_is_present) {
|
||||
int res = 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 */
|
||||
}
|
||||
}
|
||||
|
||||
/* Store some data to write to the queue later */
|
||||
@ -513,6 +524,27 @@ int defer_write(struct queue *q, void* data, ssize_t data_size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
char *p;
|
||||
|
||||
print_message(msg_fd, "writing deferred to beginning on fd %d\n", q->fd);
|
||||
p = malloc(q->deferred_data_size + data_size);
|
||||
CHECK_ALLOC(p, "malloc");
|
||||
|
||||
memcpy(p, data, data_size);
|
||||
memcpy(p + data_size, q->deferred_data, q->deferred_data_size);
|
||||
|
||||
free(q->begin_deferred_data);
|
||||
|
||||
q->begin_deferred_data = p;
|
||||
q->deferred_data = p;
|
||||
q->deferred_data_size += (int)data_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tries to flush some of the data for specified queue
|
||||
* Upon success, the number of bytes written is returned.
|
||||
* Upon failure, -1 returned (e.g. connexion closed)
|
||||
|
1
common.h
1
common.h
@ -175,6 +175,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);
|
||||
int defer_write_before(struct queue *q, void* data, ssize_t data_size);
|
||||
int flush_deferred(struct queue *q);
|
||||
|
||||
extern struct sslhcfg_item cfg;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Dec 22 22:40:51 2024.
|
||||
* on Mon Feb 24 18:37:24 2025.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2024 Yves Rutschle
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Dec 22 22:40:51 2024.
|
||||
* on Mon Feb 24 18:37:24 2025.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2024 Yves Rutschle
|
||||
|
92
proxyprotocol.c
Normal file
92
proxyprotocol.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
# proxyprotocol: Support for HAProxy's proxyprotocol
|
||||
#
|
||||
# Copyright (C) 2025 Yves Rutschle
|
||||
#
|
||||
# This program is free software; you can redistribute it
|
||||
# and/or modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be
|
||||
# useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# The full text for the General Public License is here:
|
||||
# http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
*/
|
||||
|
||||
#include <proxy_protocol.h>
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
/* Converts socket family to libproxyprotocol family */
|
||||
static int family_to_pp(int af_family)
|
||||
{
|
||||
switch (af_family) {
|
||||
case AF_INET:
|
||||
return ADDR_FAMILY_INET;
|
||||
|
||||
case AF_INET6:
|
||||
return ADDR_FAMILY_INET6;
|
||||
|
||||
case AF_UNIX:
|
||||
return ADDR_FAMILY_UNIX;
|
||||
|
||||
default:
|
||||
print_message(msg_int_error, "Unknown internal socket family %d\n", af_family);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int pp_write_header(int pp_version, struct connection* cnx)
|
||||
{
|
||||
pp_info_t pp_info_in_v1 = {
|
||||
.transport_protocol = TRANSPORT_PROTOCOL_STREAM,
|
||||
};
|
||||
uint16_t pp1_hdr_len;
|
||||
int32_t error;
|
||||
|
||||
struct sockaddr_storage ss;
|
||||
struct addrinfo addr;
|
||||
char host[NI_MAXHOST], serv[NI_MAXSERV];
|
||||
int res;
|
||||
|
||||
addr.ai_addr = (struct sockaddr*)&ss;
|
||||
addr.ai_addrlen = sizeof(ss);
|
||||
|
||||
res = getpeername(cnx->q[0].fd, addr.ai_addr, &addr.ai_addrlen);
|
||||
res = getnameinfo(addr.ai_addr, addr.ai_addrlen,
|
||||
host, sizeof(host),
|
||||
serv, sizeof(serv),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV );
|
||||
memcpy(pp_info_in_v1.src_addr, host, sizeof(pp_info_in_v1.src_addr));
|
||||
pp_info_in_v1.src_port = atoi(serv);
|
||||
pp_info_in_v1.address_family = family_to_pp(addr.ai_addr->sa_family);
|
||||
|
||||
res = getpeername(cnx->q[1].fd, addr.ai_addr, &addr.ai_addrlen);
|
||||
res = getnameinfo(addr.ai_addr, addr.ai_addrlen,
|
||||
host, sizeof(host),
|
||||
serv, sizeof(serv),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV );
|
||||
memcpy(pp_info_in_v1.dst_addr, host, sizeof(pp_info_in_v1.dst_addr));
|
||||
pp_info_in_v1.dst_port = atoi(serv);
|
||||
|
||||
uint8_t *pp1_hdr = pp_create_hdr(pp_version, &pp_info_in_v1, &pp1_hdr_len, &error);
|
||||
|
||||
if (!pp1_hdr) {
|
||||
print_message(msg_system_error, "pp_create_hrd:%d:%s\n", error, pp_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
defer_write_before(&cnx->q[1], pp1_hdr, pp1_hdr_len);
|
||||
|
||||
pp_info_clear(&pp_info_in_v1);
|
||||
free(pp1_hdr);
|
||||
|
||||
return 0;
|
||||
}
|
15
proxyprotocol.h
Normal file
15
proxyprotocol.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PROXYPROTOCOL_H
|
||||
#define PROXYPROTOCOL_H
|
||||
|
||||
|
||||
#if HAVE_PROXYPROTOCOL
|
||||
int pp_write_header(int pp_version, struct connection* cnx);
|
||||
|
||||
|
||||
#else /* HAVE_PROXYPROTOCOL */
|
||||
|
||||
static inline int pp_write_header(int pp_version, struct connection* cnx) {}
|
||||
|
||||
#endif /* HAVE_PROXYPROTOCOL */
|
||||
|
||||
#endif /* PROXYPROTOCOL_H */
|
25
sslh-conf.c
25
sslh-conf.c
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Dec 22 22:40:51 2024.
|
||||
* on Mon Feb 24 18:37:24 2025.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2024 Yves Rutschle
|
||||
@ -500,7 +500,7 @@ struct arg_file* sslhcfg_conffile;
|
||||
struct arg_str* sslhcfg_anyprot;
|
||||
struct arg_end* sslhcfg_end;
|
||||
|
||||
|
||||
|
||||
static struct config_desc table_sslhcfg_protocols[] = {
|
||||
|
||||
|
||||
@ -775,6 +775,22 @@ static struct config_desc table_sslhcfg_protocols[] = {
|
||||
/* optional */ 1,
|
||||
/* default_val*/ .default_val.def_int = 0
|
||||
},
|
||||
|
||||
{
|
||||
/* name */ "proxyprotocol",
|
||||
/* type */ CFG_INT,
|
||||
/* sub_group*/ NULL,
|
||||
/* arg_cl */ NULL,
|
||||
/* base_addr */ NULL,
|
||||
/* offset */ offsetof(struct sslhcfg_protocols_item, proxyprotocol),
|
||||
/* offset_len */ 0,
|
||||
/* offset_present */ offsetof(struct sslhcfg_protocols_item, proxyprotocol_is_present),
|
||||
/* size */ sizeof(int),
|
||||
/* array_type */ -1,
|
||||
/* mandatory */ 0,
|
||||
/* optional */ 1,
|
||||
/* default_val*/ .default_val.def_int = 0
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -2427,6 +2443,11 @@ static void sslhcfg_protocols_fprint(
|
||||
if (! sslhcfg_protocols->minlength_is_present)
|
||||
fprintf(out, " <unset>");
|
||||
fprintf(out, "\n");
|
||||
indent(out, depth);
|
||||
fprintf(out, "proxyprotocol: %d", sslhcfg_protocols->proxyprotocol);
|
||||
if (! sslhcfg_protocols->proxyprotocol_is_present)
|
||||
fprintf(out, " <unset>");
|
||||
fprintf(out, "\n");
|
||||
}
|
||||
|
||||
static void sslhcfg_listen_fprint(
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Dec 22 22:40:51 2024.
|
||||
* on Mon Feb 24 18:37:24 2025.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2024 Yves Rutschle
|
||||
@ -71,6 +71,8 @@ struct sslhcfg_protocols_item {
|
||||
char** regex_patterns;
|
||||
int minlength_is_present;
|
||||
int minlength;
|
||||
int proxyprotocol_is_present;
|
||||
int proxyprotocol;
|
||||
T_PROBE* probe;
|
||||
struct addrinfo* saddr;
|
||||
void* data;
|
||||
|
@ -136,6 +136,7 @@ config: {
|
||||
element_type: "string"
|
||||
},
|
||||
{ name: "minlength"; type: "int"; optional: true },
|
||||
{ name: "proxyprotocol"; type: "int"; optional: true },
|
||||
|
||||
# Runtime data
|
||||
{ name: "probe"; type: "runtime"; c_type: "T_PROBE*" },
|
||||
|
2
test.cfg
2
test.cfg
@ -45,7 +45,7 @@ protocols:
|
||||
(
|
||||
{ name: "ssh"; host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true; },
|
||||
{ name: "socks5"; host: "localhost"; port: "9001"; },
|
||||
{ name: "http"; is_unix: true; host: "/tmp/nginx.sock"; port: ""; },
|
||||
{ name: "http"; host: "www.lemonde.fr"; port: "80"; proxyprotocol: 1; },
|
||||
{ name: "tinc"; host: "localhost"; port: "9003"; },
|
||||
{ name: "openvpn"; host: "localhost"; port: "9004"; },
|
||||
{ name: "xmpp"; host: "localhost"; port: "9009"; },
|
||||
|
Loading…
x
Reference in New Issue
Block a user