From 1154e69d3e9b8ac259bf39bf0df9de6151c7d32e Mon Sep 17 00:00:00 2001 From: Gerhard Rieger <gerhard@dest-unreach.org> Date: Fri, 10 Jan 2025 19:41:34 +0100 Subject: [PATCH] writefull() respects total inactivity timeout --- CHANGES | 4 ++++ socat.c | 2 ++ sysutils.c | 13 +++++++++++-- sysutils.h | 2 +- test.sh | 6 +++--- xio-proxy.c | 6 +++--- xio-readline.c | 2 +- xio-socks.c | 2 +- xio-socks5.c | 4 ++-- xio.h | 1 + xiolockfile.c | 2 +- xiowrite.c | 2 +- 12 files changed, 31 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index f1efbcc..0588136 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,9 @@ Corrections: On partial write to not poll with sleep() but use select()/poll(). + Partial write situations respect total inactivity timeout when + nonblocking. + Building: Disabling certain features during configure could break build process. @@ -39,6 +42,7 @@ Testing: SOCKS5 addresses are no longer experimental. Tests: SOCKS5CONNECT_TCP4 SOCKS5LISTEN_TCP4 + ####################### V 1.8.0.2: Security: diff --git a/socat.c b/socat.c index 6ffbd21..c990f62 100644 --- a/socat.c +++ b/socat.c @@ -282,6 +282,8 @@ int main(int argc, const char *argv[]) { socat_opts.total_timeout.tv_usec = (rto-socat_opts.total_timeout.tv_sec) * 1000000; } + xioparms.total_timeout.tv_sec = socat_opts.total_timeout.tv_sec; + xioparms.total_timeout.tv_usec = socat_opts.total_timeout.tv_usec; break; case 'u': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); } socat_opts.lefttoright = true; break; diff --git a/sysutils.c b/sysutils.c index a581a53..f395e58 100644 --- a/sysutils.c +++ b/sysutils.c @@ -32,10 +32,15 @@ const int one = 1; Then we can test partial write with something like: socat -d4 -lu -b 262144 -u /dev/zero,readbytes=262144 -,o-nonblock |{ sleep 3; wc -c; } */ -ssize_t writefull(int fd, const void *buff, size_t bytes) { +ssize_t writefull( + int fd, + const void *buff, + size_t bytes, + const struct timeval *tmo0) { size_t writt = 0; ssize_t chk; struct pollfd pfd; + struct timeval tmo = { 0 }; int rc; while (1) { @@ -51,7 +56,11 @@ ssize_t writefull(int fd, const void *buff, size_t bytes) { pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; - rc = xiopoll(&pfd, 1, NULL); + if (tmo0 != NULL) { + tmo.tv_sec = tmo0->tv_sec; + tmo.tv_usec = tmo0->tv_usec; + } + rc = xiopoll(&pfd, 1, (tmo.tv_sec!=0 || tmo.tv_usec!=0) ? &tmo : NULL); if (rc == 0) { Notice("inactivity timeout triggered"); errno = ETIMEDOUT; diff --git a/sysutils.h b/sysutils.h index 5e8ae10..cfdff04 100644 --- a/sysutils.h +++ b/sysutils.h @@ -47,7 +47,7 @@ struct xiorange { extern const int one; #endif -extern ssize_t writefull(int fd, const void *buff, size_t bytes); +extern ssize_t writefull(int fd, const void *buff, size_t bytes, const struct timeval *tmo0); #if _WITH_SOCKET extern socklen_t socket_init(int af, union sockaddr_union *sa); diff --git a/test.sh b/test.sh index 9d08236..c16a839 100755 --- a/test.sh +++ b/test.sh @@ -19053,7 +19053,7 @@ else da="test$N $(date) $RANDOM" case X$IPPORT in XPORT) newport $(tolower $PROTO); _PORT=$PORT ;; - XPROTO) echo "IPPROTO=\"$IPPROTO\"" + XPROTO) #echo "IPPROTO=\"$IPPROTO\"" _PORT=$IPPROTO ;; esac CMD0="$TRACE $SOCAT $opts ${ADDR}:$_PORT,$option,$ACCEPT_TIMEOUT PIPE" @@ -19146,7 +19146,7 @@ else da="test$N $(date) $RANDOM" case X$IPPORT in XPORT) newport $(tolower $PROTO); _PORT=$PORT ;; - XPROTO) echo "IPPROTO=\"$IPPROTO\"" + XPROTO) #echo "IPPROTO=\"$IPPROTO\"" _PORT=$IPPROTO ;; esac CMD0="$TRACE $SOCAT $opts -u /dev/null $ADDR:localhost-6-4.dest-unreach.net:$_PORT,bind=127.0.0.1" @@ -19211,7 +19211,7 @@ else da="test$N $(date) $RANDOM" case X$IPPORT in XPORT) newport $(tolower $PROTO); _PORT=$PORT ;; - XPROTO) echo "IPPROTO=\"$IPPROTO\"" + XPROTO) #echo "IPPROTO=\"$IPPROTO\"" _PORT=$IPPROTO ;; esac CMD0="$TRACE $SOCAT $opts ${ADDR%%-*}-LISTEN:$_PORT,pf=ip4 PIPE" diff --git a/xio-proxy.c b/xio-proxy.c index 86d86e3..0a8d4e6 100644 --- a/xio-proxy.c +++ b/xio-proxy.c @@ -376,7 +376,7 @@ int _xioopen_proxy_connect(struct single *sfd, * xiosanitize(request, strlen(request), textbuff) = '\0'; Info1("sending \"%s\"", textbuff); /* write errors are assumed to always be hard errors, no retry */ - if (writefull(sfd->fd, request, strlen(request)) < 0) { + if (writefull(sfd->fd, request, strlen(request), NULL) < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", sfd->fd, request, strlen(request), strerror(errno)); if (Close(sfd->fd) < 0) { @@ -406,7 +406,7 @@ int _xioopen_proxy_connect(struct single *sfd, *next = '\0'; Info1("sending \"%s\\r\\n\"", header); *next++ = '\r'; *next++ = '\n'; *next++ = '\0'; - if (writefull(sfd->fd, header, strlen(header)) < 0) { + if (writefull(sfd->fd, header, strlen(header), NULL) < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", sfd->fd, header, strlen(header), strerror(errno)); if (Close(sfd->fd) < 0) { @@ -419,7 +419,7 @@ int _xioopen_proxy_connect(struct single *sfd, } Info("sending \"\\r\\n\""); - if (writefull(sfd->fd, "\r\n", 2) < 0) { + if (writefull(sfd->fd, "\r\n", 2, NULL) < 0) { Msg2(level, "write(%d, \"\\r\\n\", 2): %s", sfd->fd, strerror(errno)); if (Close(sfd->fd) < 0) { diff --git a/xio-readline.c b/xio-readline.c index 376cd26..2807379 100644 --- a/xio-readline.c +++ b/xio-readline.c @@ -184,7 +184,7 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) { /* we must carriage return, because readline will first print the prompt */ ssize_t writt; - writt = writefull(pipe->fd, "\r", 1); + writt = writefull(pipe->fd, "\r", 1, NULL); if (writt < 0) { Warn2("write(%d, \"\\r\", 1): %s", pipe->fd, strerror(errno)); diff --git a/xio-socks.c b/xio-socks.c index 089fd27..fd064dd 100644 --- a/xio-socks.c +++ b/xio-socks.c @@ -370,7 +370,7 @@ int _xioopen_socks4_connect(struct single *sfd, } } #endif /* WITH_MSGLEVEL <= E_DEBUG */ - if (writefull(sfd->fd, sockhead, headlen) < 0) { + if (writefull(sfd->fd, sockhead, headlen, NULL) < 0) { Msg4(level, "write(%d, %p, "F_Zu"): %s", sfd->fd, sockhead, headlen, strerror(errno)); if (Close(sfd->fd) < 0) { diff --git a/xio-socks5.c b/xio-socks5.c index d931961..31aa1ca 100644 --- a/xio-socks5.c +++ b/xio-socks5.c @@ -136,7 +136,7 @@ static int _xioopen_socks5_handshake(struct single *sfd, int level) } #endif - if (writefull(sfd->fd, client_hello, client_hello_size) < 0) { + if (writefull(sfd->fd, client_hello, client_hello_size, NULL) < 0) { Msg4(level, "write(%d, %p, %d): %s", sfd->fd, client_hello, client_hello_size, strerror(errno)); @@ -426,7 +426,7 @@ static int _xioopen_socks5_request( } #endif - if (writefull(sfd->fd, req, bytes) < 0) { + if (writefull(sfd->fd, req, bytes, NULL) < 0) { Msg4(level, "write(%d, %p, %d): %s", sfd->fd, req, bytes, strerror(errno)); if (Close(sfd->fd) < 0) { diff --git a/xio.h b/xio.h index a276a56..ade2d0a 100644 --- a/xio.h +++ b/xio.h @@ -120,6 +120,7 @@ typedef struct xioparms { const char *sniffleft_name; /* file name with -r */ const char *sniffright_name; /* file name with -R */ size_t bufsiz; + struct timeval total_timeout;/* when nothing happens, die after seconds */ } xioparms_t; /* pack the description of a lock file */ diff --git a/xiolockfile.c b/xiolockfile.c index c6896d4..ff29c2f 100644 --- a/xiolockfile.c +++ b/xiolockfile.c @@ -52,7 +52,7 @@ int xiogetlock(const char *lockfile) { pid = Getpid(); bytes = sprintf(pidbuf, F_pid"\n", pid); - if (writefull(fd, pidbuf, bytes) < 0) { + if (writefull(fd, pidbuf, bytes, NULL) < 0) { Error4("write(%d, %p, "F_Zu"): %s", fd, pidbuf, bytes, strerror(errno)); return -1; } diff --git a/xiowrite.c b/xiowrite.c index a3e77ab..c5885ad 100644 --- a/xiowrite.c +++ b/xiowrite.c @@ -50,7 +50,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) { switch (pipe->dtype & XIODATA_WRITEMASK) { case XIOWRITE_STREAM: - writt = writefull(pipe->fd, buff, bytes); + writt = writefull(pipe->fd, buff, bytes, NULL); if (writt < 0) { _errno = errno; switch (_errno) {