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.
|
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:
|
Porting:
|
||||||
Small correction in configure.ac makes Socat C99 able.
|
Small correction in configure.ac makes Socat C99 able.
|
||||||
Thanks to Florian Weimer from Red Hat for providing a patch.
|
Thanks to Florian Weimer from Red Hat for providing a patch.
|
||||||
|
|
97
socat.c
97
socat.c
|
@ -59,6 +59,7 @@ struct {
|
||||||
void socat_usage(FILE *fd);
|
void socat_usage(FILE *fd);
|
||||||
void socat_opt_hint(FILE *fd, char a, char b);
|
void socat_opt_hint(FILE *fd, char a, char b);
|
||||||
void socat_version(FILE *fd);
|
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(const char *address1, const char *address2);
|
||||||
int _socat(void);
|
int _socat(void);
|
||||||
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
|
||||||
|
@ -187,21 +188,9 @@ int main(int argc, const char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((socat_opts.sniffleft = Open(a, O_CREAT|O_WRONLY|O_APPEND|
|
if ((socat_opts.sniffleft = xio_openauxwr(a, "option -r")) < 0) {
|
||||||
#ifdef O_LARGEFILE
|
Error2("option -r: failed to open \"%s\": %s", a, strerror(errno));
|
||||||
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));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'R': if (arg1[0][2]) {
|
case 'R': if (arg1[0][2]) {
|
||||||
a = *arg1+2;
|
a = *arg1+2;
|
||||||
|
@ -212,21 +201,9 @@ int main(int argc, const char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((socat_opts.sniffright = Open(a, O_CREAT|O_WRONLY|O_APPEND|
|
if ((socat_opts.sniffright = xio_openauxwr(a, "option -R")) < 0) {
|
||||||
#ifdef O_LARGEFILE
|
Error2("option -R: failed to open \"%s\": %s", a, strerror(errno));
|
||||||
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));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'b': if (arg1[0][2]) {
|
case 'b': if (arg1[0][2]) {
|
||||||
a = *arg1+2;
|
a = *arg1+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;
|
xiofile_t *sock1, *sock2;
|
||||||
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
|
||||||
2..counting down closing timeout */
|
2..counting down closing timeout */
|
||||||
|
@ -1281,6 +1299,7 @@ static int
|
||||||
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||||
unsigned char *buff, size_t bufsiz, bool righttoleft) {
|
unsigned char *buff, size_t bufsiz, bool righttoleft) {
|
||||||
ssize_t bytes, writt = 0;
|
ssize_t bytes, writt = 0;
|
||||||
|
ssize_t sniffed;
|
||||||
|
|
||||||
bytes = xioread(inpipe, buff, bufsiz);
|
bytes = xioread(inpipe, buff, bufsiz);
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
|
@ -1331,9 +1350,23 @@ int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!righttoleft && socat_opts.sniffleft >= 0) {
|
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) {
|
} 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) {
|
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"
|
TEST="$NAME: Socat does not leak FDs to EXEC'd program"
|
||||||
# Run Socat with EXEC address, execute Filan to display its file descriptors
|
# Run Socat with EXEC address, execute Filan to display its file descriptors
|
||||||
# Test succeeds when only FDs 0, 1, 2 are in use.
|
# 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"
|
tf="$td/test$N.stdout"
|
||||||
te="$td/test$N.stderr"
|
te="$td/test$N.stderr"
|
||||||
tdiff="$td/test$N.diff"
|
tdiff="$td/test$N.diff"
|
||||||
|
@ -15974,15 +15983,60 @@ eval "$CMD" >"${tf}" 2>"${te}"
|
||||||
# "door" is a special FD type on Solaris/SunOS
|
# "door" is a special FD type on Solaris/SunOS
|
||||||
if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then
|
if [ "$(cat "${tf}" |grep -v ' door ' |wc -l)" -eq 3 ]; then
|
||||||
$PRINTF "$OK\n"
|
$PRINTF "$OK\n"
|
||||||
if [ "$VERBOSE" ]; then
|
if [ "$VERBOSE" ]; then echo "$CMD"; fi
|
||||||
echo "$CMD" >&2
|
if [ "$DEBUG" ]; then cat "${te}" >&2; fi
|
||||||
fi
|
|
||||||
numOK=$((numOK+1))
|
numOK=$((numOK+1))
|
||||||
else
|
else
|
||||||
$PRINTF "$FAILED\n"
|
$PRINTF "$FAILED\n"
|
||||||
echo "$CMD" >&2
|
echo "$CMD" >&2
|
||||||
cat "${tf}" >&2
|
|
||||||
cat "${te}" >&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))
|
numFAIL=$((numFAIL+1))
|
||||||
listFAIL="$listFAIL $N"
|
listFAIL="$listFAIL $N"
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue