PROXY Stream transport

This commit adds a new stream-based transport with an interface
compatible with TCP. The transport is built on top of TCP transport
and the new PROXYv2 handling code. Despite being built on top of TCP,
it can be easily extended to work on top of any TCP-like stream-based
transport. The intention of having this transport is to add PROXYv2
support into all existing stream-based DNS transport (DNS over TCP,
DNS over TLS, DNS over HTTP) by making the work on top of this new
transport.

The idea behind the transport is simple after accepting the connection
or connecting to a remote server it enters PROXYv2 handling mode: that
is, it either attempts to read (when accepting the connection) or send
(when establishing a connection) a PROXYv2 header. After that it works
like a mere wrapper on top of the underlying stream-based
transport (TCP).
This commit is contained in:
Artem Boldariev
2023-03-16 12:50:04 +02:00
parent 7d9a8ddc00
commit d119d666b3
6 changed files with 1647 additions and 4 deletions

View File

@@ -106,6 +106,7 @@ libisc_la_SOURCES = \
$(libisc_la_HEADERS) \
netmgr/netmgr-int.h \
netmgr/netmgr.c \
netmgr/proxystream.c \
netmgr/socket.c \
netmgr/streamdns.c \
netmgr/tcp.c \

View File

@@ -21,6 +21,7 @@
#include <isc/refcount.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/tls.h>
#include <isc/types.h>
@@ -87,6 +88,21 @@ typedef void (*isc_nm_opaquecb_t)(void *arg);
* callbacks.
*/
typedef struct isc_nm_proxyheader_info {
bool complete;
union {
isc_region_t complete_header; /* complete header data */
struct {
isc_sockaddr_t src_addr;
isc_sockaddr_t dst_addr;
isc_region_t tlv_data;
} proxy_info; /* information to put into the new header */
};
} isc_nm_proxyheader_info_t;
/*%<
* Information to put into the PROXYv2 header when establishing a connection.
*/
void
isc_netmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t **netgmrp);
/*%<
@@ -229,6 +245,29 @@ isc_nmhandle_localaddr(isc_nmhandle_t *handle);
* Return the local address for the given handle.
*/
isc_sockaddr_t
isc_nmhandle_real_peeraddr(isc_nmhandle_t *handle);
/*%<
* Return the real (as seen by the OS) peer address for the given
* handle even when PROXY protocol is used.
*
* NOTE: This function is intended mostly for a) implementing PROXYv2
* access control facilities and b) logging. Using it for anything
* else WILL break PROXYv2 support. Please consider using
* 'isc_nmhandle_peeraddr()' instead.
*/
isc_sockaddr_t
isc_nmhandle_real_localaddr(isc_nmhandle_t *handle);
/*%<
* Return the real (as seen by the OS) local address for the given
* handle even when PROXY protocol is used.
*
* NOTE: This function is intended mostly for a) implementing PROXYv2
* access control facilities and b) logging. Using it for anything
* else WILL break PROXYv2 support. Please consider using
* 'isc_nmhandle_localaddr()' instead.
*/
isc_nm_t *
isc_nmhandle_netmgr(isc_nmhandle_t *handle);
/*%<
@@ -391,6 +430,68 @@ isc_nm_listenstreamdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
* 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
*/
isc_result_t
isc_nm_listenproxystream(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
int backlog, isc_quota_t *quota,
isc_nmsocket_t **sockp);
/*%<
* Start listening for data preceded by a PROXYv2 header over the
* TCP on interface 'iface', using net manager 'mgr'.
*
* On success, 'sockp' will be updated to contain a new listening TCP
* socket.
*
* When connection is accepted on the socket, 'accept_cb' will be called with
* 'accept_cbarg' as its argument. The callback is expected to start a read.
*
* If 'quota' is not NULL, then the socket is attached to the specified
* quota. This allows us to enforce TCP client quota limits.
*/
void
isc_nm_proxystreamconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
unsigned int timeout,
isc_nm_proxyheader_info_t *proxy_info);
/*%<
* Create a TCP socket using netmgr 'mgr', bind it to the address
* 'local', and connect it to the address 'peer'. Right after the
* connection has been established, send PROXYv2 header using the
* information provided via the 'proxy_info' to the remote peer. Then
* the connection is considered established.
*
* If 'proxy_info' is omitted, then a LOCAL PROXYv2 header is sent.
*
* When the connection is established or has timed out, call 'cb' with
* argument 'cbarg'.
*
* 'timeout' specifies the timeout interval in milliseconds.
*
* The connected socket can only be accessed via the handle passed to
* 'cb'.
*/
void
isc_nm_proxyheader_info_init(isc_nm_proxyheader_info_t *restrict info,
isc_sockaddr_t *restrict src_addr,
isc_sockaddr_t *restrict dst_addr,
isc_region_t *restrict tlv_data);
/*%<
* Initialize a 'isc_nm_proxyheader_info_t' object with user
* provided addresses and a TLVs blob, that can be omitted (the rest
* of the data is REQUIRE()d).
*/
void
isc_nm_proxyheader_info_init_complete(isc_nm_proxyheader_info_t *restrict info,
isc_region_t *restrict header_data);
/*%<
* Initialize a 'isc_nm_proxyheader_info_t' with user provided data
* blob (e.g. a pre-rendered PROXYv2 header for forwarding or
* testing).
*/
void
isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
uint32_t keepalive, uint32_t advertised);
@@ -499,6 +600,19 @@ isc_nm_is_http_handle(isc_nmhandle_t *handle);
* 'isc_nm_httpsocket'.
*/
bool
isc_nm_is_proxy_unspec(isc_nmhandle_t *handle);
/*%<
* Returns 'true' iff 'handle' is associated with a peer who send
* a PROXYv2 header with unsupported address type.
*/
bool
isc_nm_is_proxy_handle(isc_nmhandle_t *handle);
/*%< Returns 'true' iff 'handle' is associated is with a PROXYv2
* connection.
*/
isc_result_t
isc_nm_listentls(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg, int backlog,

View File

@@ -98,13 +98,15 @@ typedef enum isc_nmsocket_type {
isc_nm_tlssocket = 1 << 3,
isc_nm_httpsocket = 1 << 4,
isc_nm_streamdnssocket = 1 << 5,
isc_nm_proxystreamsocket = 1 << 6,
isc_nm_maxsocket,
isc_nm_udplistener, /* Aggregate of nm_udpsocks */
isc_nm_tcplistener,
isc_nm_tlslistener,
isc_nm_httplistener,
isc_nm_streamdnslistener
isc_nm_streamdnslistener,
isc_nm_proxystreamlistener
} isc_nmsocket_type;
typedef isc_nmsocket_type isc_nmsocket_type_t;

View File

@@ -26,6 +26,7 @@
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/proxy2.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
@@ -111,6 +112,9 @@ STATIC_ASSERT(ISC_NETMGR_TCP_RECVBUF_SIZE <= ISC_NETMGR_RECVBUF_SIZE,
#define ISC_NM_NMHANDLES_MAX 64
#define ISC_NM_UVREQS_MAX 64
/*% ISC_PROXY2_MIN_AF_UNIX_SIZE is the largest type when TLVs are not used */
#define ISC_NM_PROXY2_DEFAULT_BUFFER_SIZE (ISC_PROXY2_MIN_AF_UNIX_SIZE)
/*
* Define ISC_NETMGR_TRACE to activate tracing of handles and sockets.
* This will impair performance but enables us to quickly determine,
@@ -244,6 +248,7 @@ struct isc_nmhandle {
isc_sockaddr_t peer;
isc_sockaddr_t local;
bool proxy_is_unspec;
isc_nm_opaquecb_t doreset; /* reset extra callback, external */
isc_nm_opaquecb_t dofree; /* free extra callback, external */
#if ISC_NETMGR_TRACE
@@ -536,6 +541,20 @@ struct isc_nmsocket {
bool dot_alpn_negotiated;
const char *tls_verify_error;
} streamdns;
struct {
isc_nmsocket_t *sock;
bool reading;
size_t nsending;
void *send_req;
union {
isc_proxy2_handler_t *handler; /* server */
isc_buffer_t *outbuf; /* client */
} proxy2;
bool header_processed;
bool extra_processed; /* data arrived past header processed */
} proxy;
/*%
* pquota is a non-attached pointer to the TCP client quota, stored in
* listening sockets.
@@ -1136,6 +1155,71 @@ void
isc__nm_streamdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
bool
isc__nm_valid_proxy_addresses(const isc_sockaddr_t *src,
const isc_sockaddr_t *dst);
void
isc__nm_proxystream_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
void
isc__nm_proxystream_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_proxystream_cleanup_data(isc_nmsocket_t *sock);
void
isc__nmhandle_proxystream_cleartimeout(isc_nmhandle_t *handle);
void
isc__nmhandle_proxystream_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nmhandle_proxystream_keepalive(isc_nmhandle_t *handle, bool value);
void
isc__nmhandle_proxystream_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout);
void
isc__nmsocket_proxystream_reset(isc_nmsocket_t *sock);
bool
isc__nmsocket_proxystream_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_proxystream_timer_restart(isc_nmsocket_t *sock);
void
isc__nmsocket_proxystream_timer_stop(isc_nmsocket_t *sock);
void
isc__nmhandle_proxystream_set_manual_timer(isc_nmhandle_t *handle,
const bool manual);
isc_result_t
isc__nmhandle_proxystream_set_tcp_nodelay(isc_nmhandle_t *handle,
const bool value);
void
isc__nm_proxystream_read_stop(isc_nmhandle_t *handle);
void
isc__nm_proxystream_close(isc_nmsocket_t *sock);
void
isc__nm_proxystream_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
void *cbarg);
void
isc__nm_proxystream_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_proxystream_senddns(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_incstats(isc_nmsocket_t *sock, isc__nm_statid_t id);
/*%<
@@ -1323,6 +1407,14 @@ void
isc__nmhandle_log(const isc_nmhandle_t *handle, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
void
isc__nm_received_proxy_header_log(isc_nmhandle_t *handle,
const isc_proxy2_command_t cmd,
const int socktype,
const isc_sockaddr_t *restrict src_addr,
const isc_sockaddr_t *restrict dst_addr,
const isc_region_t *restrict tlvs);
void
isc__nmhandle_set_manual_timer(isc_nmhandle_t *handle, const bool manual);
/*

View File

@@ -28,6 +28,7 @@
#include <isc/loop.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/netmgr.h>
#include <isc/quota.h>
#include <isc/random.h>
@@ -319,6 +320,10 @@ isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) {
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_setwritetimeout(handle, write_timeout);
break;
case isc_nm_proxystreamsocket:
isc__nmhandle_proxystream_setwritetimeout(handle,
write_timeout);
break;
default:
UNREACHABLE();
break;
@@ -469,6 +474,7 @@ nmsocket_cleanup(void *arg) {
isc__nm_http_cleanup_data(sock);
#endif
isc__nm_streamdns_cleanup_data(sock);
isc__nm_proxystream_cleanup_data(sock);
if (sock->barriers_initialised) {
isc_barrier_destroy(&sock->listen_barrier);
@@ -601,6 +607,9 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
isc__nm_http_close(sock);
return;
#endif
case isc_nm_proxystreamsocket:
isc__nm_proxystream_close(sock);
return;
default:
break;
}
@@ -645,7 +654,8 @@ isc_nmsocket_close(isc_nmsocket_t **sockp) {
(*sockp)->type == isc_nm_tcplistener ||
(*sockp)->type == isc_nm_streamdnslistener ||
(*sockp)->type == isc_nm_tlslistener ||
(*sockp)->type == isc_nm_httplistener);
(*sockp)->type == isc_nm_httplistener ||
(*sockp)->type == isc_nm_proxystreamlistener);
isc__nmsocket_detach(sockp);
}
@@ -844,6 +854,7 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t const *peer,
FALLTHROUGH;
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
case isc_nm_proxystreamsocket:
INSIST(sock->statichandle == NULL);
/*
@@ -875,7 +886,8 @@ isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
return (handle->sock->type == isc_nm_tcpsocket ||
handle->sock->type == isc_nm_tlssocket ||
handle->sock->type == isc_nm_httpsocket ||
handle->sock->type == isc_nm_streamdnssocket);
handle->sock->type == isc_nm_streamdnssocket ||
handle->sock->type == isc_nm_proxystreamsocket);
}
static void
@@ -1030,6 +1042,9 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) {
case isc_nm_streamdnssocket:
isc__nm_streamdns_failed_read_cb(sock, result, async);
return;
case isc_nm_proxystreamsocket:
isc__nm_proxystream_failed_read_cb(sock, result, async);
return;
default:
UNREACHABLE();
}
@@ -1133,6 +1148,9 @@ isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_timer_restart(sock);
return;
case isc_nm_proxystreamsocket:
isc__nmsocket_proxystream_timer_restart(sock);
return;
default:
break;
}
@@ -1176,6 +1194,8 @@ isc__nmsocket_timer_running(isc_nmsocket_t *sock) {
return (isc__nmsocket_tls_timer_running(sock));
case isc_nm_streamdnssocket:
return (isc__nmsocket_streamdns_timer_running(sock));
case isc_nm_proxystreamsocket:
return (isc__nmsocket_proxystream_timer_running(sock));
default:
break;
}
@@ -1207,6 +1227,9 @@ isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_timer_stop(sock);
return;
case isc_nm_proxystreamsocket:
isc__nmsocket_proxystream_timer_stop(sock);
return;
default:
break;
}
@@ -1228,6 +1251,7 @@ isc___nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr FLARG) {
switch (sock->type) {
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
case isc_nm_proxystreamsocket:
#if ISC_NETMGR_TRACE
isc_nmhandle__attach(sock->statichandle,
&req->handle FLARG_PASS);
@@ -1380,6 +1404,9 @@ isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) {
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_cleartimeout(handle);
return;
case isc_nm_proxystreamsocket:
isc__nmhandle_proxystream_cleartimeout(handle);
return;
default:
handle->sock->read_timeout = 0;
@@ -1406,6 +1433,9 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_settimeout(handle, timeout);
return;
case isc_nm_proxystreamsocket:
isc__nmhandle_proxystream_settimeout(handle, timeout);
return;
default:
handle->sock->read_timeout = timeout;
isc__nmsocket_timer_restart(handle->sock);
@@ -1446,6 +1476,9 @@ isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) {
isc__nmhandle_http_keepalive(handle, value);
break;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_proxystreamsocket:
isc__nmhandle_proxystream_keepalive(handle, value);
break;
default:
/*
* For any other protocol, this is a no-op.
@@ -1559,6 +1592,9 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
isc__nm_http_send(handle, region, cb, cbarg);
break;
#endif
case isc_nm_proxystreamsocket:
isc__nm_proxystream_send(handle, region, cb, cbarg);
break;
default:
UNREACHABLE();
}
@@ -1576,6 +1612,9 @@ isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
case isc_nm_tlssocket:
isc__nm_tls_senddns(handle, region, cb, cbarg);
break;
case isc_nm_proxystreamsocket:
isc__nm_proxystream_senddns(handle, region, cb, cbarg);
break;
default:
UNREACHABLE();
}
@@ -1603,6 +1642,9 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc__nm_http_read(handle, cb, cbarg);
break;
#endif
case isc_nm_proxystreamsocket:
isc__nm_proxystream_read(handle, cb, cbarg);
break;
default:
UNREACHABLE();
}
@@ -1654,6 +1696,9 @@ isc_nm_read_stop(isc_nmhandle_t *handle) {
case isc_nm_tlssocket:
isc__nm_tls_read_stop(handle);
break;
case isc_nm_proxystreamsocket:
isc__nm_proxystream_read_stop(handle);
break;
default:
UNREACHABLE();
}
@@ -1690,6 +1735,9 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
isc__nm_http_stoplistening(sock);
break;
#endif
case isc_nm_proxystreamlistener:
isc__nm_proxystream_stoplistening(sock);
break;
default:
UNREACHABLE();
}
@@ -1702,7 +1750,8 @@ isc__nmsocket_stop(isc_nmsocket_t *listener) {
REQUIRE(listener->tid == 0);
REQUIRE(listener->type == isc_nm_httplistener ||
listener->type == isc_nm_tlslistener ||
listener->type == isc_nm_streamdnslistener);
listener->type == isc_nm_streamdnslistener ||
listener->type == isc_nm_proxystreamlistener);
REQUIRE(!listener->closing);
listener->closing = true;
@@ -1833,6 +1882,9 @@ isc__nmsocket_reset(isc_nmsocket_t *sock) {
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_reset(sock);
return;
case isc_nm_proxystreamsocket:
isc__nmsocket_proxystream_reset(sock);
return;
default:
UNREACHABLE();
break;
@@ -2042,6 +2094,7 @@ isc_nm_bad_request(isc_nmhandle_t *handle) {
case isc_nm_tcpsocket:
case isc_nm_streamdnssocket:
case isc_nm_tlssocket:
case isc_nm_proxystreamsocket:
REQUIRE(sock->parent == NULL);
isc__nmsocket_reset(sock);
return;
@@ -2085,6 +2138,162 @@ isc_nm_is_http_handle(isc_nmhandle_t *handle) {
return (handle->sock->type == isc_nm_httpsocket);
}
static isc_nmhandle_t *
get_proxy_handle(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
sock = handle->sock;
switch (sock->type) {
case isc_nm_proxystreamsocket:
return (handle);
default:
break;
}
if (sock->outerhandle == NULL) {
return NULL;
}
return (get_proxy_handle(sock->outerhandle));
}
bool
isc_nm_is_proxy_handle(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
return (get_proxy_handle(handle) != NULL);
}
bool
isc_nm_is_proxy_unspec(isc_nmhandle_t *handle) {
isc_nmhandle_t *proxyhandle;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
if (handle->sock->client) {
return (false);
}
proxyhandle = get_proxy_handle(handle);
if (proxyhandle == NULL) {
return (false);
}
return (proxyhandle->proxy_is_unspec);
}
isc_sockaddr_t
isc_nmhandle_real_peeraddr(isc_nmhandle_t *handle) {
isc_sockaddr_t addr = { 0 };
isc_nmhandle_t *proxyhandle;
REQUIRE(VALID_NMHANDLE(handle));
proxyhandle = get_proxy_handle(handle);
if (proxyhandle == NULL) {
return (isc_nmhandle_peeraddr(handle));
}
INSIST(VALID_NMSOCK(proxyhandle->sock));
if (isc_nmhandle_is_stream(proxyhandle)) {
addr = isc_nmhandle_peeraddr(proxyhandle->sock->outerhandle);
} else {
/* TODO: PROXY over UDP */
UNREACHABLE();
}
return (addr);
}
isc_sockaddr_t
isc_nmhandle_real_localaddr(isc_nmhandle_t *handle) {
isc_sockaddr_t addr = { 0 };
isc_nmhandle_t *proxyhandle;
REQUIRE(VALID_NMHANDLE(handle));
proxyhandle = get_proxy_handle(handle);
if (proxyhandle == NULL) {
return (isc_nmhandle_localaddr(handle));
}
INSIST(VALID_NMSOCK(proxyhandle->sock));
if (isc_nmhandle_is_stream(proxyhandle)) {
addr = isc_nmhandle_localaddr(proxyhandle->sock->outerhandle);
} else {
/* TODO: PROXY over UDP */
UNREACHABLE();
}
return (addr);
}
bool
isc__nm_valid_proxy_addresses(const isc_sockaddr_t *src,
const isc_sockaddr_t *dst) {
struct in_addr inv4 = { 0 };
struct in6_addr inv6 = { 0 };
isc_netaddr_t zerov4 = { 0 }, zerov6 = { 0 };
isc_netaddr_t src_addr = { 0 }, dst_addr = { 0 };
if (src == NULL || dst == NULL) {
return (false);
}
/*
* We should not allow using 0 in source addresses as well, but we
* have a precedent of a tool that issues port 0 in the source
* addresses (kdig).
*/
if (isc_sockaddr_getport(dst) == 0) {
return (false);
}
/*
* Anybody using zeroes in source or destination addresses is not
* a friend. Considering that most of the upper level code is
* written with consideration that bot source and destination
* addresses are returned by the OS and should be valid, we should
* discard so suspicious addresses. Also, keep in mind that both
* "0.0.0.0" and "::" match all interfaces when using as listener
* addresses.
*/
isc_netaddr_fromin(&zerov4, &inv4);
isc_netaddr_fromin6(&zerov6, &inv6);
isc_netaddr_fromsockaddr(&src_addr, src);
isc_netaddr_fromsockaddr(&dst_addr, dst);
INSIST(isc_sockaddr_pf(src) == isc_sockaddr_pf(dst));
switch (isc_sockaddr_pf(src)) {
case AF_INET:
if (isc_netaddr_equal(&src_addr, &zerov4)) {
return (false);
}
if (isc_netaddr_equal(&dst_addr, &zerov4)) {
return (false);
}
break;
case AF_INET6:
if (isc_netaddr_equal(&src_addr, &zerov6)) {
return (false);
}
if (isc_netaddr_equal(&dst_addr, &zerov6)) {
return (false);
}
break;
default:
UNREACHABLE();
}
return (true);
}
void
isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) {
isc_nmsocket_t *sock = NULL;
@@ -2110,6 +2319,7 @@ isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) {
break;
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
case isc_nm_proxystreamsocket:
default:
UNREACHABLE();
break;
@@ -2157,6 +2367,10 @@ isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
case isc_nm_tlssocket:
return (isc__nm_tls_verify_tls_peer_result_string(handle));
break;
case isc_nm_proxystreamsocket:
return (isc__nm_proxystream_verify_tls_peer_result_string(
handle));
break;
#if HAVE_LIBNGHTTP2
case isc_nm_httpsocket:
return (isc__nm_http_verify_tls_peer_result_string(handle));
@@ -2351,6 +2565,96 @@ isc__nmhandle_log(const isc_nmhandle_t *handle, int level, const char *fmt,
isc__nmsocket_log(handle->sock, level, "handle %p: %s", handle, msgbuf);
}
void
isc__nm_received_proxy_header_log(isc_nmhandle_t *handle,
const isc_proxy2_command_t cmd,
const int socktype,
const isc_sockaddr_t *restrict src_addr,
const isc_sockaddr_t *restrict dst_addr,
const isc_region_t *restrict tlvs) {
const int log_level = ISC_LOG_DEBUG(1);
isc_sockaddr_t real_local, real_peer;
char real_local_fmt[ISC_SOCKADDR_FORMATSIZE] = { 0 };
char real_peer_fmt[ISC_SOCKADDR_FORMATSIZE] = { 0 };
char common_msg[512] = { 0 };
const char *proto = NULL;
const char *real_addresses_msg =
"real source and destination addresses are used";
if (!isc_log_wouldlog(isc_lctx, log_level)) {
return;
}
if (isc_nmhandle_is_stream(handle)) {
proto = isc_nm_has_encryption(handle) ? "TLS" : "TCP";
} else {
proto = "UDP";
}
real_local = isc_nmhandle_real_localaddr(handle);
real_peer = isc_nmhandle_real_peeraddr(handle);
isc_sockaddr_format(&real_local, real_local_fmt,
sizeof(real_local_fmt));
isc_sockaddr_format(&real_peer, real_peer_fmt, sizeof(real_peer_fmt));
(void)snprintf(common_msg, sizeof(common_msg),
"Received a PROXYv2 header from %s on %s over %s",
real_peer_fmt, real_local_fmt, proto);
if (cmd == ISC_PROXY2_CMD_LOCAL) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_DEFAULT,
ISC_LOGMODULE_NETMGR, log_level,
"%s: command: LOCAL (%s)", common_msg,
real_addresses_msg);
return;
} else if (cmd == ISC_PROXY2_CMD_PROXY) {
const char *tlvs_msg = tlvs == NULL ? "no" : "yes";
const char *socktype_name = NULL;
const char *src_addr_msg = "(none)", *dst_addr_msg = "(none)";
char src_addr_fmt[ISC_SOCKADDR_FORMATSIZE] = { 0 };
char dst_addr_fmt[ISC_SOCKADDR_FORMATSIZE] = { 0 };
switch (socktype) {
case 0:
isc_log_write(isc_lctx, ISC_LOGCATEGORY_DEFAULT,
ISC_LOGMODULE_NETMGR, log_level,
"%s: command: PROXY (unspecified address "
"and socket type, %s)",
common_msg, real_addresses_msg);
return;
case SOCK_STREAM:
socktype_name = "SOCK_STREAM";
break;
case SOCK_DGRAM:
socktype_name = "SOCK_DGRAM";
break;
default:
UNREACHABLE();
}
if (src_addr) {
isc_sockaddr_format(src_addr, src_addr_fmt,
sizeof(src_addr_fmt));
src_addr_msg = src_addr_fmt;
}
if (dst_addr) {
isc_sockaddr_format(dst_addr, dst_addr_fmt,
sizeof(dst_addr_fmt));
dst_addr_msg = dst_addr_fmt;
}
isc_log_write(isc_lctx, ISC_LOGCATEGORY_DEFAULT,
ISC_LOGMODULE_NETMGR, log_level,
"%s: command: PROXY, socket type: %s, source: "
"%s, destination: %s, TLVs: %s",
common_msg, socktype_name, src_addr_msg,
dst_addr_msg, tlvs_msg);
}
}
void
isc__nmhandle_set_manual_timer(isc_nmhandle_t *handle, const bool manual) {
REQUIRE(VALID_NMHANDLE(handle));
@@ -2365,6 +2669,9 @@ isc__nmhandle_set_manual_timer(isc_nmhandle_t *handle, const bool manual) {
case isc_nm_tlssocket:
isc__nmhandle_tls_set_manual_timer(handle, manual);
return;
case isc_nm_proxystreamsocket:
isc__nmhandle_proxystream_set_manual_timer(handle, manual);
return;
default:
break;
};
@@ -2409,6 +2716,10 @@ isc_nmhandle_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value) {
case isc_nm_tlssocket:
result = isc__nmhandle_tls_set_tcp_nodelay(handle, value);
break;
case isc_nm_proxystreamsocket:
result = isc__nmhandle_proxystream_set_tcp_nodelay(handle,
value);
break;
default:
UNREACHABLE();
break;
@@ -2423,6 +2734,36 @@ isc_nmsocket_getaddr(isc_nmsocket_t *sock) {
return (sock->iface);
}
void
isc_nm_proxyheader_info_init(isc_nm_proxyheader_info_t *restrict info,
isc_sockaddr_t *restrict src_addr,
isc_sockaddr_t *restrict dst_addr,
isc_region_t *restrict tlv_data) {
REQUIRE(info != NULL);
REQUIRE(src_addr != NULL);
REQUIRE(dst_addr != NULL);
REQUIRE(tlv_data == NULL ||
(tlv_data->length > 0 && tlv_data->base != NULL));
*info = (isc_nm_proxyheader_info_t){ .proxy_info.src_addr = *src_addr,
.proxy_info.dst_addr = *dst_addr };
if (tlv_data != NULL) {
info->proxy_info.tlv_data = *tlv_data;
}
}
void
isc_nm_proxyheader_info_init_complete(isc_nm_proxyheader_info_t *restrict info,
isc_region_t *restrict header_data) {
REQUIRE(info != NULL);
REQUIRE(header_data != NULL);
REQUIRE(header_data->base != NULL &&
header_data->length >= ISC_PROXY2_HEADER_SIZE);
*info = (isc_nm_proxyheader_info_t){ .complete = true,
.complete_header = *header_data };
}
#if ISC_NETMGR_TRACE
/*
* Dump all active sockets in netmgr. We output to stderr
@@ -2452,6 +2793,10 @@ nmsocket_type_totext(isc_nmsocket_type type) {
return ("isc_nm_streamdnslistener");
case isc_nm_streamdnssocket:
return ("isc_nm_streamdnssocket");
case isc_nm_proxystreamlistener:
return ("isc_nm_proxystreamlistener");
case isc_nm_proxystreamsocket:
return ("isc_nm_proxystreamsocket");
default:
UNREACHABLE();
}

1089
lib/isc/netmgr/proxystream.c Normal file

File diff suppressed because it is too large Load Diff