MINOR: quic: handle perm error on bind during runtime

Improve EACCES permission errors encounterd when using QUIC connection
socket at runtime :

* First occurence of the error on the process will generate a log
  warning. This should prevent users from using a privileged port
  without mandatory access rights.

* Socket mode will automatically fallback to listener socket for the
  receiver instance. This requires to duplicate the settings from the
  bind_conf to the receiver instance to support configurations with
  multiple addresses on the same bind line.
This commit is contained in:
Amaury Denoyelle 2023-10-03 16:11:40 +02:00
parent 3ef6df7387
commit 2ac5d9a657
4 changed files with 26 additions and 3 deletions

View File

@ -28,6 +28,7 @@
#include <haproxy/api-t.h>
#include <haproxy/namespace-t.h>
#include <haproxy/proto_reverse_connect-t.h>
#include <haproxy/quic_sock-t.h>
#include <haproxy/thread.h>
/* Bit values for receiver->flags */
@ -79,6 +80,7 @@ struct receiver {
struct list proto_list; /* list in the protocol header */
#ifdef USE_QUIC
struct mt_list rxbuf_list; /* list of buffers to receive and dispatch QUIC datagrams. */
enum quic_sock_mode quic_mode; /* QUIC socket allocation strategy */
#endif
struct {
struct task *task; /* Task used to open connection for reverse. */

View File

@ -645,6 +645,11 @@ static int quic_bind_listener(struct listener *listener, char *errmsg, int errle
goto udp_return;
}
/* Duplicate quic_mode setting from bind_conf. Useful to overwrite it
* at runtime per receiver instance.
*/
listener->rx.quic_mode = listener->bind_conf->quic_mode;
/* Set IP_PKTINFO to retrieve destination address on recv. */
fd = listener->rx.fd;
switch (addr.ss_family) {

View File

@ -1264,7 +1264,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
conn_id->qc = qc;
if (l->bind_conf->quic_mode == QUIC_SOCK_MODE_CONN &&
if (HA_ATOMIC_LOAD(&l->rx.quic_mode) == QUIC_SOCK_MODE_CONN &&
(global.tune.options & GTUNE_QUIC_SOCK_PER_CONN) &&
is_addr(local_addr)) {
TRACE_USER("Allocate a socket for QUIC connection", QUIC_EV_CONN_INIT, qc);

View File

@ -46,6 +46,9 @@
#define TRACE_SOURCE &trace_quic
/* Log only first EACCES bind() error runtime occurence. */
static volatile char quic_bind_eacces_warn = 0;
/* Retrieve a connection's source address. Returns -1 on failure. */
int quic_sock_get_src(struct connection *conn, struct sockaddr *addr, socklen_t len)
{
@ -812,7 +815,8 @@ int qc_rcv_buf(struct quic_conn *qc)
void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
const struct sockaddr_storage *dst)
{
struct proxy *p = qc->li->bind_conf->frontend;
struct bind_conf *bc = qc->li->bind_conf;
struct proxy *p = bc->frontend;
int fd = -1;
int ret;
@ -854,8 +858,20 @@ void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
goto err;
ret = bind(fd, (struct sockaddr *)src, get_addr_len(src));
if (ret < 0)
if (ret < 0) {
if (errno == EACCES) {
if (!quic_bind_eacces_warn) {
send_log(p, LOG_WARNING,
"Permission error on QUIC socket binding for proxy %s. Consider using setcap cap_net_bind_service (Linux only) or running as root.\n",
p->id);
quic_bind_eacces_warn = 1;
}
/* Fallback to listener socket for this receiver instance. */
HA_ATOMIC_STORE(&qc->li->rx.quic_mode, QUIC_SOCK_MODE_LSTNR);
}
goto err;
}
ret = connect(fd, (struct sockaddr *)dst, get_addr_len(dst));
if (ret < 0)