Fixed Socats behaviour on failing UNIX domain accesses ea.

This commit is contained in:
Gerhard Rieger 2022-03-25 11:00:00 +01:00
parent ed4780553f
commit 0b1af3703d
3 changed files with 109 additions and 20 deletions

View file

@ -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

View file

@ -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);

View file

@ -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);
}