mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
-r, -R now with CLOEXEC, and warn on write problems
This commit is contained in:
parent
eeeebe6cb2
commit
2dadc1010f
3 changed files with 131 additions and 37 deletions
7
CHANGES
7
CHANGES
|
@ -74,6 +74,13 @@ Coding:
|
|||
|
||||
fcntl() trace prints flags now in hexadecimal.
|
||||
|
||||
Stream dump options -r and -R now open their pathes with CLOEXEC to
|
||||
prevent leaking into sub processes.
|
||||
Test: EXEC_SNIFF
|
||||
|
||||
Stream dump write now warn on write errors and partial writes (but
|
||||
still do not recover).
|
||||
|
||||
Porting:
|
||||
Small correction in configure.ac makes Socat C99 able.
|
||||
Thanks to Florian Weimer from Red Hat for providing a patch.
|
||||
|
|
93
socat.c
93
socat.c
|
@ -59,6 +59,7 @@ struct {
|
|||
void socat_usage(FILE *fd);
|
||||
void socat_opt_hint(FILE *fd, char a, char b);
|
||||
void socat_version(FILE *fd);
|
||||
static int xio_openauxwr(const char *path, const char *hint);
|
||||
int socat(const char *address1, const char *address2);
|
||||
int _socat(void);
|
||||
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||
|
@ -187,20 +188,8 @@ int main(int argc, const char *argv[]) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ((socat_opts.sniffleft = Open(a, O_CREAT|O_WRONLY|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) < 0) {
|
||||
if (errno == ENXIO) {
|
||||
if ((socat_opts.sniffleft = Open(a, O_CREAT|O_RDWR|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) > 0)
|
||||
break; /* try to open pipe rdwr */
|
||||
}
|
||||
Error2("option -r \"%s\": %s", a, strerror(errno));
|
||||
if ((socat_opts.sniffleft = xio_openauxwr(a, "option -r")) < 0) {
|
||||
Error2("option -r: failed to open \"%s\": %s", a, strerror(errno));
|
||||
}
|
||||
break;
|
||||
case 'R': if (arg1[0][2]) {
|
||||
|
@ -212,20 +201,8 @@ int main(int argc, const char *argv[]) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ((socat_opts.sniffright = Open(a, O_CREAT|O_WRONLY|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) < 0) {
|
||||
if (errno == ENXIO) {
|
||||
if ((socat_opts.sniffright = Open(a, O_CREAT|O_RDWR|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) > 0)
|
||||
break; /* try to open pipe rdwr */
|
||||
}
|
||||
Error2("option -R \"%s\": %s", a, strerror(errno));
|
||||
if ((socat_opts.sniffright = xio_openauxwr(a, "option -R")) < 0) {
|
||||
Error2("option -R: failed to open \"%s\": %s", a, strerror(errno));
|
||||
}
|
||||
break;
|
||||
case 'b': if (arg1[0][2]) {
|
||||
|
@ -629,6 +606,47 @@ void socat_version(FILE *fd) {
|
|||
}
|
||||
|
||||
|
||||
/* Opens a path for logging or tracing.
|
||||
Return the filedescriptor, or -1 when an error occurred (errn0).
|
||||
Prints messages but no Error().
|
||||
*/
|
||||
static int xio_openauxwr(const char *path, const char *hint)
|
||||
{
|
||||
int fd;
|
||||
int _errno;
|
||||
|
||||
if ((fd = Open(path, O_CREAT|O_WRONLY|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
O_CLOEXEC|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) < 0) {
|
||||
if (errno != ENXIO)
|
||||
return -1;
|
||||
/* Possibly a named pipe that does not yet have a reader */
|
||||
_errno = errno;
|
||||
Notice3("%s \"%s\": %s, retrying r/w", hint, path, strerror(errno));
|
||||
if ((fd = Open(path, O_CREAT|O_RDWR|O_APPEND|
|
||||
#ifdef O_LARGEFILE
|
||||
O_LARGEFILE|
|
||||
#endif
|
||||
#ifdef O_CLOEXEC
|
||||
O_CLOEXEC|
|
||||
#endif
|
||||
O_NONBLOCK, 0664)) < 0) {
|
||||
errno = _errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifndef O_CLOEXEC
|
||||
Fcntl_l(fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
xiofile_t *sock1, *sock2;
|
||||
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
||||
2..counting down closing timeout */
|
||||
|
@ -1281,6 +1299,7 @@ static int
|
|||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||
unsigned char *buff, size_t bufsiz, bool righttoleft) {
|
||||
ssize_t bytes, writt = 0;
|
||||
ssize_t sniffed;
|
||||
|
||||
bytes = xioread(inpipe, buff, bufsiz);
|
||||
if (bytes < 0) {
|
||||
|
@ -1331,9 +1350,23 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
|||
}
|
||||
|
||||
if (!righttoleft && socat_opts.sniffleft >= 0) {
|
||||
Write(socat_opts.sniffleft, buff, bytes);
|
||||
if ((sniffed = Write(socat_opts.sniffleft, buff, bytes)) < bytes) {
|
||||
if (sniffed < 0)
|
||||
Warn3("-r: write(%d, buff, "F_Zu"): %s",
|
||||
socat_opts.sniffleft, bytes, strerror(errno));
|
||||
else if (sniffed < bytes)
|
||||
Warn3("-r: write(%d, buff, "F_Zu") -> "F_Zd,
|
||||
socat_opts.sniffleft, bytes, sniffed);
|
||||
}
|
||||
} else if (righttoleft && socat_opts.sniffright >= 0) {
|
||||
Write(socat_opts.sniffright, buff, bytes);
|
||||
if ((sniffed = Write(socat_opts.sniffright, buff, bytes)) < bytes) {
|
||||
if (sniffed < 0)
|
||||
Warn3("-R: write(%d, buff, "F_Zu"): %s",
|
||||
socat_opts.sniffright, bytes, strerror(errno));
|
||||
else if (sniffed < bytes)
|
||||
Warn3("-R: write(%d, buff, "F_Zu") -> "F_Zd,
|
||||
socat_opts.sniffright, bytes, sniffed);
|
||||
}
|
||||
}
|
||||
|
||||
if (socat_opts.verbose && socat_opts.verbhex) {
|
||||
|
|
64
test.sh
64
test.sh
|
@ -15963,7 +15963,16 @@ case "$TESTS" in
|
|||
TEST="$NAME: Socat does not leak FDs to EXEC'd program"
|
||||
# Run Socat with EXEC address, execute Filan to display its file descriptors
|
||||
# Test succeeds when only FDs 0, 1, 2 are in use.
|
||||
if ! eval $NUMCOND; then :; else
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! a=$(testaddrs STDIO EXEC); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! o=$(testoptions stderr) >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
|
@ -15974,15 +15983,60 @@ eval "$CMD" >"${tf}" 2>"${te}"
|
|||
# "door" is a special FD type on Solaris/SunOS
|
||||
if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then
|
||||
echo "$CMD" >&2
|
||||
fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD" >&2
|
||||
cat "${tf}" >&2
|
||||
cat "${te}" >&2
|
||||
cat "${tf}" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
# Test if Socat makes the sniffing file descriptos (-r, -R) CLOEXEC to not leak
|
||||
# them to EXEC'd program
|
||||
NAME=EXEC_SNIFF
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%filan%*|*%$NAME%*)
|
||||
TEST="$NAME: Socat does not leak sniffing FDs"
|
||||
# Run Socat sniffing both directions, with EXEC address,
|
||||
# execute Filan to display its file descriptors
|
||||
# Test succeeds when only FDs 0, 1, 2 are in use.
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! a=$(testaddrs STDIO EXEC); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! o=$(testoptions stderr) >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD="$TRACE $SOCAT $opts -r $td/test$N.-r -R $td/test$N.-R - EXEC:\"$FILAN -s\",stderr"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD" >"${tf}" 2>"${te}"
|
||||
# "door" is a special FD type on Solaris/SunOS
|
||||
if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD" >&2
|
||||
cat "${te}" >&2
|
||||
cat "${tf}" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue