diff options
| author | Felix Fietkau | 2026-02-13 08:50:58 +0000 |
|---|---|---|
| committer | Felix Fietkau | 2026-02-13 09:02:45 +0000 |
| commit | 0efa2cd3b74ca295362341f7b21f0449066141f5 (patch) | |
| tree | 95eaa58c36f176351c5dd92951b48d7b57923ba1 | |
| parent | 5ec7ff2effb36bed32de122629b8c1404bd5157a (diff) | |
| download | libubox-0efa2cd3b74ca295362341f7b21f0449066141f5.tar.gz | |
usock: check SO_ERROR after poll in usock_inet_timeout()
After poll() returns with POLLOUT on a non-blocking connect, the
connection may have failed (ECONNREFUSED, ENETUNREACH, etc.). Check
the socket error via getsockopt(SO_ERROR) before accepting the
connection as successful.
Without this, a fast-failing IPv6 connection would be returned to
the caller instead of falling back to IPv4.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
| -rw-r--r-- | usock.c | 29 |
1 files changed, 24 insertions, 5 deletions
@@ -131,6 +131,17 @@ static int poll_restart(struct pollfd *fds, int nfds, int timeout) } } +static int usock_check_connect(int fd) +{ + int err = 0; + socklen_t len = sizeof(err); + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len)) + return -1; + + return err ? -1 : 0; +} + int usock_inet_timeout(int type, const char *host, const char *service, void *addr, int timeout) { @@ -184,9 +195,15 @@ int usock_inet_timeout(int type, const char *host, const char *service, if (timeout > 300) { if (poll_restart(pfds, 1, 300) == 1) { - rp = rp_v6; - sock = pfds[0].fd; - goto out; + if (usock_check_connect(pfds[0].fd) == 0) { + rp = rp_v6; + sock = pfds[0].fd; + goto out; + } + close(pfds[0].fd); + pfds[0].fd = -1; + rp_v6 = NULL; + goto try_v4; } } timeout -= 300; @@ -208,13 +225,15 @@ try_v4: wait: poll_restart(pfds + !rp_v6, !!rp_v6 + !!rp_v4, timeout); - if (pfds[0].revents & POLLOUT) { + if ((pfds[0].revents & POLLOUT) && + usock_check_connect(pfds[0].fd) == 0) { rp = rp_v6; sock = pfds[0].fd; goto out; } - if (pfds[1].revents & POLLOUT) { + if ((pfds[1].revents & POLLOUT) && + usock_check_connect(pfds[1].fd) == 0) { rp = rp_v4; sock = pfds[1].fd; goto out; |