From 2ac5d9a6573791a6fe4e959afc40657ff06b0aed Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 3 Oct 2023 16:11:40 +0200 Subject: [PATCH] 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. --- include/haproxy/receiver-t.h | 2 ++ src/proto_quic.c | 5 +++++ src/quic_conn.c | 2 +- src/quic_sock.c | 20 ++++++++++++++++++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/haproxy/receiver-t.h b/include/haproxy/receiver-t.h index f7c934726e..e21f06b190 100644 --- a/include/haproxy/receiver-t.h +++ b/include/haproxy/receiver-t.h @@ -28,6 +28,7 @@ #include #include #include +#include #include /* 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. */ diff --git a/src/proto_quic.c b/src/proto_quic.c index 22776cd83c..73a48e44ba 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -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) { diff --git a/src/quic_conn.c b/src/quic_conn.c index a2d28c7b04..f2957f4eda 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -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); diff --git a/src/quic_sock.c b/src/quic_sock.c index 1cbb71f9e2..3b3c3a7a28 100644 --- a/src/quic_sock.c +++ b/src/quic_sock.c @@ -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)