diff --git a/CHANGES b/CHANGES index a0ede59..148e598 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,15 @@ Corrections: Test: TCP_TIMEOUT_RETRY Thanks to Kamil Holubicki for reporting this issue. + There were a couple of weaknesses and errors when accessing invalid or + incompatible file system entries with UNIX domain, file, and generic + addresses. + For example, UNIX-CONNECT, when using a non matching socktype, failed + with -1 and did not print an error message, instead of printing an + error message and exiting with rc=1. + Thanks to Paul Wise for reporting and analyzing the case of accessing + a left over socket entry with GOPEN. + Porting: OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain conditions: client connection to server with certificate with empty diff --git a/xio-socket.c b/xio-socket.c index 7d89874..3d55837 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -738,14 +738,14 @@ int xiogetpacketinfo(int fd) -/* a subroutine that is common to all socket addresses that want to connect - to a peer address. - might fork. - applies and consumes the following options: +/* A subroutine that is common to all socket addresses that want to connect() + a socket to a peer. + Applies and consumes the following options: PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT, PH_CONNECTED, PH_LATE, OFUNC_OFFSET, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC + Does not fork, does not retry. returns 0 on success. */ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen, @@ -961,23 +961,19 @@ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen, xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); } - } else if (pf == PF_UNIX && errno == EPROTOTYPE) { + } else if (pf == PF_UNIX) { /* this is for UNIX domain sockets: a connect attempt seems to be - the only way to distinguish stream and datagram sockets */ + the only way to distinguish stream and datagram sockets. + And no ancillary message expected + */ int _errno = errno; Info4("connect(%d, %s, "F_Zd"): %s", xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); -#if 0 - Info("assuming datagram socket"); - xfd->dtype = DATA_RECVFROM; - xfd->salen = themlen; - memcpy(&xfd->peersa.soa, them, xfd->salen); -#endif - /*!!! and remove bind socket */ + /* caller must handle this condition */ Close(xfd->fd); xfd->fd = -1; errno = _errno; - return -1; + return STAT_RETRYLATER; } else { /* try to find details about error, especially from ICMP */ xiogetpacketinfo(xfd->fd); diff --git a/xio-unix.c b/xio-unix.c index 09140b1..e4b054b 100644 --- a/xio-unix.c +++ b/xio-unix.c @@ -15,7 +15,7 @@ #if WITH_UNIX -/* to avoid unneccessary "live" if () conditionals when no abstract support is +/* to avoid unneccessary runtime if () conditionals when no abstract support is compiled in (or at least to give optimizing compilers a good chance) we need a constant that can be used in C expressions */ #if WITH_ABSTRACT_UNIXSOCKET @@ -218,6 +218,10 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, socklen_t themlen, uslen = sizeof(us); bool needbind = false; bool opt_unlink_close = true; + bool dofork = false; + struct opt *opts0; + char infobuff[256]; + int level; int result; if (argc != 2) { @@ -258,13 +262,91 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, xfd->opt_unlink_close = true; } - if ((result = - xioopen_connect(xfd, + retropt_bool(opts, OPT_FORK, &dofork); + + opts0 = copyopts(opts, GROUP_ALL); + + Notice1("opening connection to %s", + sockaddr_info((struct sockaddr *)&them, themlen, infobuff, sizeof(infobuff))); + + do { /* loop over retries and forks */ + +#if WITH_RETRY + if (xfd->forever || xfd->retry) { + level = E_INFO; + } else +#endif /* WITH_RETRY */ + level = E_ERROR; + + result = + _xioopen_connect(xfd, needbind?(union sockaddr_union *)&us:NULL, uslen, (struct sockaddr *)&them, themlen, - opts, pf, socktype, protocol, false)) != 0) { - return result; - } + opts, pf, socktype, protocol, false, level); + if (result != 0) { + char infobuff[256]; + /* we caller must handle this */ + Msg3(level, "connect(, %s, "F_Zd"): %s", + sockaddr_info((struct sockaddr *)&them, themlen, infobuff, sizeof(infobuff)), + themlen, strerror(errno)); + } + switch (result) { + case STAT_OK: break; +#if WITH_RETRY + case STAT_RETRYLATER: + if (xfd->forever || xfd->retry) { + --xfd->retry; + if (result == STAT_RETRYLATER) { + Nanosleep(&xfd->intervall, NULL); + } + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; + } + return STAT_NORETRY; +#endif /* WITH_RETRY */ + default: + return result; + } + + if (dofork) { + xiosetchilddied(); /* set SIGCHLD handler */ + } + +#if WITH_RETRY + if (dofork) { + pid_t pid; + int level = E_ERROR; + if (xfd->forever || xfd->retry) { + level = E_WARN; /* most users won't expect a problem here, + so Notice is too weak */ + } + + while ((pid = xio_fork(false, level)) < 0) { + --xfd->retry; + if (xfd->forever || xfd->retry) { + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + Nanosleep(&xfd->intervall, NULL); continue; + } + return STAT_RETRYLATER; + } + + if (pid == 0) { /* child process */ + break; + } + + /* parent process */ + Close(xfd->fd); + /* with and without retry */ + Nanosleep(&xfd->intervall, NULL); + dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL); + continue; /* with next socket() bind() connect() */ + } else +#endif /* WITH_RETRY */ + { + break; + } + } while (true); + if ((result = _xio_openlate(xfd, opts)) < 0) { return result; } @@ -500,6 +582,7 @@ int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, } +/* generic UNIX socket client, tries connect, SEQPACKET, send(to) */ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) { /* we expect the form: filename */ if (argc != 2) { @@ -615,6 +698,7 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, } while (0); if (result != 0) { + Error2("UNIX-CLIENT:%s: %s", name, strerror(errno)); if (needbind) { Unlink(us.un.sun_path); }