From: Willy Tarreau Date: Tue, 15 Sep 2020 15:41:56 +0000 (+0200) Subject: MEDIUM: tools: make str2sa_range() resolve pre-bound listeners X-Git-Tag: v2.3-dev5~33 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6edc7220937250a7a2d86bc420b879f80065f518;p=thirdparty%2Fhaproxy.git MEDIUM: tools: make str2sa_range() resolve pre-bound listeners When str2sa_range() is invoked for a bind or log line, and it gets a file descriptor number, it will immediately resolve the socket's address (when it's a socket) so that the address family, address and port are correctly set. This will later allow to resolve some transport protocols that are attached to existing FDs. For raw FDs (e.g. logs) and for socket pairs, the FD number is still returned in the address, because we need the underlying address management to complete the bind/listen/connect/whatever needed. One immediate benefit is that passing a bad FD will now result in one of these errors: 'bind' : cannot use file descriptor '3' : Socket operation on non-socket. 'bind' : socket on file descriptor '3' is of the wrong type. Note that as of now, we never return a listening socket with a family of AF_CUST_EXISTING_FD. The only case where this family is seen is for a raw FD (e.g. logs). --- diff --git a/src/tools.c b/src/tools.c index 9fffc70299..db17fda0c2 100644 --- a/src/tools.c +++ b/src/tools.c @@ -963,8 +963,31 @@ struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, int goto out; } - ((struct sockaddr_in *)&ss)->sin_addr.s_addr = new_fd; - ((struct sockaddr_in *)&ss)->sin_port = 0; + if (opts & PA_O_SOCKET_FD) { + socklen_t addr_len; + int type; + + addr_len = sizeof(ss); + if (getsockname(new_fd, (struct sockaddr *)&ss, &addr_len) == -1) { + memprintf(err, "cannot use file descriptor '%d' : %s.\n", new_fd, strerror(errno)); + goto out; + } + + addr_len = sizeof(type); + if (getsockopt(new_fd, SOL_SOCKET, SO_TYPE, &type, &addr_len) != 0 || + (type == SOCK_STREAM) != !!(opts & PA_O_STREAM)) { + memprintf(err, "socket on file descriptor '%d' is of the wrong type.\n", new_fd); + goto out; + } + + porta = portl = porth = get_host_port(&ss); + } else if (opts & PA_O_RAW_FD) { + ((struct sockaddr_in *)&ss)->sin_addr.s_addr = new_fd; + ((struct sockaddr_in *)&ss)->sin_port = 0; + } else { + memprintf(err, "a file descriptor is not acceptable here in '%s'\n", str); + goto out; + } } else if (ss.ss_family == AF_UNIX) { struct sockaddr_un *un = (struct sockaddr_un *)&ss;