From eeabf31e048e619d9306b2392c3b9fddbe96ca81 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sat, 17 Jun 2023 15:31:26 +0200 Subject: [PATCH] Option -S for controlling signals' logging --- CHANGES | 4 +++ doc/socat.yo | 9 ++++++ socat.c | 41 ++++++++++++++---------- test.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 123 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index 1da4617..5b019c4 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,10 @@ Features: The number of warnings has been reduced, e.g.removing a non existing file does in most cases no longer log a warning. + New option -S controls catching and logging of signals that are + not internally used by Socat. + Tests: SIGTERM_NOLOG SIG31_LOG + Corrections: When a sub process (EXEC, SYSTEM) terminated with exit code other than 0, its last sent data might have been lost depending on timing of read/ diff --git a/doc/socat.yo b/doc/socat.yo index 6a6619a..175d734 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -176,6 +176,15 @@ label(option_s)dit(bf(tt(-s))) option, socat() is sloppy with errors and tries to continue. Even with this option, socat will exit on fatals, and will abort connection attempts when security checks failed. +label(option_S)dit(bf(tt(-S))tt()) + Changes the set of signals that are caught by socat() just for printing an + log message. This catching is useful to get the information about the signal + into socat()s log, but prevents core dump or other standard actions. The + default set of these signals is SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, + SIGBUS, SIGFPE, SIGSEGV, and SIGTERM; replace this set (0x89de on Linux) + with a bitmap (e.g., SIGFPE has value 8 and its bit is 0x0080).nl() + Note: Signals SIGHUP, SIGINT, SIGQUIT, SIGUSR1, SIGPIPE, SIGALRM, SIGTERM, and + SIGCHLD may be handled specially anyway. label(option_t)dit(bf(tt(-t))tt()) When one channel has reached EOF, the write part of the other channel is shut down. Then, socat() waits [link(timeval)(TYPE_TIMEVAL)] seconds diff --git a/socat.c b/socat.c index 6488103..98c7e7e 100644 --- a/socat.c +++ b/socat.c @@ -39,6 +39,7 @@ struct { int sniffleft; /* -1 or an FD for teeing data arriving on xfd1 */ int sniffright; /* -1 or an FD for teeing data arriving on xfd2 */ xiolock_t lock; /* a lock file */ + unsigned long log_sigs; /* signals to be caught just for logging */ } socat_opts = { 8192, /* bufsiz */ false, /* verbose */ @@ -54,6 +55,7 @@ struct { -1, /* sniffleft */ -1, /* sniffright */ { NULL, 0 }, /* lock */ + 1< log to file\n", fd); fputs(" -ls log to stderr (default if no other log)\n", fd); fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd); - fputs(" -lp set the program name used for logging\n", fd); + fputs(" -lp set the program name used for logging and vars\n", fd); fputs(" -lu use microseconds for logging timestamps\n", fd); fputs(" -lh add hostname to log messages\n", fd); fputs(" -v verbose text dump of data traffic\n", fd); @@ -438,6 +450,7 @@ void socat_usage(FILE *fd) { fputs(" -R raw dump of data flowing from right to left\n", fd); fputs(" -b set data buffer size (8192)\n", fd); fputs(" -s sloppy (continue on error)\n", fd); + fputs(" -S log these signals, override default\n", fd); fputs(" -t wait seconds before closing second channel\n", fd); fputs(" -T total inactivity timeout in seconds\n", fd); fputs(" -u unidirectional mode (left to right)\n", fd); @@ -1593,11 +1606,7 @@ void socat_signal(int signum) { diag_in_handler = 1; Notice1("socat_signal(): handling signal %d", signum); switch (signum) { - case SIGILL: - case SIGABRT: - case SIGBUS: - case SIGFPE: - case SIGSEGV: + default: diag_immediate_exit = 1; case SIGQUIT: case SIGPIPE: diff --git a/test.sh b/test.sh index 0cb66b5..963d010 100755 --- a/test.sh +++ b/test.sh @@ -4267,7 +4267,7 @@ case "$TESTS" in *%$N%*|*%functions%*|*%$NAME%*) if ! eval $NUMCOND; then : elif ! F=$(testfeats STDIO EXEC); then - $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs STDIO EXEC); then @@ -9271,7 +9271,7 @@ case "$TESTS" in TEST="$NAME: UDP/IPv6 multicast" if ! eval $NUMCOND; then :; elif ! f=$(testfeats ip6 udp); then - $PRINTF "test $F_n $TEST... ${YELLOW}Feature $f not available in $SOCAT${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $f not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! a=$(testaddrs - STDIO UDP6-RECV UDP6-SENDTO); then @@ -16127,7 +16127,7 @@ TEST="$NAME: ${KEYW}-RECVFROM with fork option" # When the second record is stored before the first one the test succeeded. if ! eval $NUMCOND; then :; elif ! F=$(testfeats $FEAT STDIO SYSTEM); then - $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - STDIO SYSTEM $PROTO-RECVFROM $PROTO-SENDTO); then @@ -16205,6 +16205,87 @@ UDP6 UDP udp4 [::1] PORT UNIX unix unix $td/test\$N.server - " + +# Test if option -S turns off logging of SIGTERM +NAME=SIGTERM_NOLOG +case "$TESTS" in +*%$N%*|*%functions%*|*%signal%*|*%$NAME%*) +TEST="$NAME: Option -S can turn off logging of SIGTERM" +# Start Socat with option -S 0x0000, kill it with SIGTERM +# When no logging entry regarding this signal is there, the test succeeded +if ! eval $NUMCOND; then :; +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +newport tcp4 # or whatever proto, or drop this line +CMD0="$TRACE $SOCAT $opts -S 0x0000 PIPE PIPE" +printf "test $F_n $TEST... " $N +$CMD0 >/dev/null 2>"${te}0" & +pid0=$! +relsleep 1 # give process time to start +kill -TERM $pid0 2>/dev/null; wait +if ! grep -q "exiting on signal" ${te}0; then + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$DEBUG" ]; then echo "kill -TERM " >&2; fi + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "kill -TERM " >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" +fi +fi # NUMCOND + ;; +esac +N=$((N+1)) + +# Test if option -S turns on logging of signal 31 +NAME=SIG31_LOG +case "$TESTS" in +*%$N%*|*%functions%*|*%signal%*|*%$NAME%*) +TEST="$NAME: Option -S can turn on logging of signal 31" +# Start Socat with option -S 0x80000000, kill it with -31 +# When a logging entry regarding this signal is there, the test succeeded +if ! eval $NUMCOND; then :; +else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +newport tcp4 # or whatever proto, or drop this line +CMD0="$TRACE $SOCAT $opts -S 0x80000000 PIPE PIPE" +printf "test $F_n $TEST... " $N +$CMD0 >/dev/null 2>"${te}0" & +pid0=$! +relsleep 1 # give process time to start +kill -31 $pid0 2>/dev/null; wait +if grep -q "exiting on signal" ${te}0; then + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$DEBUG" ]; then echo "kill -31 " >&2; fi + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "kill -31 " >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" +fi +fi # NUMCOND + ;; +esac +N=$((N+1)) + # end of common tests ################################################################################## @@ -16355,7 +16436,7 @@ elif ! $(type systemd-socket-activate >/dev/null 2>&1); then numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! F=$(testfeats STDIO IP4 TCP PIPE); then - $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available in $SOCAT${NORMAL}\n" $N + $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" elif ! A=$(testaddrs - TCP4 TCP4-LISTEN PIPE); then