diff --git a/socat-1.7.4.3.tar.gz b/socat-1.7.4.3.tar.gz deleted file mode 100644 index abc58429aa01adf8d11da96f454193ebf8da0370..0000000000000000000000000000000000000000 Binary files a/socat-1.7.4.3.tar.gz and /dev/null differ diff --git a/socat-1.7.4.4.patch b/socat-1.7.4.4.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e371d4ac44e4279b0b27aa536495b5cf752caed --- /dev/null +++ b/socat-1.7.4.4.patch @@ -0,0 +1,3586 @@ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/CHANGES socat-1.7.4.4/CHANGES +--- socat-1.7.4.3/CHANGES 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/CHANGES 2022-10-30 16:21:47.880473970 +0100 +@@ -1,4 +1,144 @@ +  ++####################### V 1.7.4.4: ++ ++Corrections: ++ In error.c msg2() there was a stack overflow on long messages: The ++ terminating \0 Byte was written behind the last position. ++ Thanks to Martin Liška for sending the address sanitizer report. ++ ++ UDP-RECVFROM with fork sometimes terminated when multiple packets ++ arrived. This issue was introduced with a bug fix in version 1.7.4.0. ++ Reason was not handling EAGAIN on recvmsg(). ++ Thanks to Jamie McQuillan for reporting this issue. ++ ++ Address TCP with options connect-timeout and retry terminated ++ immediately when a connection attempt failed on network error or ++ connection refused. ++ 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. ++ ++ The rawer option failed because it tried to clear CREAD. ++ Test: RAWER ++ ++ UDP-SEND and UPD-SENDTO with option lowport always bound to port 1 ++ instead of a free port in range 640..1023 ++ Test: UDP_LOWPORT ++ ++ Fixed bad parser error message on "socat /tmp/x\"x/x -" ++ ++ Tightened syntax checks to detect numerical arguments that are missing ++ or have trailing garbage. ++ Test: INTEGER_GARBAGE ++ ++ ctype(3) functions need there arguments to be unsigned char. ++ Thanks to Taylor R Campbell for sending a patch. ++ ++ Filan library uses Socats diag/error message system and therefore had ++ always the signal handler messages socket pair open. This fix avoids ++ this socketpair in standalone Filan. ++ ++ Corrected printf format for type socklen_t in two places. ++ ++Porting: ++ OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain ++ conditions: client connection to server with certificate with empty ++ subject, and pressing ^C after successful connect. ++ This crash is now prevented by setting OPENSSL_INIT_NO_ATEXIT. ++ Thanks to Martin Dorey for reporting and analyzing this issue, and for ++ providing an environment for reproduction. ++ ++ Socat failed to compile on platforms that have ++ IP_ADD_SOURCE_MEMBERSHIP but not struct ip_mreq_source ++ Thanks to Justin Yackoski for sending a patch. ++ ++ configure.ac's detection of getprotobynumber_r() variant did not ++ recognize if this function does not exist, e.g. on Musl libc. ++ Thanks to Alexander Kanavin and Baruch Siach for sending patches. ++ ++ Corrected message format when no strftime() is available; improved ++ handling of very long host or program names ++ ++ Solaris requires that termios options are always applied to the slave ++ side of PTY. ++ ++ Fixed ancillary messages on Solaris. ++ ++ Filan: Solaris has the open file path infos in /proc//path/ ++ Thanks to Andy Fiddaman to directing me to the patch. ++ ++ Filan now recognizes and prints Solaris doors and event ports. ++ ++ Solaris derivatives no longer need librt for clock_gettime() ++ Thanks to Andy Fiddaman to directing me to the patch. ++ ++Building: ++ Failure during building documentation, e.g. due to missing Yodl ++ packages, now does not let the build process fail. ++ Feature requested by Seyhun. ++ ++Features: ++ Filan prints target of symlink when appropriate ++ Test: FILANSYMLINK ++ ++ VSOCK-LISTEN now generates environment variables SOCAT_PEERADDR, ++ SOCAT_PEERPORT, SOCAT_SOCKADDR, SOCAT_SOCKPORT ++ New address aliases VSOCK, VSOCK-L ++ ++Documentation: ++ Fixed typo in doc/socat-tun.html and link in README. ++ Thanks to William Suthers for reporting. ++ ++ Fixed hard coded path in docu examples. ++ Thanks to Jakub Wilk for sending a patch. ++ ++ Updated doc/socat-openssltunnel.html: 2048 bits, commonname ++ ++Testing: ++ Unset SOCAT_MAIN_WAIT on informational Socat calls ++ ++ SOCAT=socat used ./socat instead of the version derived by $PATH ++ ++ Do not try VSOCK_ECHO test when feature is not compiled in. ++ ++ Fixed logging of test 220 TUNINTERFACE ++ ++ Musl libc refuses to execve() shell scripts, 2 tests needed to be ++ adapted. ++ ++ Musl libc has FOPEN_MAX=1000 which made bash dumping core on test ++ EXCEED_FOPEN_MAX. ++ ++ Added tests for failures of UNIX socket and GOPEN accesses to non ++ matching file system entries. ++ Tests: ++ CONNECT_TO_MISSING CONNECT_TO_DENIED CONNECT_TO_DIRECTORY ++ CONNECT_TO_ORPHANED CONNECT_TO_FILE CONNECT_TO_DGRAM ++ CONNECT_TO_SEQPACKET SEND_TO_MISSING SEND_TO_DENIED SEND_TO_DIRECTORY ++ SEND_TO_ORPHANED SEND_TO_FILE SEND_TO_STREAM SEND_TO_SEQPACKET ++ SENDTO_TO_MISSING SENDTO_TO_DENIED SENDTO_TO_DIRECTORY ++ SENDTO_TO_ORPHANED SENDTO_TO_FILE SENDTO_TO_STREAM SENDTO_TO_SEQPACKET ++ SEQPACKET_TO_MISSING SEQPACKET_TO_DENIED SEQPACKET_TO_DIRECTORY ++ SEQPACKET_TO_ORPHANED SEQPACKET_TO_FILE SEQPACKET_TO_STREAM ++ SEQPACKET_TO_DGRAM UNIX_TO_MISSING UNIX_TO_DENIED UNIX_TO_DIRECTORY ++ UNIX_TO_FILE UNIX_TO_ORPHANED GOPEN_TO_DENIED GOPEN_TO_DIRECTORY ++ GOPEN_TO_ORPHANED ++ ++ On RHEL-9 SCTP support requires installation of package ++ kernel-modules-extra. test.sh now detects when SCTP is missing in ++ kernel and reacts with warnings instead of errors. ++ ++ VSOCK loopback still does not seem to work even in kernel 5.13, so just ++ issue warning on "No such device". ++ + ####################### V 1.7.4.3: + + Corrections: +diff -r -N -U 3 --no-dereference socat-1.7.4.3/Makefile.in socat-1.7.4.4/Makefile.in +--- socat-1.7.4.3/Makefile.in 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/Makefile.in 2022-10-30 16:21:47.880473970 +0100 +@@ -100,11 +100,11 @@ + rm -f doc/socat.1 doc/socat.html + + doc/socat.1: doc/socat.yo +- mkdir -p $(@D); yodl2man -o $@ $+ ++ -mkdir -p $(@D); yodl2man -o $@ $+ + + doc/socat.html: doc/socat.yo + # care for refs in html +- mkdir -p $(@D); cd $(@D); yodl2html -o socat.html ../$+; cd .. ++ -mkdir -p $(@D); cd $(@D); yodl2html -o socat.html ../$+; cd .. + + progs: $(PROGS) + +diff -r -N -U 3 --no-dereference socat-1.7.4.3/README socat-1.7.4.4/README +--- socat-1.7.4.3/README 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/README 2022-10-30 16:21:47.880473970 +0100 +@@ -75,7 +75,7 @@ + + Get the tarball and extract it: + tar xzf socat.tar.gz +- cd socat-1.7.4.3 ++ cd socat-1.7.4.4 + ./configure + make + su +@@ -306,4 +306,4 @@ + + public git repository: + git://repo.or.cz/socat.git +- http://repo.or.cz/r/socat.git ++ http://repo.or.cz/socat.git +diff -r -N -U 3 --no-dereference socat-1.7.4.3/VERSION socat-1.7.4.4/VERSION +--- socat-1.7.4.3/VERSION 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/VERSION 2022-10-30 16:21:47.880473970 +0100 +@@ -1 +1 @@ +-"1.7.4.3" ++"1.7.4.4" +diff -r -N -U 3 --no-dereference socat-1.7.4.3/compat.h socat-1.7.4.4/compat.h +--- socat-1.7.4.3/compat.h 2021-01-10 13:57:35.000000000 +0100 ++++ socat-1.7.4.4/compat.h 2022-10-30 16:21:47.880473970 +0100 +@@ -31,6 +31,10 @@ + # undef PIPE_STATES_SOCKET + #endif + ++#if defined(__sun) || defined(__sun__) || defined(__SunOS) ++# define XIO_ANCILLARY_TYPE_SOLARIS 1 ++#endif ++ + /*****************************************************************************/ + + /* substitute some features that might be missing on some platforms */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/config.h.in socat-1.7.4.4/config.h.in +--- socat-1.7.4.3/config.h.in 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/config.h.in 2022-10-30 16:21:47.880473970 +0100 +@@ -652,6 +652,7 @@ + + /* Define if you have the /proc/$$/fd directories */ + #undef HAVE_PROC_DIR_FD ++#undef HAVE_PROC_DIR_PATH + + #undef HAVE_SETGRENT + #undef HAVE_GETGRENT +diff -r -N -U 3 --no-dereference socat-1.7.4.3/configure socat-1.7.4.4/configure +--- socat-1.7.4.3/configure 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/configure 2022-10-30 16:21:47.884473989 +0100 +@@ -4358,7 +4358,7 @@ + return 0; + } + _ACEOF +-if ac_fn_c_try_compile "$LINENO"; then : ++if ac_fn_c_try_link "$LINENO"; then : + sc_cv_getprotobynumber_r=1; tmp_bynum_variant=Linux + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -4373,7 +4373,7 @@ + return 0; + } + _ACEOF +-if ac_fn_c_try_compile "$LINENO"; then : ++if ac_fn_c_try_link "$LINENO"; then : + sc_cv_getprotobynumber_r=2; tmp_bynum_variant=Solaris + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -4388,17 +4388,20 @@ + return 0; + } + _ACEOF +-if ac_fn_c_try_compile "$LINENO"; then : ++if ac_fn_c_try_link "$LINENO"; then : + sc_cv_getprotobynumber_r=3; tmp_bynum_variant=AIX + else + sc_cv_getprotobynumber_r= + + fi +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext + fi +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext + fi +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext + fi + + if test "$sc_cv_getprotobynumber_r"; then +@@ -8377,7 +8380,12 @@ + $as_echo "$sc_cv_have_prototype_lib_gettimeofday" >&6; } + + +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 ++ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" ++if test "x$ac_cv_func_clock_gettime" = xyes; then : ++ $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h ++ ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 + $as_echo_n "checking for clock_gettime in -lrt... " >&6; } + if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -8418,6 +8426,8 @@ + + fi + ++fi ++ + + # with Linux it's in libc, with AIX in libbsd + ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" +@@ -21101,6 +21111,20 @@ + $as_echo "no" >&6; } + fi + ++# On Solaris family, we have to use /proc/$$/path/N ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /proc/*/path" >&5 ++$as_echo_n "checking for /proc/*/path... " >&6; } ++if test -d /proc/$$/path; then ++ $as_echo "#define HAVE_PROC_DIR_PATH 1" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ + # on some platforms, raw linking with libwrap fails because allow_severity and + # deny_severity are not explicitely defined. Thus we put the libwrap part to + # the end +diff -r -N -U 3 --no-dereference socat-1.7.4.3/configure.ac socat-1.7.4.4/configure.ac +--- socat-1.7.4.3/configure.ac 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/configure.ac 2022-10-30 16:21:47.884473989 +0100 +@@ -137,13 +137,13 @@ + # getprotobynumber_r() is not standardized + AC_MSG_CHECKING(for getprotobynumber_r() variant) + AC_CACHE_VAL(sc_cv_getprotobynumber_r, +-[AC_TRY_COMPILE([#include ++[AC_TRY_LINK([#include + #include ],[getprotobynumber_r(1,NULL,NULL,1024,NULL);], + [sc_cv_getprotobynumber_r=1; tmp_bynum_variant=Linux], +- [AC_TRY_COMPILE([#include ++ [AC_TRY_LINK([#include + #include ],[getprotobynumber_r(1,NULL,NULL,1024);], + [sc_cv_getprotobynumber_r=2; tmp_bynum_variant=Solaris], +- [AC_TRY_COMPILE([#include ++ [AC_TRY_LINK([#include + #include ],[getprotobynumber_r(1,NULL,NULL);], + [sc_cv_getprotobynumber_r=3; tmp_bynum_variant=AIX], + +@@ -1516,8 +1516,7 @@ + + AC_CHECK_PROTOTYPE_LIB(gettimeofday) + +-AC_CHECK_LIB(rt, clock_gettime, +- [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)]) ++AC_CHECK_FUNC(clock_gettime, AC_DEFINE(HAVE_CLOCK_GETTIME), AC_CHECK_LIB(rt, clock_gettime, [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)])) + + dnl Search for flock() + # with Linux it's in libc, with AIX in libbsd +@@ -1985,6 +1984,16 @@ + AC_MSG_RESULT(no) + fi + ++# On Solaris family, we have to use /proc/$$/path/N ++AC_MSG_CHECKING(for /proc/*/path) ++if test -d /proc/$$/path; then ++ AC_DEFINE(HAVE_PROC_DIR_PATH, 1) ++ AC_MSG_RESULT(yes) ++else ++ AC_MSG_RESULT(no) ++fi ++ ++ + dnl "tcpd" "tcpwrappers" + # on some platforms, raw linking with libwrap fails because allow_severity and + # deny_severity are not explicitely defined. Thus we put the libwrap part to +diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat-openssltunnel.html socat-1.7.4.4/doc/socat-openssltunnel.html +--- socat-1.7.4.3/doc/socat-openssltunnel.html 2016-07-21 23:28:19.000000000 +0200 ++++ socat-1.7.4.4/doc/socat-openssltunnel.html 2022-10-30 16:21:47.896474048 +0100 +@@ -42,13 +42,13 @@ + FILENAME=server + +

Generate a public/private key pair:

+-openssl genrsa -out $FILENAME.key 1024 ++openssl genrsa -out $FILENAME.key 2048 + +

Generate a self signed certificate:

+ + openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt +

You will be prompted for your country code, name etc.; you may quit all prompts +-with the enter key.

++with the ENTER key, except for the Common Name which must be exactly the name or IP address of the server that the client will use.

+

Generate the PEM file by just appending the key and certificate files:

+ cat $FILENAME.key $FILENAME.crt >$FILENAME.pem + +@@ -70,7 +70,7 @@ +

First prepare a different basename for the files related to the client certificate:

+ FILENAME=client + +-

Repeat the procedure for certificate generation described above. ++

Repeat the procedure for certificate generation described above. A special common name is not required. + Copy client.pem to the SSL client, and client.crt to the + server.

+ +@@ -81,7 +81,7 @@ + ceritificate and private key, and cafile=... points to the file + containing the certificate of the peer; we trust clients only if they can proof + that they have the related private key (OpenSSL handles this for us):

+-socat openssl-listen:4433,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt echo ++socat OPENSSL-LISTEN:4433,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt PIPE +

After starting this command, socat should be listening on port 4433, but + will require client authentication.

+ +@@ -89,7 +89,7 @@ +

Substitute your tcp-connect or tcp address keyword with + openssl-connect or just ssl and here too add the + cert and cafile options:

+-socat stdio openssl-connect:server.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt ++socat STDIO OPENSSL-CONNECT:server.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt +

This command should establish a secured connection to the server + process.

+ +@@ -100,10 +100,10 @@ + address of the server:

+

Server:

+ socat +-openssl-listen:4433,pf=ip6,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt echo ++OPENSSL-LISTEN:4433,pf=ip6,reuseaddr,cert=$HOME/etc/server.pem,cafile=$HOME/etc/client.crt PIPE + +

Client:

+-socat stdio openssl-connect:ip6name.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt ++socat STDIO OPENSSL-CONNECT:ip6name.domain.org:4433,cert=$HOME/etc/client.pem,cafile=$HOME/etc/server.crt + +

Troubleshooting

+ +@@ -153,8 +153,11 @@ + present a trusted certificate. socat's OpenSSL implementation still does not + check the contents of a certificate like host name or host address. +

++

++ Socat 1.7.3.0 introduces check of servers commonname by the client, and optionally check of clients commonname by the server. ++

+ +-

This document was last modified in March 2007.

++

This document was last modified in Oct. 2023.

+ +

More info about socat OpenSSL

+ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat-tun.html socat-1.7.4.4/doc/socat-tun.html +--- socat-1.7.4.3/doc/socat-tun.html 2016-07-21 23:28:19.000000000 +0200 ++++ socat-1.7.4.4/doc/socat-tun.html 2022-10-30 16:21:47.896474048 +0100 +@@ -68,7 +68,7 @@ + +

+ After successful connection both TUN interfaces should be active and transfer +-date between each other using the TCP connection. Try this by pinging ++data between each other using the TCP connection. Try this by pinging + 192.168.255.1 from the client and 192.168.255.2 from the server. +

+ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.1 socat-1.7.4.4/doc/socat.1 +--- socat-1.7.4.3/doc/socat.1 2022-01-08 22:10:29.000000000 +0100 ++++ socat-1.7.4.4/doc/socat.1 2022-10-30 16:21:47.900474067 +0100 +@@ -3792,7 +3792,7 @@ + SOCAT_IP_DSTADDR: it contains the target address of the packet which may be a + unicast, multicast, or broadcast address\&. + .IP +-.IP "\fB\f(CWecho \-e \(dq\&M\-SEARCH * HTTP/1\&.1\enHOST: 239\&.255\&.255\&.250:1900\enMAN: \e\(dq\&ssdp:discover\e\(dq\&\enMX: 4\enST: \e\(dq\&ssdp:all\e\(dq\&\en\(dq\& |\&./socat \- UDP\-DATAGRAM:239\&.255\&.255\&.250:1900,crlf\fP\fP" ++.IP "\fB\f(CWecho \-e \(dq\&M\-SEARCH * HTTP/1\&.1\enHOST: 239\&.255\&.255\&.250:1900\enMAN: \e\(dq\&ssdp:discover\e\(dq\&\enMX: 4\enST: \e\(dq\&ssdp:all\e\(dq\&\en\(dq\& |socat \- UDP\-DATAGRAM:239\&.255\&.255\&.250:1900,crlf\fP\fP" + + .IP + sends an SSDP (Simple Service Discovery Protocol) query to the local network +diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.html socat-1.7.4.4/doc/socat.html +--- socat-1.7.4.3/doc/socat.html 2022-01-08 22:10:29.000000000 +0100 ++++ socat-1.7.4.4/doc/socat.html 2022-10-30 16:21:47.900474067 +0100 +@@ -1,26 +1,10 @@ + +-socat +- +- +- +-
+-

socat

+- +- +- +- +- +-
+-

+- +- + <strong>socat</strong> + + + +
+

socat

+-

+ + +

+@@ -3665,7 +3649,7 @@ + unicast, multicast, or broadcast address. +

+ +-

echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |./socat - UDP-DATAGRAM:239.255.255.250:1900,crlf
++

echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |socat - UDP-DATAGRAM:239.255.255.250:1900,crlf
+

+ sends an SSDP (Simple Service Discovery Protocol) query to the local network + and collects and outputs the answers received. +diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.yo socat-1.7.4.4/doc/socat.yo +--- socat-1.7.4.3/doc/socat.yo 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/doc/socat.yo 2022-10-30 16:21:47.900474067 +0100 +@@ -3578,7 +3578,7 @@ + + + label(EXAMPLE_SSD) +-dit(bf(tt(echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |./socat - UDP-DATAGRAM:239.255.255.250:1900,crlf))) ++dit(bf(tt(echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |socat - UDP-DATAGRAM:239.255.255.250:1900,crlf))) + + sends an SSDP (Simple Service Discovery Protocol) query to the local network + and collects and outputs the answers received. +diff -r -N -U 3 --no-dereference socat-1.7.4.3/error.c socat-1.7.4.4/error.c +--- socat-1.7.4.3/error.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/error.c 2022-10-30 16:21:47.884473989 +0100 +@@ -37,6 +37,7 @@ + int exitstatus; /* pass signal number to error exit */ + bool withhostname; /* in custom logs add hostname */ + char *hostname; ++ bool signalsafe; + } ; + + +@@ -44,7 +45,7 @@ + + + struct diag_opts diagopts = +- { NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0 } ; ++ { NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0, false, NULL, true } ; + + static void msg2( + #if HAVE_CLOCK_GETTIME +@@ -134,8 +135,10 @@ + diaginitialized = 1; + /* gcc with GNU libc refuses to set this in the initializer */ + diagopts.logfile = stderr; +- if (diag_sock_pair() < 0) { +- return -1; ++ if (diagopts.signalsafe) { ++ if (diag_sock_pair() < 0) { ++ return -1; ++ } + } + return 0; + } +@@ -143,6 +146,16 @@ + + + void diag_set(char what, const char *arg) { ++ switch (what) { ++ case 'I': ++ if (diagopts.signalsafe) { ++ if (diag_sock_send >= 0) { Close(diag_sock_send); diag_sock_send = -1; } ++ if (diag_sock_recv >= 0) { Close(diag_sock_recv); diag_sock_recv = -1; } ++ } ++ diagopts.signalsafe = false; ++ return; ++ } ++ + DIAG_INIT; + switch (what) { + const struct wordent *keywd; +@@ -240,7 +253,10 @@ + int diag_fork() { + Close(diag_sock_send); + Close(diag_sock_recv); +- return diag_sock_pair(); ++ if (diagopts.signalsafe) { ++ return diag_sock_pair(); ++ } ++ return 0; + } + + /* Linux and AIX syslog format: +@@ -281,7 +297,7 @@ + diag_dgram.level = level; + diag_dgram.exitcode = diagopts.exitstatus; + vsnprintf_r(diag_dgram.text, sizeof(diag_dgram.text), format, ap); +- if (diag_in_handler && !diag_immediate_msg) { ++ if (diagopts.signalsafe && diag_in_handler && !diag_immediate_msg) { + send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN + strlen(diag_dgram.text)+1, + 0 /* for canonical reasons */ + #ifdef MSG_DONTWAIT +@@ -317,8 +333,8 @@ + #if HAVE_STRFTIME + struct tm struct_tm; + #endif +-#define BUFLEN 512 +- char buff[BUFLEN], *bufp, *syslp; ++#define MSGLEN 512 ++ char buff[MSGLEN+2], *bufp = buff, *syslp; + size_t bytes; + + #if HAVE_CLOCK_GETTIME +@@ -328,12 +344,14 @@ + #else + epoch = *now; + #endif ++ /*! consider caching instead of recalculating many times per second */ + #if HAVE_STRFTIME +- bytes = strftime(buff, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm)); +- buff[bytes] = '\0'; ++ bytes = strftime(bufp, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm)); + #else +- bytes = snprintf(buff, 11, F_time, epoch); ++ bytes = snprintf(bufp, 11, F_time, epoch); + #endif ++ bufp += bytes; ++ *bufp = '\0'; + if (diagopts.micros) { + #if HAVE_CLOCK_GETTIME + micros = now->tv_nsec/1000; +@@ -342,29 +360,38 @@ + #else + micros = 0; + #endif +- bytes += sprintf(buff+19, ".%06lu ", micros); ++ bufp += sprintf(bufp, ".%06lu ", micros); + } else { +- buff[19] = ' '; buff[20] = '\0'; ++ *bufp++ = ' '; ++ *bufp = '\0'; + } +- bytes = strlen(buff); + +- bufp = buff + bytes; + if (diagopts.withhostname) { +- bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes; +- } +- bytes = sprintf(bufp, "%s["F_pid"] ", diagopts.progname, getpid()); ++ bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s ", diagopts.hostname); ++ if (bytes >= MSGLEN-(bufp-buff)) ++ bytes = MSGLEN-(bufp-buff)-1; ++ bufp += bytes; ++ } ++ bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s["F_pid"] ", diagopts.progname, getpid()); ++ if (bytes >= MSGLEN-(bufp-buff)) ++ bytes = MSGLEN-(bufp-buff)-1; + bufp += bytes; +- syslp = bufp; +- *bufp++ = "DINWEF"[level]; ++ syslp = bufp; /* syslog prefixes with time etc.itself */ ++ if (bufp < buff+MSGLEN) ++ *bufp++ = "DINWEF"[level]; + #if 0 /* only for debugging socat */ +- if (handler) bufp[-1] = tolower(bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */ ++ if (handler) bufp[-1] = tolower((unsigned char)bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */ + #endif +- *bufp++ = ' '; +- strncpy(bufp, text, BUFLEN-(bufp-buff)-1); +- strcat(bufp, "\n"); ++ if (bufp < buff+MSGLEN) ++ *bufp++ = ' '; ++ strncpy(bufp, text, MSGLEN-(bufp-buff)); ++ bufp = strchr(bufp, '\0'); ++ strcpy(bufp, "\n"); + _msg(level, buff, syslp); + if (level >= diagopts.exitlevel) { + if (E_NOTICE >= diagopts.msglevel) { ++ if ((syslp - buff) + 16 > MSGLEN+1) ++ syslp = buff + MSGLEN - 15; + snprintf_r(syslp, 16, "N exit(%d)\n", exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1)); + _msg(E_NOTICE, buff, syslp); + } +@@ -388,6 +415,11 @@ + void diag_flush(void) { + struct diag_dgram recv_dgram; + char exitmsg[20]; ++ ++ if (!diagopts.signalsafe) { ++ return; ++ } ++ + while (recv(diag_sock_recv, &recv_dgram, sizeof(recv_dgram)-1, + 0 /* for canonical reasons */ + #ifdef MSG_DONTWAIT +diff -r -N -U 3 --no-dereference socat-1.7.4.3/fdname.c socat-1.7.4.4/fdname.c +--- socat-1.7.4.3/fdname.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/fdname.c 2022-10-30 16:21:47.884473989 +0100 +@@ -60,7 +60,7 @@ + } + } + +-#if HAVE_PROC_DIR_FD ++#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH + static int procgetfdname(int fd, char *filepath, size_t pathsize) { + static pid_t pid = -1; + char procpath[PATH_MAX]; +@@ -91,30 +91,36 @@ + #endif /* !HAVE_STAT64 */ + + if (pid < 0) pid = Getpid(); +- snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/fd/%d", pid, fd); ++ snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/" ++#if HAVE_PROC_DIR_PATH ++ "path" ++#else ++ "fd" ++#endif ++ "/%d", pid, fd); + if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) { +- Error4("readlink(\"%s\", %p, "F_Zu"): %s", ++ Warn4("readlink(\"%s\", %p, "F_Zu"): %s", + procpath, filepath, pathsize, strerror(errno)); +- return -1; ++ len = 0; + } + filepath[len] = '\0'; + return 0; + } +-#endif /* HAVE_PROC_DIR_FD */ ++#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */ + + int statname(const char *file, int fd, int filetype, FILE *outfile, + char style) { + char filepath[PATH_MAX]; + + filepath[0] = '\0'; +-#if HAVE_PROC_DIR_FD ++#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH + if (fd >= 0) { + procgetfdname(fd, filepath, sizeof(filepath)); + if (filepath[0] == '/') { + file = filepath; + } + } +-#endif /* HAVE_PROC_DIR_FD */ ++#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */ + /* now see for type specific infos */ + switch (filetype) { + case (S_IFIFO>>12): /* 1, FIFO */ +@@ -156,6 +162,18 @@ + return -1; + #endif /* !_WITH_SOCKET */ + break; ++#ifdef S_IFDOOR ++ case (S_IFDOOR>>12): /* 13, door (Solaris) */ ++ fputs("door", outfile); ++ if (file) fprintf(outfile, " %s", file); ++ break; ++#endif /* HAVE_MACRO_S_IFDOOR */ ++#ifdef S_IFPORT ++ case (S_IFPORT>>12): /* 14, event port (Solaris) */ ++ fputs("event_port", outfile); ++ if (file) fprintf(outfile, " %s", file); ++ break; ++#endif /* HAVE_MACRO_S_IFPORT */ + } + /* ioctl() */ + fputc('\n', outfile); +@@ -237,12 +255,21 @@ + #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) + optlen = sizeof(proto); + #ifdef SO_PROTOCOL +- Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen); ++ rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen); + #elif defined(SO_PROTOTYPE) +- Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen); ++ rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen); + #endif ++ if (rc < 0) { ++ Warn5("getsocktop(%d, SOL_SOCKET, " ++#ifdef SO_PROTOCOL ++ "SO_PROTOCOL" ++#else ++ "SO_PROTOTYPE" ++#endif ++ ", &%p, {"F_socklen"}): errno=%d (%s)", fd, &proto, optlen, errno, strerror(errno)); ++ } ++ proto = 0; + #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */ +- + optlen = sizeof(opttype); + Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen); + sockettype(opttype, typename, sizeof(typename)); +@@ -261,8 +288,12 @@ + } + strncpy(protoname, protoentp->p_name, sizeof(protoname)); + #elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */ +- protoentp = getprotobynumber(proto); +- strncpy(protoname, protoentp->p_name, sizeof(protoname)); ++ { ++# define FILAN_GETPROTOBYNUMBER_R_BUFLEN 1024 ++ char buffer[FILAN_GETPROTOBYNUMBER_R_BUFLEN]; ++ protoentp = getprotobynumber_r(proto, &protoent, buffer, FILAN_GETPROTOBYNUMBER_R_BUFLEN); ++ strncpy(protoname, protoentp->p_name, sizeof(protoname)); ++ } + #elif HAVE_GETPROTOBYNUMBER_R==3 /* AIX */ + { + struct protoent_data proto_data; +diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan.c socat-1.7.4.4/filan.c +--- socat-1.7.4.3/filan.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/filan.c 2022-10-30 16:21:47.884473989 +0100 +@@ -79,17 +79,20 @@ + default: + if ((fd = + Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK ++#ifdef O_NOFOLLOW ++ |(filan_followsymlinks?0:O_NOFOLLOW) ++#endif + #ifdef O_LARGEFILE + |O_LARGEFILE + #endif + , 0700)) + < 0) { +- Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s", ++ Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE, 0700): %s", + filename, strerror(errno)); + } + } + +- result = filan_stat(&buf, fd, -1, outfile); ++ result = filan_stat(&buf, fd, -1, outfile, filename); + fputc('\n', outfile); + return result; + } +@@ -119,7 +122,7 @@ + } + Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode)); + +- result = filan_stat(&buf, fd, fd, outfile); ++ result = filan_stat(&buf, fd, fd, outfile, NULL); + + if (result >= 0) { + /* even more dynamic info */ +@@ -212,7 +215,12 @@ + #else + struct stat *buf + #endif /* !HAVE_STAT64 */ +- , int statfd, int dynfd, FILE *outfile) { ++ , int statfd, int dynfd, FILE *outfile, ++ const char *filename /* Linux does not (yet) provide an ++ freadlink system call, so we need ++ the original name for readlink in ++ case it is a symlink */ ++ ) { + char stdevstr[8]; + + /* print header */ +@@ -380,7 +388,11 @@ + break; + case (S_IFREG): /* 8, regular file */ + break; ++#ifdef S_IFLNK + case (S_IFLNK): /* 10, symbolic link */ ++ /* we wait for freadlink() sytem call */ ++ break; ++#endif /* S_IFLNK */ + break; + #ifdef S_IFSOCK + case (S_IFSOCK): /* 12, socket */ +@@ -393,6 +405,19 @@ + break; + #endif /* S_IFSOCK */ + } ++ } else { ++ switch (buf->st_mode&S_IFMT) { ++#ifdef S_IFLNK ++ case (S_IFLNK): /* 10, symbolic link */ ++ { ++ char linktarget[PATH_MAX+1]; ++ memset(linktarget, 0, PATH_MAX+1); ++ Readlink(filename, linktarget, PATH_MAX); ++ fprintf(outfile, "LINKTARGET=%s", linktarget); ++ } ++ break; ++#endif /* S_IFLNK */ ++ } + } + /* ioctl() */ + return 0; +@@ -917,7 +942,7 @@ + fd, &tcpinfo, sizeof(tcpinfo), strerror(errno)); + return -1; + } +- fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state); ++ fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state); + #if 0 /* on BSD these components are prefixed with __ - I get tired... */ + fprintf(outfile, "%s={%u}\t", "TCPI_CA_STATE", tcpinfo.tcpi_ca_state); + fprintf(outfile, "%s={%u}\t", "TCPI_RETRANSMITS", tcpinfo.tcpi_retransmits); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan.h socat-1.7.4.4/filan.h +--- socat-1.7.4.3/filan.h 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/filan.h 2022-10-30 16:21:47.888474009 +0100 +@@ -22,7 +22,8 @@ + #else + struct stat *buf + #endif /* !HAVE_STAT64 */ +- , int statfd, int dynfd, FILE *outfile); ++ , int statfd, int dynfd, FILE *outfile, ++ const char *filename); + + extern int cdevan(int fd, FILE *outfile); + +diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan_main.c socat-1.7.4.4/filan_main.c +--- socat-1.7.4.3/filan_main.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/filan_main.c 2022-10-30 16:21:47.888474009 +0100 +@@ -21,7 +21,7 @@ + + + int main(int argc, const char *argv[]) { +- const char **arg1, *a; ++ const char **arg1, *a0, *a; + const char *filename = NULL, *waittimetxt; + unsigned int m = 0; /* first FD (default) */ + unsigned int n = FD_SETSIZE; /* last excl. */ +@@ -32,6 +32,7 @@ + const char *outfname = NULL; + unsigned long fildes; + ++ diag_set('I', false); + diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); + + arg1 = argv+1; --argc; +@@ -50,27 +51,39 @@ + case 'S': style = arg1[0][1]; break; + case 'r': filan_rawoutput = true; break; + case 'i': if (arg1[0][2]) { +- a = *arg1+2; ++ a = a0 = *arg1+2; + } else { + ++arg1, --argc; +- if ((a = *arg1) == NULL) { ++ if ((a = a0 = *arg1) == NULL) { + Error("option -i requires an argument"); + filan_usage(stderr); exit(1); + } + } + m = strtoul(a, (char **)&a, 0); ++ if (a == a0) { ++ Error1("not a numerical arg in \"-b %s\"", a0); ++ } ++ if (*a != '\0') { ++ Error1("trailing garbage in \"-b %s\"", a0); ++ } + n = m; + break; + case 'n': if (arg1[0][2]) { +- a = *arg1+2; ++ a = a0 = *arg1+2; + } else { + ++arg1, --argc; +- if ((a = *arg1) == NULL) { ++ if ((a = a0 = *arg1) == NULL) { + Error("option -n requires an argument"); + filan_usage(stderr); exit(1); + } + } + n = strtoul(a, (char **)&a, 0); ++ if (a == a0) { ++ Error1("not a numerical arg in \"-b %s\"", a0); ++ } ++ if (*a != '\0') { ++ Error1("trailing garbage in \"-b %s\"", a0); ++ } + break; + case 'f': if (arg1[0][2]) { + filename = *arg1+2; +@@ -135,7 +148,7 @@ + else if (!strcmp(outfname,"stderr")) { fdout=stderr; } + /* file descriptor */ + else if (*outfname == '+') { +- a = outfname+1; ++ a = outfname+1; + fildes = strtoul(a, (char **)&a, 0); + if ((fdout = fdopen(fildes, "w")) == NULL) { + Error2("can't fdopen file descriptor %lu: %s\n", fildes, strerror(errno)); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/socat.c socat-1.7.4.4/socat.c +--- socat-1.7.4.3/socat.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/socat.c 2022-10-30 16:21:47.888474009 +0100 +@@ -238,7 +238,7 @@ + Exit(1); + } + } +- socat_opts.bufsiz = strtoul(a, (char **)&a, 0); ++ socat_opts.bufsiz = Strtoul(a, (char **)&a, 0, "-b"); + break; + case 's': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); } + diag_set_int('e', E_FATAL); break; +@@ -251,7 +251,7 @@ + Exit(1); + } + } +- rto = strtod(a, (char **)&a); ++ rto = Strtod(a, (char **)&a, "-t"); + socat_opts.closwait.tv_sec = rto; + socat_opts.closwait.tv_usec = + (rto-socat_opts.closwait.tv_sec) * 1000000; +@@ -265,7 +265,7 @@ + Exit(1); + } + } +- rto = strtod(a, (char **)&a); ++ rto = Strtod(a, (char **)&a, "-T"); + socat_opts.total_timeout.tv_sec = rto; + socat_opts.total_timeout.tv_usec = + (rto-socat_opts.total_timeout.tv_sec) * 1000000; +diff -r -N -U 3 --no-dereference socat-1.7.4.3/socat.spec socat-1.7.4.4/socat.spec +--- socat-1.7.4.3/socat.spec 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/socat.spec 2022-10-30 16:21:47.888474009 +0100 +@@ -1,6 +1,6 @@ + + %define majorver 1.7 +-%define minorver 4.3 ++%define minorver 4.4 + + Summary: socat - multipurpose relay + Name: socat +Binary files socat-1.7.4.3/socat.tar and socat-1.7.4.4/socat.tar differ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sslcls.c socat-1.7.4.4/sslcls.c +--- socat-1.7.4.3/sslcls.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/sslcls.c 2022-10-30 16:21:47.888474009 +0100 +@@ -21,7 +21,7 @@ + #include "sysutils.h" + #include "sycls.h" + +-#if HAVE_OPENSSL_init_ssl ++#if HAVE_OPENSSL_INIT_SSL + int sycOPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) { + int result; + Debug2("OPENSSL_init_ssl("F_uint64_t", %p)", opts, settings); +@@ -31,7 +31,7 @@ + } + #endif + +-#if !HAVE_OPENSSL_init_ssl ++#if !HAVE_OPENSSL_INIT_SSL + void sycSSL_load_error_strings(void) { + Debug("SSL_load_error_strings()"); + SSL_load_error_strings(); +@@ -39,7 +39,7 @@ + } + #endif + +-#if !HAVE_OPENSSL_init_ssl ++#if !HAVE_OPENSSL_INIT_SSL + int sycSSL_library_init(void) { + int result; + Debug("SSL_library_init()"); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sslcls.h socat-1.7.4.4/sslcls.h +--- socat-1.7.4.3/sslcls.h 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/sslcls.h 2022-10-30 16:21:47.888474009 +0100 +@@ -8,7 +8,7 @@ + #if WITH_SYCLS + #if WITH_OPENSSL + +-#if HAVE_OPENSSL_init_ssl ++#if HAVE_OPENSSL_INIT_SSL + int sycOPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings); + #endif + void sycSSL_load_error_strings(void); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sycls.c socat-1.7.4.4/sycls.c +--- socat-1.7.4.3/sycls.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/sycls.c 2022-10-30 16:21:47.888474009 +0100 +@@ -677,7 +677,10 @@ + _errno = errno; + if (!diag_in_handler) diag_flush(); + #if WITH_SYCLS +- Debug1("ioctl() -> %d", retval); ++ if (retval < 0) ++ Debug2("ioctl() -> %d, errno=%d", retval, _errno); ++ else ++ Debug1("ioctl() -> %d", retval); + #endif /* WITH_SYCLS */ + errno = _errno; + return retval; +@@ -1736,6 +1739,7 @@ + } + #endif + ++ + #if WITH_READLINE + + char *Readline(const char *prompt) { +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sycls.h socat-1.7.4.4/sycls.h +--- socat-1.7.4.3/sycls.h 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/sycls.h 2022-10-30 16:21:47.888474009 +0100 +@@ -167,6 +167,8 @@ + int Mkstemp(char *template); + int Setenv(const char *name, const char *value, int overwrite); + void Unsetenv(const char *name); ++#endif /* WITH_SYCLS */ ++#if WITH_SYCLS + + char *Readline(const char *prompt); + void Using_history(void); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sysutils.c socat-1.7.4.4/sysutils.c +--- socat-1.7.4.3/sysutils.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/sysutils.c 2022-10-30 16:21:47.888474009 +0100 +@@ -745,7 +745,7 @@ + progname = diag_get_string('p'); + envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1); + l = strlen(envname); +- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]); ++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]); + strncat(envname+l, "_", XIO_ENVNAMELEN-l-1); + l += 1; + strncat(envname+l, varname, XIO_ENVNAMELEN-l-1); +@@ -771,7 +771,7 @@ + l += 1; + strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1); + l += strlen(envname+l); +- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]); ++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]); + return _xiosetenv(envname, value, overwrite, sep); + # undef XIO_ENVNAMELEN + } +@@ -799,7 +799,7 @@ + l += 1; + strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1); + l += strlen(envname+l); +- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]); ++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]); + return _xiosetenv(envname, value, overwrite, sep); + # undef XIO_ENVNAMELEN + } +@@ -824,3 +824,45 @@ + return xiosetenv(varname, envbuff, overwrite, NULL); + # undef XIO_SHORTLEN + } ++ ++ ++unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt) { ++ unsigned long res; ++ ++ res = strtoul(nptr, endptr, base); ++ if (nptr == *endptr) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", txt); ++ } ++ if (**endptr != '\0') { ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt); ++ } ++ return res; ++} ++ ++#if HAVE_STRTOLL ++long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt) { ++ long long int res; ++ ++ res = strtoul(nptr, endptr, base); ++ if (nptr == *endptr) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", txt); ++ } ++ if (**endptr != '\0') { ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt); ++ } ++ return res; ++} ++#endif /* HAVE_STRTOLL */ ++ ++double Strtod(const char *nptr, char **endptr, const char *txt) { ++ double res; ++ ++ res = strtod(nptr, endptr); ++ if (nptr == *endptr) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", txt); ++ } ++ if (**endptr != '\0') { ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt); ++ } ++ return res; ++} +diff -r -N -U 3 --no-dereference socat-1.7.4.3/sysutils.h socat-1.7.4.4/sysutils.h +--- socat-1.7.4.3/sysutils.h 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/sysutils.h 2022-10-30 16:21:47.888474009 +0100 +@@ -107,5 +107,8 @@ + int overwrite); + extern int xiosetenvushort(const char *varname, unsigned short value, + int overwrite); ++extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt); ++extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt); ++extern double Strtod(const char *nptr, char **endptr, const char *txt); + + #endif /* !defined(__sysutils_h_included) */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/test.sh socat-1.7.4.4/test.sh +--- socat-1.7.4.3/test.sh 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/test.sh 2022-10-30 16:21:47.892474028 +0100 +@@ -51,6 +51,18 @@ + [ -z "$SECONDs" ] && SECONDs=0 + + withroot=0 # perform privileged tests even if not run by root ++ ++[ -z "$SOCAT" ] && SOCAT="./socat" ++if ! [ -x "$SOCAT" ] && ! type $SOCAT >/dev/null 2>&1; then ++ echo "$SOCAT does not exist" >&2; exit 1; ++fi ++if [ "$SOCAT" = socat ]; then ++ SOCAT=$(type -p socat) || SOCAT=$(which socat) ++fi ++#echo $SOCAT ++if [ -z "$PROCAN" ]; then if test -x ./procan; then PROCAN="./procan"; elif type procan >/dev/null 2>&1; then PROCAN=procan; elif test -x ${SOCAT%/*}/procan; then PROCAN=${SOCAT%/*}/procan; else PROCAN=false; fi; fi ++if [ -z "$FILAN" ]; then if test -x ./filan; then FILAN="./filan"; elif ! type filan >/dev/null 2>&1; then FILAN=filan; elif test -x ${SOCAT%/*}/filan; then FILAN=${SOCAT%/*}/filan; else FILAN=false; fi; fi ++ + #PATH=$PATH:/opt/freeware/bin + #PATH=$PATH:/usr/local/ssl/bin + PATH=$PATH:/sbin # RHEL6:ip +@@ -60,23 +72,18 @@ + #OPENSSL_RAND="-rand /dev/egd-pool" + #SOCAT_EGD="egd=/dev/egd-pool" + MISCDELAY=1 +-[ -z "$SOCAT" ] && SOCAT="./socat" +-if ! [ -x "$SOCAT" ] && ! type $SOCAT >/dev/null 2>&1; then +- echo "$SOCAT does not exist" >&2; exit 1; +-fi +-if [ -z "$PROCAN" ]; then if test -x ./procan; then PROCAN="./procan"; elif type procan >/dev/null 2>&1; then PROCAN=procan; elif test -x ${SOCAT%/*}/procan; then PROCAN=${SOCAT%/*}/procan; else PROCAN=false; fi; fi +-if [ -z "$FILAN" ]; then if test -x ./filan; then FILAN="./filan"; elif ! type filan >/dev/null 2>&1; then FILAN=filan; elif test -x ${SOCAT%/*}/filan; then FILAN=${SOCAT%/*}/filan; else FILAN=false; fi; fi ++ + opts="$opt_t $OPTS" + export SOCAT_OPTS="$opts" + #debug="1" + debug= + TESTS="$*"; export TESTS +-if ! $SOCAT -V >/dev/null 2>&1; then ++if ! SOCAT_MAIN_WAIT= $SOCAT -V >/dev/null 2>&1; then + echo "Failed to execute $SOCAT, exiting" >&2 + exit 1 + fi + +-SOCAT_VERSION=$($SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/') ++SOCAT_VERSION=$(SOCAT_MAIN_WAIT= $SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/') + if [ -z "$SOCAT_VERSION" ]; then + echo "Warning: failed to retrieve Socat version" >&2 + fi +@@ -263,8 +270,8 @@ + # PTYOPTS2= + # ;; + SunOS) +- PTYOPTS="echo=0,opost=0,perm=600" +- PTYOPTS2="cfmakeraw" ++ PTYOPTS="perm=600" ++ PTYOPTS2="echo=0,opost=0" + ;; + *) + PTYOPTS="echo=0,opost=0" +@@ -1842,7 +1849,7 @@ + local a A; + for a in $@; do + A=$(echo "$a" |tr 'a-z-' 'A-Z_') +- if $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then ++ if SOCAT_MAIN_WAIT= $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then + if [[ "$A" =~ OPENSSL.* ]]; then + gentestcert testsrv + gentestcert testcli +@@ -2063,6 +2070,7 @@ + runssctp4 () { + runsip4 >/dev/null || { echo SCTP4; return 1; } + $SOCAT -h |grep ' sctp4-' >/dev/null || return 1 ++ $SOCAT /dev/null SCTP4-L:0,accept-timeout=0.001 2>/dev/null || return 1; + return 0; + } + +@@ -2070,6 +2078,7 @@ + runssctp6 () { + runsip6 >/dev/null || { echo SCTP6; return 1; } + $SOCAT -h |grep ' sctp6-' >/dev/null || return 1 ++ $SOCAT /dev/null SCTP6-L:0,accept-timeout=0.001 2>/dev/null || return 1; + return 0; + } + +@@ -2479,6 +2488,12 @@ + return 1 + } + ++# system dependent values ++case "$UNAME" in ++ SunOS) SOCK_SEQPACKET=6 ;; ++ *) SOCK_SEQPACKET=5 ;; ++esac ++ + # generate a test certificate and key + gentestcert () { + local name="$1" +@@ -2535,6 +2550,8 @@ + cat $name.key $name.crt testcert.dh >$name.pem + } + ++#------------------------------------------------------------------------------ ++# Begin of functional tests + + NAME=UNISTDIO + case "$TESTS " in +@@ -2668,7 +2685,7 @@ + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" + else +-testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS" "$opts" ++testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" + fi + esac + N=$((N+1)) +@@ -2684,7 +2701,7 @@ + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" + else +-testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS" "$opts" ++testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts" + fi + esac + N=$((N+1)) +@@ -2996,15 +3013,19 @@ + if [ "$rc2" -ne 0 ]; then + $PRINTF "$FAILED: $TRACE $SOCAT:\n" + echo "$CMD1 &" ++ cat "${te}1" + echo "$CMD2" + echo "rc=$rc2" +- cat "${te}1" + cat "${te}2" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + elif ! echo "$da" |diff - "$tf" >"$tdiff"; then + $PRINTF "$FAILED: diff:\n" + cat "$tdiff" ++ echo "$CMD1 &" ++ cat "${te}1" ++ echo "$CMD2" ++ cat "${te}2" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + else +@@ -3875,10 +3896,6 @@ + *%$N%*|*%functions%*|*%gopen%*|*%unix%*|*%listen%*|*%seqpacket%*|*%$NAME%*) + TEST="$NAME: GOPEN on UNIX seqpacket socket" + if ! eval $NUMCOND; then :; else +- case "$UNAME" in +- SunOS) SOCK_SEQPACKET=6 ;; +- *) SOCK_SEQPACKET=5 ;; +- esac + ts="$td/test$N.socket" + tf="$td/test$N.stdout" + te="$td/test$N.stderr" +@@ -6485,10 +6502,13 @@ + N=$((N+1)) + + ++# Test if Filan can determine UNIX domain socket in file system + NAME=FILANSOCKET + case "$TESTS" in + *%$N%*|*%filan%*|*%$NAME%*) + TEST="$NAME: capability to analyze named unix socket" ++# Run Filan on a listening UNIX domain socket. ++# When its output gives "socket" as type (2nd column), the test succeeded + if ! eval $NUMCOND; then :; else + ts="$td/test$N.socket" + te1="$td/test$N.stderr1" # socat +@@ -6500,10 +6520,16 @@ + type=$($FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print($2);}') + if [ "$type" = "socket" ]; then + $PRINTF "$OK\n" +- numOK=$((numOK+1)) ++ if [ "$VERBOSE" ]; then ++ echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" ++ echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" ++ fi ++ numOK=$((numOK+1)) + else + $PRINTF "$FAILED\n" ++ echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" >&2 + cat "$te1" ++ echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" >&2 + cat "$te2" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +@@ -8534,7 +8560,9 @@ + kill $bg 2>/dev/null; wait + if [ $rc -ne 0 ]; then + $PRINTF "$FAILED: $TRACE $SOCAT:\n" +- echo "$CMD &" ++ echo "$CMD1 &" ++ cat "${te}1" ++ echo "$CMD" + cat "$te" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +@@ -8981,7 +9009,8 @@ + sh="$td/test$N-sed.sh" + echo 'sed s/XXXX/YYYY/' >"$sh" + chmod a+x "$sh" +-CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast exec:$sh" ++# EXEC need not work with script (musl libc), so use SYSTEM ++CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast SYSTEM:$sh" + #CMD2="$TRACE $SOCAT $opts - IP4-BROADCAST:$ts1" + CMD2="$TRACE $SOCAT $opts - IP4-DATAGRAM:$ts1,broadcast" + printf "test $F_n $TEST... " $N +@@ -9390,7 +9419,6 @@ + tdiff="$td/test$N.diff" + tl="$td/test$N.lock" + da="$(date) $RANDOM" +-dalen=$((${#da}+1)) + TUNNET=10.255.255 + TUNNAME=tun9 + CMD1="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME echo" +@@ -9400,7 +9428,7 @@ + pid1="$!" + #waitinterface "$TUNNAME" + sleep 1 +-echo "$da" |$CMD 2>"${te}1" >"$tf" 2>"${te}" ++echo "$da" |$CMD >"$tf" 2>"${te}" + kill $pid1 2>/dev/null + wait + if [ $? -ne 0 ]; then +@@ -9857,6 +9885,7 @@ + # Cygwin: 20 unlimit 256 64 + # AIX: 32767 65534 65534 + # SunOS 8: 20 1024 ++# musl libc: 1024 + NAME=EXCEED_FOPEN_MAX + case "$TESTS" in + *%$N%*|*%functions%*|*%maxfds%*|*%$NAME%*) +@@ -9877,7 +9906,12 @@ + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" + else +-OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX ++ if [ $FOPEN_MAX -lt 270 ]; then ++ OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX ++ else ++ OPEN_FILES=269 # bash tends to SIGSEGV on higher value ++ # btw, the test is obsolete anyway ++ fi + i=3; while [ "$i" -lt "$OPEN_FILES" ]; do + REDIR="$REDIR $i>&2" + i=$((i+1)) +@@ -10541,7 +10575,7 @@ + eval "$CMD0 2>\"${te}0\" >\"$tf\" &" + pid0=$! + wait${protov}port $tsa1 1 +-echo |$CMD1 2>"${te}1" ++{ echo; sleep 0.1; } |$CMD1 2>"${te}1" + rc1=$? + waitfile "$tf" 2 + kill $pid0 2>/dev/null; wait +@@ -10655,7 +10689,7 @@ + eval "$CMD0 >\"$tf\" 2>\"${te}0\" &" + pid0="$!" + wait${proto}port $tra 1 +-echo "XYZ" |$CMD1 2>"${te}1" ++{ echo "XYZ"; sleep 0.1; } |$CMD1 2>"${te}1" + rc1="$?" + waitfile "$tf" 2 + #i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done +@@ -11865,7 +11899,7 @@ + N=$((N+1)) + + +-# PTY address allowed to sepcify address parameters but ignored them ++# PTY address allowed to specify address parameters but ignored them + NAME=PTY_VOIDARG + case "$TESTS" in + *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*) +@@ -13714,11 +13748,13 @@ + te="$td/test$N.stderr" + tdiff="$td/test$N.diff" + da="test$N $(date) $RANDOM" +-CMD0="$TRACE $SOCAT $opts -T 1 STDIO,echo=0 EXEC:cat" ++CMD0="$TRACE $SOCAT $opts -T 1 STDIO,echo=0 EXEC:cat 2>${te}0" + echo "$CMD0" >$td/test$N.sh + chmod a+x $td/test$N.sh ++# EXEC need not work with script (musl libc), so use SYSTEM ++CMD1="$TRACE $SOCAT $opts /dev/null SYSTEM:$td/test$N.sh,pty,$PTYOPTS" + printf "test $F_n $TEST... " $N +-$SOCAT /dev/null EXEC:$td/test$N.sh,pty 2>"${te}0" ++$CMD1 2>"${te}1" + rc0=$? + if [ $rc0 -eq 0 ]; then + $PRINTF "$OK\n" +@@ -13727,6 +13763,8 @@ + $PRINTF "$FAILED\n" + echo "$CMD0" + cat "${te}0" ++ echo "$CMD1" ++ cat "${te}1" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + fi +@@ -13860,7 +13898,7 @@ + # Test if unbalanced quoting in Socat addresses is detected + NAME=UNBALANCED_QUOTE + case "$TESTS" in +-*%$N%*|*%functions%*|*%bugs%*|*%$NAME%*) ++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) + TEST="$NAME: Test fix of unbalanced quoting" + # Invoke Socat with an address containing unbalanced quoting. If Socat prints + # a "syntax error" message, the test succeeds +@@ -13872,8 +13910,10 @@ + CMD0="$TRACE $SOCAT $opts -u FILE:$td/ab\"cd FILE:/dev/null" + printf "test $F_n $TEST... " $N + $CMD0 >/dev/null 2>"${te}0" +-if grep -q "syntax error" "${te}0"; then ++if grep -q -i -e "syntax error" -e "unexpected end" "${te}0"; then + $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi ++ if [ "$debug" ]; then cat ${te} >&2; fi + numOK=$((numOK+1)) + else + $PRINTF "$FAILED\n" +@@ -14525,8 +14565,8 @@ + listCANT="$listCANT $N" + else + # Second, set accept-timeout and see if socat exits before kill +-CMD2="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr,accept-timeout=1 PIPE" >"$te1" & +-$CMD2 >"$te1" 2>&1 "$te2" 2>&1 "$tk2"; then +@@ -14666,10 +14706,15 @@ + NAME=VSOCK_ECHO + case "$TESTS" in + *%$N%*|*%functions%*|*%vsock%*|*%socket%*|*%$NAME%*) +-TEST="$NAME: test communication via vsock loopback socket" ++TEST="$NAME: test communication via VSOCK loopback socket" + # Start a listening echo server + # Connect with a client, send data and compare reply with original data +-if ! eval $NUMCOND; then :; else ++if ! eval $NUMCOND; then :; ++elif ! fea=$(testfeats VSOCK); then ++ $PRINTF "test $F_n $TEST... ${YELLOW}$fea 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" +@@ -14691,6 +14736,10 @@ + $PRINTF "${YELLOW}works only on Linux from 5.6${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" ++elif grep -q "No such device" "${te}1"; then ++ $PRINTF "${YELLOW}Loopback does not work${NORMAL}\n" $N ++ numCANT=$((numCANT+1)) ++ listCANT="$listCANT $N" + elif [ $rc1 -ne 0 ]; then + $PRINTF "$FAILED\n" + echo "$CMD0 &" >&2 +@@ -15245,6 +15294,368 @@ + PORT=$((PORT+1)) + N=$((N+1)) + ++# Socats access to different types of file system entries using various kinds ++# of addresses fails in a couple of useless combinations. These failures have ++# to print an error message and exit with return code 1. ++# Up to version 1.7.4.2 this desired behaviour was found for most combinations, ++# however some fix in 1.7.4.3 degraded the overall result. ++# This group of tests checks all known compinations. ++while read entry method; do ++if [ -z "$entry" ] || [[ "$entry" == \#* ]]; then continue; fi ++NAME=$(toupper $method)_TO_$(toupper $entry) ++case "$TESTS" in ++*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*) ++#set -vx ++TEST="$NAME: Failure handling on $method access to $entry" ++# Create some kind of system entry and try to access it with some improper ++# address. Check if Socat returns with rc 1 and prints an error message ++if ! eval $NUMCOND; then :; else ++ts="$td/test$N.socket" ++tf="$td/test$N.stdout" ++te="$td/test$N.stderr" ++tdiff="$td/test$N.diff" ++da="test$N $(date) $RANDOM" ++ ++printf "test $F_n $TEST... " $N ++# create an invalid or non-matching UNIX socket ++case "$entry" in ++ missing) pid0=; rm -f $ts ;; ++ denied) pid0=; rm -f $ts; touch $ts; chmod 000 $ts ;; ++ directory) pid0=; mkdir -p $ts ;; ++ orphaned) pid0= # the remainder of a UNIX socket in FS ++ SOCAT_MAIN_WAIT= $SOCAT $opts UNIX-LISTEN:$ts,unlink-close=0 /dev/null >${tf}0 2>${te}0 & ++ waitunixport $ts 1 ++ SOCAT_MAIN_WAIT= $SOCAT $opts /dev/null UNIX-CONNECT:$ts >>${tf}0 2>>${te}0 ++ ;; ++ file) pid0=; rm -f $ts; touch $ts ;; ++ stream) CMD0="$SOCAT $opts UNIX-LISTEN:$ts /dev/null" ++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & ++ pid0=$! ;; ++ dgram) CMD0="$SOCAT $opts -u UNIX-RECV:$ts /dev/null" ++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & ++ pid0=$! ;; ++ seqpacket) CMD0="$SOCAT $opts UNIX-LISTEN:$ts,socktype=$SOCK_SEQPACKET /dev/null" ++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 & ++ pid0=$! ;; ++esac ++[ "$pid0" ] && waitunixport $ts 1 ++# try to access this socket ++case "$method" in ++ connect) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts" ;; ++ send) CMD1="$TRACE $SOCAT $opts -u - UNIX-SEND:$ts" ;; ++ sendto) CMD1="$TRACE $SOCAT $opts -u - UNIX-SENDTO:$ts" ;; ++ seqpacket) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts,socktype=$SOCK_SEQPACKET" ;; ++ unix) CMD1="$TRACE $SOCAT $opts -u - UNIX-CLIENT:$ts" ;; ++ gopen) CMD1="$TRACE $SOCAT $opts -u - GOPEN:$ts" ;; ++esac ++echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" ++rc1=$? ++[ "$pid0" ] && { kill $pid0 2>/dev/null; wait; } ++if [ $rc1 != 1 ]; then ++ $PRINTF "$FAILED (bad return code $rc1)\n" ++ if [ "$pid0" ]; then ++ echo "$CMD0 &" >&2 ++ cat "${te}0" >&2 ++ fi ++ echo "$CMD1" >&2 ++ cat "${te}1" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++elif nerr=$(grep ' E ' "${te}1" |wc -l); test "$nerr" -ne 1; then ++ $PRINTF "$FAILED ($nerr error message(s) instead of 1)\n" ++ if [ "$pid0" ]; then ++ echo "$CMD0 &" >&2 ++ cat "${te}0" >&2 ++ fi ++ echo "$CMD1" >&2 ++ cat "${te}1" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++else ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then ++ if [ "$pid0" ]; then echo "$CMD0 &" >&2; fi ++ echo "$CMD1" >&2 ++ fi ++ numOK=$((numOK+1)) ++fi ++set +vx ++fi # NUMCOND ++ ;; ++esac ++N=$((N+1)) ++done <<<" ++missing connect ++denied connect ++directory connect ++orphaned connect ++file connect ++dgram connect ++seqpacket connect ++missing send ++denied send ++directory send ++orphaned send ++file send ++stream send ++seqpacket send ++missing sendto ++denied sendto ++directory sendto ++orphaned sendto ++file sendto ++stream sendto ++seqpacket sendto ++missing seqpacket ++denied seqpacket ++directory seqpacket ++orphaned seqpacket ++file seqpacket ++stream seqpacket ++dgram seqpacket ++missing unix ++denied unix ++directory unix ++file unix ++orphaned unix ++denied gopen ++directory gopen ++orphaned gopen ++" ++ ++ ++# Test TCP with options connect-timeout and retry. ++# Up to 1.7.4.3 this terminated immediately on connection refused ++NAME=TCP_TIMEOUT_RETRY ++case "$TESTS" in ++*%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%socket%*|*%$NAME%*) ++TEST="$NAME: TCP with options connect-timeout and retry" ++# In background run a delayed echo server ++# In foreground start TCP with connect-timeout and retry. On first attempt the ++# server is not listening; when socat makes a second attempt that succeeds, the ++# bug is absent and 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" ++CMD0="sleep 1 && $TRACE $SOCAT $opts TCP-L:$PORT,reuseaddr PIPE" ++CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,connect-timeout=2,retry=1,interval=2" ++printf "test $F_n $TEST... " $N ++eval "$CMD0" >/dev/null 2>"${te}0" & ++pid0=$! ++echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" ++rc1=$? ++kill $pid0 2>/dev/null; wait ++if [ $rc1 -ne 0 ]; then ++ $PRINTF "$FAILED\n" ++ echo "$CMD0 &" >&2 ++ cat "${te}0" >&2 ++ echo "$CMD1" >&2 ++ cat "${te}1" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++elif echo "$da" |diff - "${tf}1" >$tdiff; then ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then ++ echo "$CMD0 &" >&2 ++ echo "$CMD1" >&2 ++ fi ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "$CMD0 &" >&2 ++ cat "${te}0" >&2 ++ echo "$CMD1" >&2 ++ cat "${te}1" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++fi # NUMCOND ++ ;; ++esac ++PORT=$((PORT+1)) ++N=$((N+1)) ++ ++ ++# Test if the rawer option works. Up to Socat 1.7.4.3, it failed because it ++# cleared the CREAD flag. ++NAME=RAWER ++case "$TESTS" in ++*%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*) ++TEST="$NAME: Test if the rawer option fails" ++# Invoke Socat with a terminal address with option rawer. When it has no error ++# 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" ++CMD0="$SOCAT -lp outer /dev/null EXEC:\"$SOCAT\\ -lp\\ inner\\ -\\,rawer\\ PIPE\",pty" ++printf "test $F_n $TEST... " $N ++eval "$CMD0" >/dev/null 2>"${te}0" ++rc0=$? ++if [ $rc0 -eq 0 ]; then ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then ++ echo "$CMD0" >&2 ++ fi ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "$CMD0" >&2 ++ cat "${te}0" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++fi # NUMCOND ++ ;; ++esac ++PORT=$((PORT+1)) ++N=$((N+1)) ++ ++# Up to 1.7.4.3 there was a bug with the lowport option: ++# Active addresses UDP-SEND, UDP-SENDTO always bound to port 1 instead of ++# 640..1023 ++NAME=UDP_LOWPORT ++case "$TESTS" in ++*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) ++TEST="$NAME: UDP4-SEND with lowport" ++# Run Socat with UDP4-SEND:...,lowport and full logging and check the ++# parameters of bind() call. It port is in the range 640..1023 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" ++CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowport" ++printf "test $F_n $TEST... " $N ++$CMD >/dev/null 2>"${te}" ++rc1=$? ++LOWPORT=$(grep 'D bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/') ++#echo "LOWPORT=\"$LOWPORT\"" >&2 ++#type socat >&2 ++if [[ $LOWPORT =~ [0-9][0-9]* ]] && [ "$LOWPORT" -ge 640 -a "$LOWPORT" -le 1023 ]; then ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then ++ echo "$CMD" >&2 ++ fi ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "$CMD" >&2 ++ cat "${te}" >&2 ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++fi # NUMCOND ++ ;; ++esac ++PORT=$((PORT+1)) ++N=$((N+1)) ++ ++# Test if trailing garbage in integer type options gives error ++NAME=MISSING_INTEGER ++case "$TESTS" in ++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) ++TEST="$NAME: Error on option that's missing integer value" ++# Invoke Socat with pty and option ispeed=b19200. ++# When socat terminates with error 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" ++CMD0="$TRACE $SOCAT $opts - PTY,ispeed=b19200" ++printf "test $F_n $TEST... " $N ++$CMD0 /dev/null 2>"${te}0" ++if grep -q "missing numerical value" "${te}0"; then ++ $PRINTF "$OK\n" ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "$CMD0" ++ cat "${te}0" ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++fi # NUMCOND ++ ;; ++esac ++N=$((N+1)) ++ ++# Test if trailing garbage in integer type options gives error ++NAME=INTEGER_GARBAGE ++case "$TESTS" in ++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*) ++TEST="$NAME: Error on trailing garbabe" ++# Invoke Socat with pty and option ispeed=b19200. ++# When socat terminates with error 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" ++CMD0="$TRACE $SOCAT $opts - PTY,ispeed=19200B" ++printf "test $F_n $TEST... " $N ++$CMD0 /dev/null 2>"${te}0" ++if grep -q "trailing garbage" "${te}0"; then ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi ++ if [ "$debug" ]; then cat ${te} >&2; fi ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "$CMD0" ++ cat "${te}0" ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++fi # NUMCOND ++ ;; ++esac ++N=$((N+1)) ++ ++ ++# Test if Filan can print the target of symbolic links ++NAME=FILANSYMLINK ++case "$TESTS" in ++*%$N%*|*%filan%*|*%$NAME%*) ++TEST="$NAME: capability to display symlink target" ++# Run Filan on a symbolic link ++# When its output contains "LINKTARGET=" the test succeeded ++if ! eval $NUMCOND; then :; else ++tf="$td/test$N.file" ++tl="$td/test$N.symlink" ++te="$td/test$N.stderr" ++printf "test $F_n $TEST... " $N ++touch "$tf" ++ln -s "$tf" "$tl" ++target=$($FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/') ++if [ "$target" = "$tf" ]; then ++ $PRINTF "$OK\n" ++ if [ "$VERBOSE" ]; then ++ echo "touch \"$tf\"" ++ echo "ln -s \"$tf\" \"$tl\"" ++ echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" ++ fi ++ numOK=$((numOK+1)) ++else ++ $PRINTF "$FAILED\n" ++ echo "touch \"$tf\"" >&2 ++ echo "ln -s \"$tf\" \"$tl\"" >&2 ++ echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" >&2 ++ cat "$te" ++ numFAIL=$((numFAIL+1)) ++ listFAIL="$listFAIL $N" ++fi ++kill $spid 2>/dev/null ++wait ++fi ;; # NUMCOND ++esac ++N=$((N+1)) ++ + + # end of common tests + +@@ -15347,12 +15758,12 @@ + #============================================================================== + # test template + +-# give a description of what is tested (a bugfix, a new feature...) ++# Give a description of what is tested (a bugfix, a new feature...) + NAME=SHORT_UNIQUE_TESTNAME + case "$TESTS" in + *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) + TEST="$NAME: give a one line description of test" +-# describe how the test is performed, and what's the success criteria ++# Describe how the test is performed, and what's the success criteria + if ! eval $NUMCOND; then :; else + tf="$td/test$N.stdout" + te="$td/test$N.stderr" +diff -r -N -U 3 --no-dereference socat-1.7.4.3/utils.c socat-1.7.4.4/utils.c +--- socat-1.7.4.3/utils.c 2017-01-06 21:58:40.000000000 +0100 ++++ socat-1.7.4.4/utils.c 2022-10-30 16:21:47.892474028 +0100 +@@ -97,7 +97,7 @@ + int hn; /* high nibble */ + int ln; /* low nibble */ + int n; /* written chars */ +- if (isprint(c)) { ++ if (isprint((unsigned char)c)) { + *o = c; + return 1; + } +@@ -160,7 +160,7 @@ + *scratch = '\0'; + return scratch0; + } +- ++ + + /* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still + can handle the old glibc case with -1 return on truncation. +diff -r -N -U 3 --no-dereference socat-1.7.4.3/vsnprintf_r.c socat-1.7.4.4/vsnprintf_r.c +--- socat-1.7.4.3/vsnprintf_r.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/vsnprintf_r.c 2022-10-30 16:21:47.892474028 +0100 +@@ -404,7 +404,7 @@ + do { + fsize = 10*fsize+(c-'0'); + c = *format++; +- } while (c && isdigit(c)); ++ } while (c && isdigit((unsigned char)c)); + break; + } + if (c == '\0') { break; } +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-interface.c socat-1.7.4.4/xio-interface.c +--- socat-1.7.4.3/xio-interface.c 2017-01-06 21:58:40.000000000 +0100 ++++ socat-1.7.4.4/xio-interface.c 2022-10-30 16:21:47.892474028 +0100 +@@ -69,7 +69,7 @@ + + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, +- opts, xioflags, xfd, groups, pf, socktype, 0); ++ opts, xioflags, xfd, groups, pf, socktype, 0, 0); + } + + static +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-ip.c socat-1.7.4.4/xio-ip.c +--- socat-1.7.4.3/xio-ip.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/xio-ip.c 2022-10-30 16:21:47.892474028 +0100 +@@ -71,7 +71,7 @@ + #ifdef IP_ADD_MEMBERSHIP + const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP }; + #endif +-#ifdef IP_ADD_SOURCE_MEMBERSHIP ++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) + const struct optdesc opt_ip_add_source_membership = { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQ_SOURCE, OFUNC_SOCKOPT, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP }; + #endif + #ifdef IP_RECVDSTADDR +@@ -618,7 +618,11 @@ + cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgctr = -1; + /*!!!*/ + break; ++#if XIO_ANCILLARY_TYPE_SOLARIS ++ case IP_RECVTOS: ++#else + case IP_TOS: ++#endif + cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgctr = msglen; + break; + case IP_TTL: /* Linux */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-openssl.c socat-1.7.4.4/xio-openssl.c +--- socat-1.7.4.3/xio-openssl.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/xio-openssl.c 2022-10-30 16:21:47.892474028 +0100 +@@ -959,11 +959,15 @@ + openssl_delete_cert_info(); + + /* OpenSSL preparation */ +-#if HAVE_OPENSSL_init_ssl ++#if HAVE_OPENSSL_INIT_SSL + { ++ uint64_t opts = 0; + OPENSSL_INIT_SETTINGS *settings; + settings = OPENSSL_INIT_new(); +- sycOPENSSL_init_ssl(0, settings); ++#ifdef OPENSSL_INIT_NO_ATEXIT ++ opts |= OPENSSL_INIT_NO_ATEXIT; ++#endif ++ sycOPENSSL_init_ssl(opts, settings); + } + #else + sycSSL_library_init(); +@@ -1503,7 +1507,7 @@ + progname = diag_get_string('p'); + envprefix[0] = '\0'; strncat(envprefix, progname, XIO_ENVNAMELEN-1); + l = strlen(envprefix); +- for (i = 0; i < l; ++i) envprefix[i] = toupper(envprefix[i]); ++ for (i = 0; i < l; ++i) envprefix[i] = toupper((unsigned char)envprefix[i]); + strncat(envprefix+l, "_OPENSSL_", XIO_ENVNAMELEN-l-1); + + #if HAVE_VAR_ENVIRON +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-progcall.c socat-1.7.4.4/xio-progcall.c +--- socat-1.7.4.3/xio-progcall.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/xio-progcall.c 2022-10-30 16:21:47.892474028 +0100 +@@ -8,6 +8,7 @@ + #include "xioopen.h" + + #include "xio-process.h" ++#include "xio-named.h" + #include "xio-progcall.h" + + #include "xio-socket.h" +@@ -73,6 +74,8 @@ + bool withstderr = false; + bool nofork = false; + bool withfork; ++ char *tn = NULL; ++ int trigger[2]; + + popts = moveopts(*copts, GROUP_ALL); + if (applyopts_single(fd, popts, PH_INIT) < 0) return -1; +@@ -223,19 +226,9 @@ + /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/ + } + if (ptyfd >= 0 && ttyfd < 0) { +- char *tn = NULL; + /* we used PTMX before forking */ + extern char *ptsname(int); +-#if HAVE_GRANTPT /* AIX, not Linux */ +- if (Grantpt(ptyfd)/*!*/ < 0) { +- Warn2("grantpt(%d): %s", ptyfd, strerror(errno)); +- } +-#endif /* HAVE_GRANTPT */ +-#if HAVE_UNLOCKPT +- if (Unlockpt(ptyfd)/*!*/ < 0) { +- Warn2("unlockpt(%d): %s", ptyfd, strerror(errno)); +- } +-#endif /* HAVE_UNLOCKPT */ ++ + #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */ + if ((tn = Ptsname(ptyfd)) == NULL) { + Warn2("ptsname(%d): %s", ptyfd, strerror(errno)); +@@ -247,35 +240,16 @@ + } + } + ptyname[0] = '\0'; strncat(ptyname, tn, MAXPTYNAMELEN-1); +- if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) { +- Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); +- } else { +- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/ +- } +- +-#ifdef I_PUSH +- /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */ +- /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */ +- /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ +- /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ +- if (Ioctl(ttyfd, I_FIND, "ldterm\0") == 0) { +- Ioctl(ttyfd, I_PUSH, "ptem\0\0\0"); /* 0 */ /* padding for AdressSanitizer */ +- Ioctl(ttyfd, I_PUSH, "ldterm\0"); /* 0 */ +- Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */ +- } +-#endif +- +-#if 0 /* the following block need not work */ +- +- if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) { +- Warn2("ttyname(%d): %s", ttyfd, strerror(errno)); ++#if HAVE_GRANTPT /* AIX, not Linux */ ++ if (Grantpt(ptyfd)/*!*/ < 0) { ++ Warn2("grantpt(%d): %s", ptyfd, strerror(errno)); + } +- if (tn == NULL) { +- Error("could not open pty"); +- return -1; ++#endif /* HAVE_GRANTPT */ ++#if HAVE_UNLOCKPT ++ if (Unlockpt(ptyfd)/*!*/ < 0) { ++ Warn2("unlockpt(%d): %s", ptyfd, strerror(errno)); + } +-#endif +- Info1("opened pseudo terminal %s", tn); ++#endif /* HAVE_UNLOCKPT */ + } + } + #endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */ +@@ -290,7 +264,7 @@ + } + #endif /* HAVE_OPENPTY */ + free(*copts); +- if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) { ++ if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS|GROUP_NAMED)) == NULL) { + return -1; + } + applyopts_cloexec(ptyfd, popts);/*!*/ +@@ -306,8 +280,6 @@ + + fd->fd = ptyfd; + +- /* this for child, was after fork */ +- applyopts(ttyfd, *copts, PH_FD); + } else + #endif /* HAVE_PTY */ + if (usepipes) { +@@ -411,6 +383,7 @@ + xiosetchilddied(); /* set SIGCHLD handler */ + + if (withfork) { ++ Socketpair(PF_UNIX, SOCK_STREAM, 0, trigger); + pid = xio_fork(true, E_ERROR); + if (pid < 0) { + return -1; +@@ -422,10 +395,43 @@ + /* In particular, it's not defined whether ignoring SIGCHLD is inheritable. */ + if (Signal(SIGCHLD, SIG_DFL) == SIG_ERR) { + Warn1("signal(SIGCHLD, SIG_DFL): %s", strerror(errno)); ++ Close(trigger[0]); + } + + #if HAVE_PTY + if (usepty) { ++ applyopts_named(tn, *copts, PH_PREOPEN); ++ applyopts_named(tn, *copts, PH_EARLY); ++ applyopts_named(tn, *copts, PH_FD); ++ ++ if (ttyfd < 0) { ++ if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) { ++ Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); ++ } else { ++ /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/ ++ } ++ } else { ++ if ((tn = Ttyname(ttyfd)) == NULL) { ++ Warn2("ttyname(%d): %s", ttyfd, strerror(errno)); ++ } ++ } ++ ++#ifdef I_PUSH ++ /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */ ++ /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */ ++ /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ ++ /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ ++ if (Ioctl(ttyfd, I_FIND, "ldterm\0") == 0) { ++ Ioctl(ttyfd, I_PUSH, "ptem\0\0\0"); /* 0 */ /* padding for AdressSanitizer */ ++ Ioctl(ttyfd, I_PUSH, "ldterm\0"); /* 0 */ ++ Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */ ++ } ++#endif ++ ++ /* this for child, was after fork */ ++ applyopts(ttyfd, *copts, PH_FD); ++ ++ Info1("opened pseudo terminal %s", tn); + Close(ptyfd); + if (rw != XIO_RDONLY && fdi != ttyfd) { + /* make sure that the internal diagnostic socket pair fds do not conflict +@@ -451,7 +457,6 @@ + } + + applyopts(ttyfd, *copts, PH_LATE); +- + applyopts(ttyfd, *copts, PH_LATE2); + } else + #endif /* HAVE_PTY */ +@@ -539,6 +544,10 @@ + applyopts(fdi, *copts, PH_LATE); + applyopts(fdi, *copts, PH_LATE2); + } ++ if (withfork) { ++ Info("Signalling parent ready"); ++ Close(trigger[1]); ++ } + } /* withfork */ + else { + applyopts(-1, *copts, PH_LATE); +@@ -556,6 +565,7 @@ + + /* for parent (this is our socat process) */ + Notice1("forked off child process "F_pid, pid); ++ Close(trigger[1]); + + #if 0 + if ((popts = copyopts(*copts, +@@ -565,9 +575,11 @@ + + #if HAVE_PTY + if (usepty) { ++# if 0 + if (Close(ttyfd) < 0) { + Info2("close(%d): %s", ttyfd, strerror(errno)); + } ++# endif + } else + #endif /* HAVE_PTY */ + if (usepipes) { +@@ -586,6 +598,14 @@ + return STAT_NORETRY; + } + ++ { ++ struct pollfd fds[1]; ++ fds[0].fd = trigger[0]; ++ fds[0].events = POLLIN|POLLHUP; ++ Poll(fds, 1, -1); ++ Info("Child process signalled ready"); ++ } ++ + return pid; /* indicate parent (main) process */ + } + #endif /* WITH_EXEC || WITH_SYSTEM */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-rawip.c socat-1.7.4.4/xio-rawip.c +--- socat-1.7.4.3/xio-rawip.c 2017-01-06 21:58:40.000000000 +0100 ++++ socat-1.7.4.4/xio-rawip.c 2022-10-30 16:21:47.892474028 +0100 +@@ -143,7 +143,7 @@ + } + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, +- opts, xioflags, xfd, groups, *pf, socktype, ipproto); ++ opts, xioflags, xfd, groups, *pf, socktype, ipproto, 0); + } + + +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-socket.c socat-1.7.4.4/xio-socket.c +--- socat-1.7.4.3/xio-socket.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/xio-socket.c 2022-10-30 16:21:47.896474048 +0100 +@@ -14,6 +14,9 @@ + #include "xio-socket.h" + #include "xio-named.h" + #include "xio-unix.h" ++#if WITH_VSOCK ++#include "xio-vsock.h" ++#endif + #if WITH_IP4 + #include "xio-ip4.h" + #endif /* WITH_IP4 */ +@@ -63,6 +66,14 @@ + char *nambuff, int namlen, + char *envbuff, int envlen, + char *valbuff, int vallen); ++static int xiobind( ++ struct single *xfd, ++ union sockaddr_union *us, ++ size_t uslen, ++ struct opt *opts, ++ int pf, ++ bool alt, ++ int level); + + + #if WITH_GENERICSOCKET +@@ -457,7 +468,7 @@ + + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, +- opts, xioflags, xfd, groups, pf, socktype, proto); ++ opts, xioflags, xfd, groups, pf, socktype, proto, 0); + } + + +@@ -693,6 +704,7 @@ + + #endif /* WITH_GENERICSOCKET */ + ++/* EINTR not handled specially */ + int xiogetpacketinfo(int fd) + { + #if defined(MSG_ERRQUEUE) +@@ -737,14 +749,14 @@ + + + +-/* 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, +@@ -774,111 +786,9 @@ + + applyopts_cloexec(xfd->fd, opts); + +-#if WITH_UNIX +- if (pf == PF_UNIX && us != NULL) { +- applyopts_named(us->un.sun_path, opts, PH_PREOPEN); +- } +-#endif +- applyopts(xfd->fd, opts, PH_PREBIND); +- applyopts(xfd->fd, opts, PH_BIND); +-#if WITH_TCP || WITH_UDP +- if (alt) { +- union sockaddr_union sin, *sinp; +- unsigned short *port, i, N; +- div_t dv; +- +- /* prepare sockaddr for bind probing */ +- if (us) { +- sinp = us; +- } else { +- if (them->sa_family == AF_INET) { +- socket_in_init(&sin.ip4); +-#if WITH_IP6 +- } else { +- socket_in6_init(&sin.ip6); +-#endif +- } +- sinp = &sin; +- } +- if (them->sa_family == AF_INET) { +- port = &sin.ip4.sin_port; +-#if WITH_IP6 +- } else if (them->sa_family == AF_INET6) { +- port = &sin.ip6.sin6_port; +-#endif +- } else { +- port = 0; /* just to make compiler happy */ +- } +- /* combine random+step variant to quickly find a free port when only +- few are in use, and certainly find a free port in defined time even +- if there are almost all in use */ +- /* dirt 1: having tcp/udp code in socket function */ +- /* dirt 2: using a time related system call for init of random */ +- { +- /* generate a random port, with millisecond random init */ +-#if 0 +- struct timeb tb; +- ftime(&tb); +- srandom(tb.time*1000+tb.millitm); +-#else +- struct timeval tv; +- struct timezone tz; +- tz.tz_minuteswest = 0; +- tz.tz_dsttime = 0; +- if ((result = Gettimeofday(&tv, &tz)) < 0) { +- Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno)); +- } +- srandom(tv.tv_sec*1000000+tv.tv_usec); +-#endif +- } +- dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER); +- i = N = XIO_IPPORT_LOWER + dv.rem; +- do { /* loop over lowport bind() attempts */ +- *port = htons(i); +- if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) { +- Msg4(errno==EADDRINUSE?E_INFO:level, +- "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, +- sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), +- sizeof(*sinp), strerror(errno)); +- if (errno != EADDRINUSE) { +- Close(xfd->fd); +- return STAT_RETRYLATER; +- } +- } else { +- break; /* could bind to port, good, continue past loop */ +- } +- --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1; +- if (i == N) { +- Msg(level, "no low port available"); +- /*errno = EADDRINUSE; still assigned */ +- Close(xfd->fd); +- return STAT_RETRYLATER; +- } +- } while (i != N); +- } else +-#endif /* WITH_TCP || WITH_UDP */ +- +- if (us) { +-#if WITH_UNIX +- if (pf == PF_UNIX && us != NULL) { +- applyopts_named(us->un.sun_path, opts, PH_PREOPEN); +- } +-#endif +- if (Bind(xfd->fd, &us->soa, uslen) < 0) { +- Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", +- xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)), +- uslen, strerror(errno)); +- Close(xfd->fd); +- return STAT_RETRYLATER; +- } +- } +-#if WITH_UNIX +- if (pf == PF_UNIX && us != NULL) { +- applyopts_named(us->un.sun_path, opts, PH_PASTOPEN); ++ if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) { ++ return -1; + } +-#endif +- +- applyopts(xfd->fd, opts, PH_PASTBIND); + + applyopts(xfd->fd, opts, PH_CONNECT); + +@@ -902,6 +812,8 @@ + xfd->para.socket.connect_timeout.tv_usec != 0) { + struct timeval timeout; + struct pollfd writefd; ++ int err; ++ socklen_t errlen = sizeof(err); + int result; + + Info4("connect(%d, %s, "F_Zd"): %s", +@@ -937,30 +849,40 @@ + #endif + return STAT_RETRYLATER; + } +- /* otherwise OK */ ++ /* otherwise OK or network error */ ++ result = Getsockopt(xfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen); ++ if (result != 0) { ++ Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s", ++ xfd->fd, strerror(err)); ++ return STAT_RETRYLATER; ++ } ++ Debug2("getsockopt(%d, SOL_SOCKET, SO_ERROR, { %d }) -> 0", ++ xfd->fd, err); ++ if (err != 0) { ++ Msg4(level, "connect(%d, %s, "F_Zd"): %s", ++ xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), ++ themlen, strerror(err)); ++ return STAT_RETRYLATER; ++ } + Fcntl_l(xfd->fd, F_SETFL, fcntl_flags); + } else { + Warn4("connect(%d, %s, "F_Zd"): %s", + 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); +@@ -1103,7 +1025,7 @@ + union sockaddr_union *us, socklen_t uslen, + struct opt *opts, + int xioflags, xiosingle_t *xfd, unsigned groups, +- int pf, int socktype, int ipproto) { ++ int pf, int socktype, int ipproto, bool alt) { + int level = E_ERROR; + union sockaddr_union la; socklen_t lalen = sizeof(la); + char infobuff[256]; +@@ -1125,30 +1047,9 @@ + + applyopts_cloexec(xfd->fd, opts); + +-#if WITH_UNIX +- if (pf == PF_UNIX && us != NULL) { +- applyopts_named(us->un.sun_path, opts, PH_PREOPEN); +- } +-#endif +- applyopts(xfd->fd, opts, PH_PREBIND); +- applyopts(xfd->fd, opts, PH_BIND); +- +- if (us) { +- if (Bind(xfd->fd, &us->soa, uslen) < 0) { +- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", +- xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)), +- uslen, strerror(errno)); +- Close(xfd->fd); +- return STAT_RETRYLATER; +- } +- } +-#if WITH_UNIX +- if (pf == PF_UNIX && us != NULL) { +- applyopts_named(us->un.sun_path, opts, PH_PASTOPEN); ++ if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) { ++ return -1; + } +-#endif +- +- applyopts(xfd->fd, opts, PH_PASTBIND); + + /*applyopts(xfd->fd, opts, PH_CONNECT);*/ + +@@ -1245,6 +1146,7 @@ + return; + } + if (pid == xio_waitingfor) { ++ xio_waitingfor = 0; /* so this child will not set hashappened again */ + xio_hashappened = true; + xio_childstatus = WEXITSTATUS(status); + Debug("xiosigaction_hasread() ->"); +@@ -1284,6 +1186,7 @@ + PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD, + PH_CONNECTED, PH_LATE, PH_LATE2 + OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap ++ EINTR is not handled specially. + */ + int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, +@@ -1318,25 +1221,16 @@ + + applyopts_cloexec(xfd->fd, opts); + +- applyopts(xfd->fd, opts, PH_PREBIND); +- applyopts(xfd->fd, opts, PH_BIND); +- if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) { +- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, +- sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, +- strerror(errno)); +- Close(xfd->fd); +- return STAT_RETRYLATER; +- } +- +-#if WITH_UNIX +- if (pf == AF_UNIX && us != NULL) { +- applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); ++ if (xiobind(xfd, (union sockaddr_union *)us, uslen, ++ opts, pf, 0, level) < 0) { ++ return -1; + } +-#endif + + applyopts(xfd->fd, opts, PH_PASTBIND); ++ + #if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { ++ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); + /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); +@@ -1413,6 +1307,7 @@ + socklen_t palen = sizeof(_peername); /* peer address size */ + char ctrlbuff[1024]; /* ancillary messages */ + struct msghdr msgh = {0}; ++ int rc; + + socket_init(pf, pa); + +@@ -1423,6 +1318,7 @@ + drop = true; + } + ++ Info("Recvfrom: Checking/waiting for next packet"); + /* loop until select()/poll() returns valid */ + do { + struct pollfd readfd; +@@ -1455,15 +1351,15 @@ + #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + msgh.msg_controllen = sizeof(ctrlbuff); + #endif +- if (xiogetpacketsrc(xfd->fd, ++ while ((rc = xiogetpacketsrc(xfd->fd, + &msgh, + MSG_PEEK + #ifdef MSG_TRUNC + |MSG_TRUNC + #endif +- ) < 0) { +- return STAT_RETRYLATER; +- } ++ )) < 0 && ++ errno == EINTR) ; ++ if (rc < 0) return STAT_RETRYLATER; + palen = msgh.msg_namelen; + + Notice1("receiving packet from %s"/*"src"*/, +@@ -1534,24 +1430,21 @@ + break; + } + +- /* server: continue loop with listen */ + xio_waitingfor = pid; + ++ do { + #if HAVE_PSELECT +- { ++ { + struct timespec timeout = { LONG_MAX, 0 }; + Pselect(0, NULL, NULL, NULL, &timeout, &oldset); + Sigprocmask(SIG_SETMASK, &oldset, NULL); +- } ++ } + #else /* ! HAVE_PSELECT */ +- /* now we are ready to handle signals */ +- Sigprocmask(SIG_SETMASK, &oldset, NULL); +- +- while (!xio_hashappened) { +- Sleep(1); /* any signal speeds up return */ +- } ++ /* now we are ready to handle signals */ ++ Sigprocmask(SIG_SETMASK, &oldset, NULL); ++ Sleep(1); /* any signal speeds up return */ + #endif /* ! HAVE_PSELECT */ +- xio_waitingfor = 0; /* so this child will not set hashappened again */ ++ } while (!xio_hashappened) ; + xio_hashappened = false; + + if (xio_childstatus != 0) { +@@ -1578,7 +1471,6 @@ + struct opt *opts, int pf, int socktype, int proto, + int level) { + char *rangename; +- char infobuff[256]; + + if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; + +@@ -1591,26 +1483,13 @@ + + applyopts_cloexec(xfd->fd, opts); + +- applyopts(xfd->fd, opts, PH_PREBIND); +- applyopts(xfd->fd, opts, PH_BIND); +- if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) { +- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd, +- sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen, +- strerror(errno)); +- Close(xfd->fd); +- return STAT_RETRYLATER; ++ if (xiobind(xfd, (union sockaddr_union *)us, uslen, opts, pf, 0, level) < 0) { ++ return -1; + } + + #if WITH_UNIX + if (pf == AF_UNIX && us != NULL) { + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD); +- } +-#endif +- +- applyopts_single(xfd, opts, PH_PASTBIND); +- applyopts(xfd->fd, opts, PH_PASTBIND); +-#if WITH_UNIX +- if (pf == AF_UNIX && us != NULL) { + /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/ + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY); + applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN); +@@ -1648,7 +1527,7 @@ + char *pfname; + + if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) { +- if (isdigit(pfname[0])) { ++ if (isdigit((unsigned char)pfname[0])) { + *pf = strtoul(pfname, NULL /*!*/, 0); + #if WITH_IP4 + } else if (!strcasecmp("inet", pfname) || +@@ -1676,9 +1555,12 @@ + } + + +-/* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about +- the arriving packet. in msgh the msg_name pointer must refer to an (empty) +- sockaddr storage. */ ++/* This function calls recvmsg(..., MSG_PEEK, ...) to obtain information about ++ the arriving packet, thus it does not "consume" the packet. ++ In msgh the msg_name pointer must refer to an (empty) sockaddr storage. ++ Returns STAT_OK on success, or STAT_RETRYLATER when an error occurred, ++ including EINTR. ++ */ + int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags) { + char peekbuff[1]; + #if HAVE_STRUCT_IOVEC +@@ -2190,8 +2072,21 @@ + xiosetenv(namebuff, valuebuff, 1, NULL); + namebuff[strlen(lr)] = '\0'; ++idx; + } while (result > 0); +- break; ++ break; + #endif /* WITH_IP6 */ ++#if WITH_VSOCK ++ case PF_VSOCK: ++ strcpy(namebuff, lr); ++ do { ++ result = ++ xiosetsockaddrenv_vsock(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr), ++ valuebuff, XIOSOCKADDRENVLEN, ++ &sau->vm, proto); ++ xiosetenv(namebuff, valuebuff, 1, NULL); ++ namebuff[strlen(lr)] = '\0'; ++idx; ++ } while (result > 0); ++ break; ++#endif /* WITH_VSOCK */ + #if LATER + case PF_PACKET: + result = xiosetsockaddrenv_packet(lr, (void *)sau, proto); break; +@@ -2245,3 +2140,124 @@ + } + return result; + } ++ ++int xiobind( ++ struct single *xfd, ++ union sockaddr_union *us, ++ size_t uslen, ++ struct opt *opts, ++ int pf, ++ bool alt, ++ int level) ++{ ++ char infobuff[256]; ++ int result; ++ ++#if WITH_UNIX ++ if (pf == PF_UNIX && us != NULL) { ++ applyopts_named(us->un.sun_path, opts, PH_PREOPEN); ++ } ++#endif ++ applyopts(xfd->fd, opts, PH_PREBIND); ++ applyopts(xfd->fd, opts, PH_BIND); ++#if WITH_TCP || WITH_UDP ++ if (alt) { ++ union sockaddr_union sin, *sinp; ++ unsigned short *port, i, N; ++ div_t dv; ++ ++ /* prepare sockaddr for bind probing */ ++ if (us) { ++ sinp = us; ++ } else { ++ if (pf == AF_INET) { ++ socket_in_init(&sin.ip4); ++#if WITH_IP6 ++ } else { ++ socket_in6_init(&sin.ip6); ++#endif ++ } ++ sinp = &sin; ++ } ++ if (pf == AF_INET) { ++ port = &sin.ip4.sin_port; ++#if WITH_IP6 ++ } else if (pf == AF_INET6) { ++ port = &sin.ip6.sin6_port; ++#endif ++ } else { ++ port = 0; /* just to make compiler happy */ ++ } ++ /* combine random+step variant to quickly find a free port when only ++ few are in use, and certainly find a free port in defined time even ++ if there are almost all in use */ ++ /* dirt 1: having tcp/udp code in socket function */ ++ /* dirt 2: using a time related system call for init of random */ ++ { ++ /* generate a random port, with millisecond random init */ ++#if 0 ++ struct timeb tb; ++ ftime(&tb); ++ srandom(tb.time*1000+tb.millitm); ++#else ++ struct timeval tv; ++ struct timezone tz; ++ tz.tz_minuteswest = 0; ++ tz.tz_dsttime = 0; ++ if ((result = Gettimeofday(&tv, &tz)) < 0) { ++ Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno)); ++ } ++ srandom(tv.tv_sec*1000000+tv.tv_usec); ++#endif ++ } ++ /* Note: IPPORT_RESERVED is from includes, 1024 */ ++ dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER); ++ i = N = XIO_IPPORT_LOWER + dv.rem; ++ do { /* loop over lowport bind() attempts */ ++ *port = htons(i); ++ if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) { ++ Msg4(errno==EADDRINUSE?E_INFO:level, ++ "bind(%d, {%s}, "F_Zd"): %s", xfd->fd, ++ sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)), ++ sizeof(*sinp), strerror(errno)); ++ if (errno != EADDRINUSE) { ++ Close(xfd->fd); ++ return STAT_RETRYLATER; ++ } ++ } else { ++ break; /* could bind to port, good, continue past loop */ ++ } ++ --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1; ++ if (i == N) { ++ Msg(level, "no low port available"); ++ /*errno = EADDRINUSE; still assigned */ ++ Close(xfd->fd); ++ return STAT_RETRYLATER; ++ } ++ } while (i != N); ++ } else ++#endif /* WITH_TCP || WITH_UDP */ ++ ++ if (us) { ++#if WITH_UNIX ++ if (pf == PF_UNIX && us != NULL) { ++ applyopts_named(us->un.sun_path, opts, PH_PREOPEN); ++ } ++#endif ++ if (Bind(xfd->fd, &us->soa, uslen) < 0) { ++ Msg4(level, "bind(%d, {%s}, "F_Zd"): %s", ++ xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)), ++ uslen, strerror(errno)); ++ Close(xfd->fd); ++ return STAT_RETRYLATER; ++ } ++ } ++#if WITH_UNIX ++ if (pf == PF_UNIX && us != NULL) { ++ applyopts_named(us->un.sun_path, opts, PH_PASTOPEN); ++ } ++#endif ++ ++ applyopts(xfd->fd, opts, PH_PASTBIND); ++ return 0; ++} +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-socket.h socat-1.7.4.4/xio-socket.h +--- socat-1.7.4.3/xio-socket.h 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/xio-socket.h 2022-10-30 16:21:47.896474048 +0100 +@@ -102,7 +102,7 @@ + union sockaddr_union *us, socklen_t uslen, + struct opt *opts, + int xioflags, xiosingle_t *xfd, unsigned groups, +- int pf, int socktype, int ipproto); ++ int pf, int socktype, int ipproto, bool alt); + extern + int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, + struct sockaddr *us, socklen_t uslen, +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-termios.c socat-1.7.4.4/xio-termios.c +--- socat-1.7.4.3/xio-termios.c 2019-04-04 10:59:55.000000000 +0200 ++++ socat-1.7.4.4/xio-termios.c 2022-10-30 16:21:47.896474048 +0100 +@@ -475,7 +475,7 @@ + _xiotermios_data.termarg.c_iflag = 0; + _xiotermios_data.termarg.c_oflag = 0; + _xiotermios_data.termarg.c_lflag = 0; +- _xiotermios_data.termarg.c_cflag = (CS8); ++ _xiotermios_data.termarg.c_cflag = (CREAD|CS8); + _xiotermios_data.termarg.c_cc[VMIN] = 1; + _xiotermios_data.termarg.c_cc[VTIME] = 0; + break; +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-udp.c socat-1.7.4.4/xio-udp.c +--- socat-1.7.4.3/xio-udp.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/xio-udp.c 2022-10-30 16:21:47.896474048 +0100 +@@ -410,26 +410,12 @@ + } + + retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport); +- if (xfd->para.socket.ip.lowport) { +- switch (pf) { +-#if WITH_IP4 +- case PF_INET: +- /*!!! this is buggy */ +- us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break; +-#endif +-#if WITH_IP6 +- case PF_INET6: +- /*!!! this is buggy */ +- us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break; +-#endif +- } +- needbind = true; +- } + + xfd->dtype = XIODATA_RECVFROM; + return _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, +- pf, socktype, ipproto); ++ pf, socktype, ipproto, ++ xfd->para.socket.ip.lowport); + } + + +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-unix.c socat-1.7.4.4/xio-unix.c +--- socat-1.7.4.3/xio-unix.c 2022-01-08 21:59:57.000000000 +0100 ++++ socat-1.7.4.4/xio-unix.c 2022-10-30 16:21:47.896474048 +0100 +@@ -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 @@ + 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 @@ + 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_socklen"): %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; + } +@@ -329,7 +411,7 @@ + return + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, +- pf, socktype, protocol); ++ pf, socktype, protocol, 0); + } + + +@@ -500,6 +582,7 @@ + } + + ++/* 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) { +@@ -607,7 +690,7 @@ + if ((result = + _xioopen_dgram_sendto(needbind?&us:NULL, uslen, + opts, xioflags, xfd, groups, +- pf, SOCK_DGRAM, protocol)) ++ pf, SOCK_DGRAM, protocol, 0)) + == 0) { + xfd->dtype = XIODATA_RECVFROM; + break; +@@ -615,6 +698,7 @@ + } while (0); + + if (result != 0) { ++ Error2("UNIX-CLIENT:%s: %s", name, strerror(errno)); + if (needbind) { + Unlink(us.un.sun_path); + } +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-vsock.c socat-1.7.4.4/xio-vsock.c +--- socat-1.7.4.3/xio-vsock.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/xio-vsock.c 2022-10-30 16:21:47.896474048 +0100 +@@ -3,7 +3,7 @@ + /* Author: Stefano Garzarella svm_cid); ++ return 1; ++ case 1: ++ strcpy(namebuff, "PORT"); ++ snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_port); ++ return 0; ++ } ++ return -1; ++} ++ + #endif /* WITH_VSOCK */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-vsock.h socat-1.7.4.4/xio-vsock.h +--- socat-1.7.4.3/xio-vsock.h 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/xio-vsock.h 2022-10-30 16:21:47.896474048 +0100 +@@ -8,4 +8,8 @@ + extern const struct addrdesc addr_vsock_connect; + extern const struct addrdesc addr_vsock_listen; + ++extern int xiosetsockaddrenv_vsock(int idx, char *namebuff, size_t namelen, ++ char *valuebuff, size_t valuelen, ++ struct sockaddr_vm *sa, int ipproto); ++ + #endif /* !defined(__xio_vsock_h_included) */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioopen.c socat-1.7.4.4/xioopen.c +--- socat-1.7.4.3/xioopen.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/xioopen.c 2022-10-30 16:21:47.896474048 +0100 +@@ -308,9 +308,11 @@ + { "unix-sendto", &xioaddr_unix_sendto }, + #endif + #if WITH_VSOCK ++ { "vsock", &addr_vsock_connect }, + { "vsock-connect", &addr_vsock_connect }, + #endif + #if WITH_VSOCK && WITH_LISTEN ++ { "vsock-l", &addr_vsock_listen }, + { "vsock-listen", &addr_vsock_listen }, + #endif + #else /* !0 */ +@@ -494,6 +496,7 @@ + char token[512], *tokp; + size_t len; + int i; ++ int result; + + /* init */ + i = 0; +@@ -510,9 +513,12 @@ + sfd->argc = 0; + + len = sizeof(token); tokp = token; +- if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, +- true, true, false) < 0) { ++ result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, ++ true, true, false); ++ if (result < 0) { + Error2("keyword too long, in address \"%s%s\"", token, *addr); ++ } else if (result > 0){ ++ Error1("unexpected end of address \"%s\"", *addr); + } + *tokp = '\0'; /*! len? */ + ae = (struct addrname *) +@@ -564,9 +570,12 @@ + while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) { + *addr += strlen(xioopts.paramsep); + len = sizeof(token); tokp = token; +- if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, +- true, true, false) != 0) { +- Error1("syntax error in address \"%s\"", addr0); ++ result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests, ++ true, true, false); ++ if (result < 0) { ++ Error1("address \"%s\" too long", addr0); ++ } else if (result > 0){ ++ Error1("unexpected end of address \"%s\"", addr0); + } + *tokp = '\0'; + if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) { +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioopts.c socat-1.7.4.4/xioopts.c +--- socat-1.7.4.3/xioopts.c 2021-01-03 19:23:22.000000000 +0100 ++++ socat-1.7.4.4/xioopts.c 2022-10-30 16:21:47.896474048 +0100 +@@ -164,7 +164,7 @@ + #ifdef IP_ADD_MEMBERSHIP + IF_IP ("add-membership", &opt_ip_add_membership) + #endif +-#ifdef IP_ADD_SOURCE_MEMBERSHIP ++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) + IF_IP ("add-source-membership", &opt_ip_add_source_membership) + #endif + IF_TUN ("allmulti", &opt_iff_allmulti) +@@ -678,7 +678,7 @@ + #ifdef IP_ADD_MEMBERSHIP + IF_IP ("ip-add-membership", &opt_ip_add_membership) + #endif +-#ifdef IP_ADD_SOURCE_MEMBERSHIP ++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) + IF_IP ("ip-add-source-membership", &opt_ip_add_source_membership) + #endif + #ifdef IP_FREEBIND +@@ -1563,7 +1563,7 @@ + IF_SOCKS4 ("socksport", &opt_socksport) + IF_SOCKS4 ("socksuser", &opt_socksuser) + IF_SOCKET ("socktype", &opt_so_type) +-#ifdef IP_ADD_SOURCE_MEMBERSHIP ++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) + IF_IP ("source-membership", &opt_ip_add_source_membership) + #endif + IF_IPAPP ("sourceport", &opt_sourceport) +@@ -1926,7 +1926,7 @@ + nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests, + true, true, false); + if (parsres < 0) { +- Error1("option too long: \"%s\"", *a); ++ Error1("option too long: \"%s\"", *a); + return -1; + } else if (parsres > 0) { + Error1("syntax error in \"%s\"", *a); +@@ -2006,9 +2006,9 @@ + if (assign) { + unsigned long ul; + char *rest; +- ul = strtoul(token, &rest/*!*/, 0); ++ ul = Strtoul(token, &rest, 0, a0); + if (ul > UCHAR_MAX) { +- Error3("parseopts_table(%s): byte value exceeds limit (%lu vs. %u), using max", ++ Error3("parseopts(): option \"%s\": byte value exceeds limit (%lu vs. %u), using max", + a0, ul, UCHAR_MAX); + (*opts)[i].value.u_byte = UCHAR_MAX; + } else { +@@ -2026,7 +2026,7 @@ + case TYPE_INT: + if (assign) { + char *rest; +- (*opts)[i].value.u_int = strtoul(token, &rest/*!*/, 0); ++ (*opts)[i].value.u_int = Strtoul(token, &rest, 0, a0); + } else { + (*opts)[i].value.u_int = 1; + } +@@ -2038,10 +2038,7 @@ + (*opts)[i].value.u_bool = 1; + } else { + char *rest; +- (*opts)[i].value.u_bool = strtoul(token, &rest, 0); +- if (rest && *rest) { +- Error1("error in option \"%s\": \"0\" or \"1\" required", a0); +- } ++ (*opts)[i].value.u_bool = Strtoul(token, &rest, 0, a0); + } + Info2("setting option \"%s\" to %d", ent->desc->defname, + (*opts)[i].value.u_bool); +@@ -2055,11 +2052,7 @@ + (*opts)[i].value.u_uint = 1; + } else { + char *rest; +- ulongval = strtoul(token, &rest/*!*/, 0); +- if (ulongval > UINT_MAX) { +- Error3("parseopts_table(%s): unsigned int value exceeds limit (%lu vs. %u), using max", +- a0, ulongval, UINT_MAX); +- } ++ ulongval = Strtoul(token, &rest, 0, a0); + (*opts)[i].value.u_uint = ulongval; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, +@@ -2074,11 +2067,7 @@ + (*opts)[i].value.u_ushort = 1; + } else { + char *rest; +- ulongval = strtoul(token, &rest/*!*/, 0); +- if (ulongval > USHRT_MAX) { +- Error3("parseopts_table(%s): unsigned short value exceeds limit (%lu vs. %u), using max", +- a0, ulongval, USHRT_MAX); +- } ++ ulongval = Strtoul(token, &rest, 0, a0); + (*opts)[i].value.u_ushort = ulongval; + } + Info2("setting option \"%s\" to %u", ent->desc->defname, +@@ -2096,7 +2085,7 @@ + (*opts)[i].value.u_long = 1; + } else { + char *rest; +- slongval = strtol(token, &rest, 0); ++ slongval = Strtoul(token, &rest, 0, a0); + (*opts)[i].value.u_long = slongval; + } + Info2("setting option \"%s\" to %lu", ent->desc->defname, +@@ -2111,7 +2100,7 @@ + (*opts)[i].value.u_ulong = 1; + } else { + char *rest; +- ulongval = strtoul(token, &rest, 0); ++ ulongval = Strtoul(token, &rest, 0, a0); + (*opts)[i].value.u_ulong = ulongval; + } + Info2("setting option \"%s\" to %lu", ent->desc->defname, +@@ -2131,11 +2120,14 @@ + } else { + char *rest; + # if HAVE_STRTOLL +- slonglongval = strtoll(token, &rest, 0); ++ slonglongval = Strtoll(token, &rest, 0, a0); + # else + /* in this case, input value range is limited */ +- slonglongval = strtol(token, &rest, 0); ++ slonglongval = Strtol(token, &rest, 0, a0); + # endif /* HAVE_STRTOLL */ ++ if (*rest != '\0') { ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0); ++ } + (*opts)[i].value.u_longlong = slonglongval; + } + Info2("setting option \"%s\" to %Lu", ent->desc->defname, +@@ -2150,7 +2142,7 @@ + } + if (isdigit((*token)&0xff)) { + char *rest; +- (*opts)[i].value.u_uidt = strtoul(token, &rest/*!*/, 0); ++ (*opts)[i].value.u_uidt = Strtoul(token, &rest, 0, a0); + } else { + struct passwd *pwd; + if ((pwd = getpwnam(token)) == NULL) { +@@ -2168,7 +2160,7 @@ + continue; } + if (isdigit((token[0])&0xff)) { + char *rest; +- (*opts)[i].value.u_gidt = strtoul(token, &rest/*!*/, 0); ++ (*opts)[i].value.u_gidt = Strtoul(token, &rest, 0, a0); + } else { + struct group *grp; + grp = getgrnam(token); +@@ -2188,7 +2180,7 @@ + } + { + char *rest; +- (*opts)[i].value.u_modet = strtoul(token, &rest/*!*/, 8); ++ (*opts)[i].value.u_modet = Strtoul(token, &rest, 8, a0); + } + Info2("setting option \"%s\" to %u", ent->desc->defname, + (*opts)[i].value.u_modet); +@@ -2229,7 +2221,8 @@ + continue; + } else { + double val; +- val = strtod(token, NULL); ++ char *rest; ++ val = Strtod(token, &rest, a0); + if (val == HUGE_VAL || val == -HUGE_VAL || + val == 0.0 && errno == ERANGE) { + Error2("strtod(\"%s\", NULL): %s", token, strerror(errno)); +@@ -2248,7 +2241,8 @@ + continue; + } else { + double val; +- val = strtod(token, NULL); ++ char *rest; ++ val = Strtod(token, &rest, a0); + if (val == HUGE_VAL || val == -HUGE_VAL || + val == 0.0 && errno == ERANGE) { + Error2("strtod(\"%s\", NULL): %s", token, strerror(errno)); +@@ -2270,7 +2264,7 @@ + (*opts)[i].value.u_linger.l_onoff = 1; + { + char *rest; +- (*opts)[i].value.u_linger.l_linger = strtoul(token, &rest/*!*/, 0); ++ (*opts)[i].value.u_linger.l_linger = Strtoul(token, &rest, 0, a0); + } + Info3("setting option \"%s\" to {%d,%d}", ent->desc->defname, + (*opts)[i].value.u_linger.l_onoff, +@@ -2287,12 +2281,15 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); +- if (*rest != ':') { +- Error1("option \"%s\": 2 arguments required", ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 2 arguments required", + ent->desc->defname); + } + ++rest; +- (*opts)[i].value2.u_int = strtoul(rest, &rest, 0); ++ (*opts)[i].value2.u_int = Strtoul(rest, &rest, 0, a0); + } + Info3("setting option \"%s\" to %d:%d", ent->desc->defname, + (*opts)[i].value.u_int, (*opts)[i].value2.u_int); +@@ -2306,8 +2303,14 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } + if (*rest != ':') { +- Error1("option \"%s\": 2 arguments required", ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 2 arguments required", + ent->desc->defname); + } + ++rest; +@@ -2334,8 +2337,14 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } + if (*rest != ':') { +- Error1("option \"%s\": 2 arguments required", ++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 2 arguments required", + ent->desc->defname); + } + ++rest; +@@ -2355,18 +2364,28 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname); ++ } + if (*rest != ':') { +- Error1("option \"%s\": 3 arguments required", +- ent->desc->defname); ++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0); + } + ++rest; + (*opts)[i].value2.u_int = strtoul(rest, &rest, 0); ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname); ++ } + if (*rest != ':') { +- Error1("option \"%s\": 3 arguments required", +- ent->desc->defname); ++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0); + } + ++rest; +- (*opts)[i].value3.u_int = strtoul(rest, &rest, 0); ++ (*opts)[i].value3.u_int = Strtoul(rest, &rest, 0, a0); + } + Info4("setting option \"%s\" to %d:%d:%d", ent->desc->defname, + (*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_int); +@@ -2381,16 +2400,28 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); +- if (*rest != ':') { ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { + Error1("option \"%s\": 3 arguments required", + ent->desc->defname); + } ++ if (*rest != ':') { ++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0); ++ } + ++rest; + (*opts)[i].value2.u_int = strtoul(rest, &rest, 0); +- if (*rest != ':') { ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { + Error1("option \"%s\": 3 arguments required", + ent->desc->defname); + } ++ if (*rest != ':') { ++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0); ++ } + ++rest; + optlen = 0; + if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) { +@@ -2415,16 +2446,28 @@ + { + char *rest; + (*opts)[i].value.u_int = strtoul(token, &rest, 0); +- if (*rest != ':') { +- Error1("option \"%s\": 3 arguments required", ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 3 arguments required", + ent->desc->defname); + } ++ if (*rest != ':') { ++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0); ++ } + ++rest; + (*opts)[i].value2.u_int = strtoul(rest, &rest, 0); +- if (*rest != ':') { +- Error1("option \"%s\": 3 arguments required", ++ if (token == rest) { ++ Error1("parseopts(): missing numerical value of option \"%s\"", a0); ++ } ++ if (*rest == '\0') { ++ Error1("parseopts(): option \"%s\": 3 arguments required", + ent->desc->defname); + } ++ if (*rest != ':') { ++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0); ++ } + ++rest; + if (((*opts)[i].value3.u_string = strdup(rest)) == NULL) { + Error("out of memory"); return -1; +@@ -2507,7 +2550,7 @@ + break; + #endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ + +-#if HAVE_STRUCT_IP_MREQ_SOURCE ++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) + case TYPE_IP_MREQ_SOURCE: + xiotype_ip_add_source_membership(token, ent, opt); + break; +@@ -2873,9 +2916,14 @@ + + while (opt->desc != ODESC_END) { + if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) { ++ char *rest; + switch (opt->desc->type) { + case TYPE_INT: *result = opt->value.u_int; break; +- case TYPE_STRING: *result = strtol(opt->value.u_string, NULL, 0); ++ case TYPE_STRING: *result = strtol(opt->value.u_string, &rest, 0); ++ if (*rest != '\0') { ++ Error1("retropts: trailing garbage in numerical arg of option \"%s\"", ++ opt->desc->defname); ++ } + break; + default: Error2("cannot convert type %d of option %s to int", + opt->desc->type, opt->desc->defname); +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioread.c socat-1.7.4.4/xioread.c +--- socat-1.7.4.3/xioread.c 2021-10-31 19:06:09.000000000 +0100 ++++ socat-1.7.4.4/xioread.c 2022-10-30 16:21:47.896474048 +0100 +@@ -119,6 +119,7 @@ + socklen_t fromlen = sizeof(from); + char infobuff[256]; + char ctrlbuff[1024]; /* ancillary messages */ ++ int rc; + + msgh.msg_name = &from; + msgh.msg_namelen = fromlen; +@@ -128,14 +129,16 @@ + #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + msgh.msg_controllen = sizeof(ctrlbuff); + #endif +- if (xiogetpacketsrc(pipe->fd, &msgh, ++ ++ while ((rc = xiogetpacketsrc(pipe->fd, &msgh, + MSG_PEEK + #ifdef MSG_TRUNC + |MSG_TRUNC + #endif +- ) < 0) { +- return -1; +- } ++ )) < 0 && ++ errno == EINTR) ; ++ if (rc < 0) return -1; ++ + do { + bytes = + Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); +@@ -319,6 +322,7 @@ + char infobuff[256]; + struct msghdr msgh = {0}; + char ctrlbuff[1024]; /* ancillary messages */ ++ int rc; + + socket_init(pipe->para.socket.la.soa.sa_family, &from); + /* get source address */ +@@ -330,14 +334,15 @@ + #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN + msgh.msg_controllen = sizeof(ctrlbuff); + #endif +- if (xiogetpacketsrc(pipe->fd, &msgh, ++ while ((rc = xiogetpacketsrc(pipe->fd, &msgh, + MSG_PEEK + #ifdef MSG_TRUNC + |MSG_TRUNC + #endif +- ) < 0) { +- return -1; +- } ++ )) < 0 && ++ errno == EINTR) ; ++ if (rc < 0) return -1; ++ + xiodopacketinfo(&msgh, true, false); + if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) { + Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */ +diff -r -N -U 3 --no-dereference socat-1.7.4.3/xiosysincludes.h socat-1.7.4.4/xiosysincludes.h +--- socat-1.7.4.3/xiosysincludes.h 2017-01-06 21:58:40.000000000 +0100 ++++ socat-1.7.4.4/xiosysincludes.h 2022-10-30 16:21:47.896474048 +0100 +@@ -9,5 +9,7 @@ + #include "xioconfig.h" /* what features are enabled */ + + #include "sysincludes.h" ++//#undef IP_ADD_SOURCE_MEMBERSHIP ++#undef HAVE_STRUCT_IP_MREQ_SOURCE + + #endif /* !defined(__xiosysincludes_h_included) */ diff --git a/socat-1.7.4.4.tar.gz b/socat-1.7.4.4.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..969b5a355f8483fbab040ec19088d465a69feaea Binary files /dev/null and b/socat-1.7.4.4.tar.gz differ diff --git a/socat.spec b/socat.spec index 62bfee1d920f33ddf8281567dcacd9031a89d4ff..55d0989171f6d0c0b68b5d750761920f6d1f986d 100644 --- a/socat.spec +++ b/socat.spec @@ -2,11 +2,12 @@ Summary: Multipurpose relay Name: socat -Version: 1.7.4.3 +Version: 1.7.4.4 Release: 1 License: GPLv2 Url: http://www.dest-unreach.org/socat/ Source: http://www.dest-unreach.org/socat/download/%{name}-%{version}.tar.gz +Patch0000: socat-1.7.4.4.patch BuildRequires: gcc openssl-devel readline-devel ncurses-devel BuildRequires: autoconf kernel-headers > 2.6.18 @@ -38,7 +39,6 @@ mv CHANGES.utf8 CHANGES --enable-openssl --enable-sycls --enable-filan \ --enable-system --enable-pty --enable-readline - %make_build %install @@ -60,8 +60,11 @@ cp -a *.sh %{buildroot}/%{_docdir}/socat/ %doc %{_mandir}/man1/socat.1* %changelog +* Sat Nov 5 2022 hkgy - 1.7.4.4-1 +- Upgrade to v1.7.4.4 + * Thu Jul 28 2022 fushanqing - 1.7.4.3-1 - update to 1.7.4.3 * Tue Nov 19 2019 mengxian - 1.7.3.2-8 -- Package init \ No newline at end of file +- Package init