From: Willy Tarreau Date: Mon, 11 Apr 2022 16:04:33 +0000 (+0200) Subject: MINOR: connection: skip FD-based syscalls for FD-less connections X-Git-Tag: v2.6-dev6~134 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e22267971b7c1a09cfb95fba6e300d32ee01ac70;p=thirdparty%2Fhaproxy.git MINOR: connection: skip FD-based syscalls for FD-less connections Some syscalls at the TCP level act directly on the FD. Some of them are used by TCP actions like set-tos, set-mark, silent-drop, others try to retrieve TCP info, get the source or destination address. These ones must not be called with an invalid FD coming from an FD-less connection, so let's add the relevant tests for this. It's worth noting that all these ones already have fall back plans (do nothing, error, or switch to alternate implementation). --- diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index f6407ff4b2..5d9b5ca748 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -352,7 +352,8 @@ static inline int conn_get_src(struct connection *conn) if (!sockaddr_alloc(&conn->src, NULL, 0)) return 0; - if (conn->ctrl->fam->get_src(conn->handle.fd, (struct sockaddr *)conn->src, + if (conn->ctrl->fam->get_src && !(conn->flags & CO_FL_FDLESS) && + conn->ctrl->fam->get_src(conn->handle.fd, (struct sockaddr *)conn->src, sizeof(*conn->src), obj_type(conn->target) != OBJ_TYPE_LISTENER) == -1) return 0; @@ -375,7 +376,8 @@ static inline int conn_get_dst(struct connection *conn) if (!sockaddr_alloc(&conn->dst, NULL, 0)) return 0; - if (conn->ctrl->fam->get_dst(conn->handle.fd, (struct sockaddr *)conn->dst, + if (conn->ctrl->fam->get_dst && !(conn->flags & CO_FL_FDLESS) && + conn->ctrl->fam->get_dst(conn->handle.fd, (struct sockaddr *)conn->dst, sizeof(*conn->dst), obj_type(conn->target) != OBJ_TYPE_LISTENER) == -1) return 0; @@ -389,7 +391,7 @@ static inline int conn_get_dst(struct connection *conn) */ static inline void conn_set_tos(const struct connection *conn, int tos) { - if (!conn || !conn_ctrl_ready(conn)) + if (!conn || !conn_ctrl_ready(conn) || (conn->flags & CO_FL_FDLESS)) return; #ifdef IP_TOS @@ -412,7 +414,7 @@ static inline void conn_set_tos(const struct connection *conn, int tos) */ static inline void conn_set_mark(const struct connection *conn, int mark) { - if (!conn || !conn_ctrl_ready(conn)) + if (!conn || !conn_ctrl_ready(conn) || (conn->flags & CO_FL_FDLESS)) return; #if defined(SO_MARK) @@ -429,7 +431,7 @@ static inline void conn_set_mark(const struct connection *conn, int mark) */ static inline void conn_set_quickack(const struct connection *conn, int value) { - if (!conn || !conn_ctrl_ready(conn)) + if (!conn || !conn_ctrl_ready(conn) || (conn->flags & CO_FL_FDLESS)) return; #ifdef TCP_QUICKACK diff --git a/src/tcp_act.c b/src/tcp_act.c index ecb33d9f3a..04400d2107 100644 --- a/src/tcp_act.c +++ b/src/tcp_act.c @@ -290,6 +290,9 @@ static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct if (strm) strm->csf->si->flags |= SI_FL_NOLINGER; + if (conn->flags & CO_FL_FDLESS) + goto out; + /* We're on the client-facing side, we must force to disable lingering to * ensure we will use an RST exclusively and kill any pending data. */ diff --git a/src/tcp_sample.c b/src/tcp_sample.c index 895a1306fd..53e3d1e01f 100644 --- a/src/tcp_sample.c +++ b/src/tcp_sample.c @@ -332,7 +332,8 @@ static inline int get_tcp_info(const struct arg *args, struct sample *smp, /* The fd may not be available for the tcp_info struct, and the syscal can fail. */ optlen = sizeof(info); - if (getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1) + if ((conn->flags & CO_FL_FDLESS) || + getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1) return 0; /* extract the value. */ diff --git a/src/tcpcheck.c b/src/tcpcheck.c index 1926311f7f..6e995a0ea0 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -1210,7 +1210,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec ssl_sock_set_alpn(conn, (unsigned char *)s->check.alpn_str, s->check.alpn_len); #endif - if (conn_ctrl_ready(conn) && (connect->options & TCPCHK_OPT_LINGER)) { + if (conn_ctrl_ready(conn) && (connect->options & TCPCHK_OPT_LINGER) && !(conn->flags & CO_FL_FDLESS)) { /* Some servers don't like reset on close */ HA_ATOMIC_AND(&fdtab[conn->handle.fd].state, ~FD_LINGER_RISK); }