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).
This commit is contained in:
Willy Tarreau 2022-04-11 18:04:33 +02:00
parent 0e9c264ca0
commit e22267971b
4 changed files with 13 additions and 7 deletions

View File

@ -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

View File

@ -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.
*/

View File

@ -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. */

View File

@ -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);
}