mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Fixed Socats behaviour on failing UNIX domain accesses ea.
This commit is contained in:
parent
ed4780553f
commit
0b1af3703d
3 changed files with 109 additions and 20 deletions
9
CHANGES
9
CHANGES
|
@ -15,6 +15,15 @@ Corrections:
|
||||||
Test: TCP_TIMEOUT_RETRY
|
Test: TCP_TIMEOUT_RETRY
|
||||||
Thanks to Kamil Holubicki for reporting this issue.
|
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:
|
Porting:
|
||||||
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
||||||
conditions: client connection to server with certificate with empty
|
conditions: client connection to server with certificate with empty
|
||||||
|
|
24
xio-socket.c
24
xio-socket.c
|
@ -738,14 +738,14 @@ int xiogetpacketinfo(int fd)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* a subroutine that is common to all socket addresses that want to connect
|
/* A subroutine that is common to all socket addresses that want to connect()
|
||||||
to a peer address.
|
a socket to a peer.
|
||||||
might fork.
|
Applies and consumes the following options:
|
||||||
applies and consumes the following options:
|
|
||||||
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
|
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
|
||||||
PH_CONNECTED, PH_LATE,
|
PH_CONNECTED, PH_LATE,
|
||||||
OFUNC_OFFSET,
|
OFUNC_OFFSET,
|
||||||
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
|
||||||
|
Does not fork, does not retry.
|
||||||
returns 0 on success.
|
returns 0 on success.
|
||||||
*/
|
*/
|
||||||
int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
|
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)),
|
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
themlen, strerror(errno));
|
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
|
/* 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;
|
int _errno = errno;
|
||||||
Info4("connect(%d, %s, "F_Zd"): %s",
|
Info4("connect(%d, %s, "F_Zd"): %s",
|
||||||
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
|
||||||
themlen, strerror(errno));
|
themlen, strerror(errno));
|
||||||
#if 0
|
/* caller must handle this condition */
|
||||||
Info("assuming datagram socket");
|
|
||||||
xfd->dtype = DATA_RECVFROM;
|
|
||||||
xfd->salen = themlen;
|
|
||||||
memcpy(&xfd->peersa.soa, them, xfd->salen);
|
|
||||||
#endif
|
|
||||||
/*!!! and remove bind socket */
|
|
||||||
Close(xfd->fd); xfd->fd = -1;
|
Close(xfd->fd); xfd->fd = -1;
|
||||||
errno = _errno;
|
errno = _errno;
|
||||||
return -1;
|
return STAT_RETRYLATER;
|
||||||
} else {
|
} else {
|
||||||
/* try to find details about error, especially from ICMP */
|
/* try to find details about error, especially from ICMP */
|
||||||
xiogetpacketinfo(xfd->fd);
|
xiogetpacketinfo(xfd->fd);
|
||||||
|
|
92
xio-unix.c
92
xio-unix.c
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#if WITH_UNIX
|
#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
|
compiled in (or at least to give optimizing compilers a good chance) we need
|
||||||
a constant that can be used in C expressions */
|
a constant that can be used in C expressions */
|
||||||
#if WITH_ABSTRACT_UNIXSOCKET
|
#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);
|
socklen_t themlen, uslen = sizeof(us);
|
||||||
bool needbind = false;
|
bool needbind = false;
|
||||||
bool opt_unlink_close = true;
|
bool opt_unlink_close = true;
|
||||||
|
bool dofork = false;
|
||||||
|
struct opt *opts0;
|
||||||
|
char infobuff[256];
|
||||||
|
int level;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (argc != 2) {
|
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;
|
xfd->opt_unlink_close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result =
|
retropt_bool(opts, OPT_FORK, &dofork);
|
||||||
xioopen_connect(xfd,
|
|
||||||
|
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,
|
needbind?(union sockaddr_union *)&us:NULL, uslen,
|
||||||
(struct sockaddr *)&them, themlen,
|
(struct sockaddr *)&them, themlen,
|
||||||
opts, pf, socktype, protocol, false)) != 0) {
|
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;
|
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) {
|
if ((result = _xio_openlate(xfd, opts)) < 0) {
|
||||||
return result;
|
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) {
|
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 */
|
/* we expect the form: filename */
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
|
@ -615,6 +698,7 @@ _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups,
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
|
Error2("UNIX-CLIENT:%s: %s", name, strerror(errno));
|
||||||
if (needbind) {
|
if (needbind) {
|
||||||
Unlink(us.un.sun_path);
|
Unlink(us.un.sun_path);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue