Fix use of accept() in test socks4a proxy.

The read() in readall() to read the SOCKS4a request was sometimes
failing with EAGAIN, which it wasn't prepared for, causing the
request to be rejected and the test to fail.

I wrote this code specifically under the assumption the fd would be
in blocking mode, and in the original draft I wrote with stdin/stdout
under socat that was true.  But when I adapted this to do its own
bind/listen/accept logic, I broke it, because POSIX leaves it
unspecified whether accept() inherits the O_NONBLOCK setting or not:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/accept4.html

And the traditional BSD semantics is to inherit O_NONBLOCK.

So, just explicitly clear O_NONBLOCK on the fd returned by accept().
This commit is contained in:
Taylor R Campbell
2026-01-21 14:28:01 +00:00
committed by Nico Williams
parent 112a82dd25
commit 253a001ebc

View File

@@ -545,6 +545,23 @@ makenonblocking(int fd)
err(EXIT_FAILURE, "fcntl(F_SETFL)");
}
/*
* makeblocking(fd)
*
* Make fd blocking. Fail with err(3) if it can't be done.
*/
static void
makeblocking(int fd)
{
int flags;
if ((flags = fcntl(fd, F_GETFL)) == -1)
err(EXIT_FAILURE, "fcntl(F_GETFL)");
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1)
err(EXIT_FAILURE, "fcntl(F_SETFL)");
}
static int help_flag;
static int version_flag;
static struct getargs args[] = {
@@ -758,6 +775,15 @@ main(int argc, char **argv)
err(EXIT_FAILURE, "accept");
}
/*
* POSIX leaves it unspecified whether the fd it
* returns is blocking or non-blocking. Make it
* blocking, since readall/writeall used to read the
* SOCKS4a request and write the SOCKS4a response
* expects that.
*/
makeblocking(clientfd);
/*
* Fork a child to handle it; then close the client
* socket so we don't leak it.