1
0
Fork 0
mirror of https://repo.or.cz/socat.git synced 2025-05-29 15:30:48 +00:00

Compare commits

...

51 commits

Author SHA1 Message Date
Gerhard
78cc5ae1a5 Version 1.8.0.3 2025-02-21 12:38:14 +01:00
Gerhard
245f5e657f Catch problems caused by ISPs DNS 2025-02-21 12:37:53 +01:00
Gerhard
34b09a44ee Again fixes a few disable problems 2025-02-20 10:29:49 +01:00
Gerhard
6a53c955d3 Help shows option groups beyond 32 bits 2025-02-20 10:26:37 +01:00
Gerhard
b57d8668ec Added POSIXMQ-WRITE; warn on maxmsg,msgsize failure; doc 2025-02-18 12:34:15 +01:00
Gerhard
436d764029 Small fixes with tests, logs, comments, and doc 2025-02-17 20:39:06 +01:00
Gerhard
9269897bab Fix for compiling on Solaris-11 2025-02-17 20:33:18 +01:00
Gerhard
f0b30f3859 Fixes for FreeBSD-15 (DCCP) 2025-02-17 20:32:06 +01:00
Gerhard
48f3341d82 Use correct IPPROTO with CONNECT 2025-02-17 20:30:26 +01:00
Gerhard
186a323c2d Improved README; explained benefit of UDP-DATAGRAM 2025-02-13 14:40:24 +01:00
Gerhard
52e2e5a277 Corrected lots of misspellings etc. 2025-02-13 14:33:06 +01:00
Gerhard
d9d06eb587 Fixed preprocessor directives in macro invocation 2025-02-13 14:29:15 +01:00
Gerhard
c8aec28b82 Added options setsockopt-socket and setsockopt-connected 2025-02-13 11:25:09 +01:00
Gerhard
e6aa3d1787 Print info on implicit SO_REUSEADDR 2025-02-11 12:31:59 +01:00
Gerhard
3339885f5b Procan prints some C-defines in oct and hex 2025-02-10 22:24:56 +01:00
Gerhard Rieger
699da5f522 Procan tells if char is signed or unsigned 2025-02-10 22:01:24 +01:00
Gerhard Rieger
200ccb24cd Procan -V; more C-defines (__GLIBC__, O_*, AI_*, EAI_*) 2025-02-10 22:00:42 +01:00
Gerhard Rieger
568c26861b Procan: print saved set-user-ID 2025-02-10 21:59:43 +01:00
Gerhard
08d01c19ff Fixed UDP6-RECVFROM with range 2025-02-10 21:06:22 +01:00
Gerhard
264b21c1a9 getpwuid() errno 2025-02-10 19:42:22 +01:00
Gerhard
7b26406d96 Reworked IPAPP clients 2025-02-10 12:48:04 +01:00
Gerhard
63f67101f4 Corrections for Ubuntu-24 with newer compilers 2025-02-10 12:46:57 +01:00
Gerhard
676888e8cc UNIX-L with bind option logged INTERNAL error 2025-02-08 20:55:03 +01:00
Gerhard
ed11b3d2c5 Protect SSL_connect(); Nanosleep() with decimal output 2025-02-08 20:53:35 +01:00
Gerhard Rieger
416fe38e33 Satisfy some deprecation warnings of newer Linux distributions 2025-01-30 10:12:52 +01:00
Gerhard Rieger
3f4b171523 Fixed flock() on AIX, Solaris 2025-01-30 10:11:42 +01:00
Gerhard Rieger
2439276651 Fixes for old Scientific/RHEL 2025-01-30 10:10:23 +01:00
Gerhard Rieger
19d488a14f Fixes for old Debian 2025-01-30 10:08:19 +01:00
Gerhard Rieger
0f1c5dd85a Fixed UDP-LISTEN with bind to IPv4 address on option -0 2025-01-29 22:58:37 +01:00
Gerhard Rieger
c4844692f3 New alias POSIXMQ for POSIXMQ-BIDIRECTIONAL 2025-01-29 22:56:13 +01:00
Gerhard Rieger
1ea37d48c2 Fixed o-creat, o-excl, and o-cloexec with POSIXMQ-* 2025-01-29 22:56:06 +01:00
Gerhard Rieger
25d2f746d9 Added options posixmq-maxmsg and posixmq-msgsize 2025-01-29 22:56:00 +01:00
Gerhard Rieger
663a6bb012 Added option posixmq-flush 2025-01-29 22:55:51 +01:00
Gerhard Rieger
9bf5fc625c POSIXMQ-RECV takes option o-nonblock 2025-01-29 22:55:45 +01:00
Gerhard Rieger
68f0143f7b READLINE now prints newline on empty input line 2025-01-29 22:52:47 +01:00
Gerhard Rieger
920ed1f0a3 Fixed possible crash or fail of option ip-add-membership with two parameters 2025-01-29 22:44:52 +01:00
Gerhard Rieger
bcca5a3b9a Option ip-add-source-membership did not work 2025-01-29 22:44:47 +01:00
Gerhard Rieger
9beffd3193 Fixed: xiopoll(...) Bad file descriptor 2025-01-29 22:41:25 +01:00
Gerhard Rieger
1154e69d3e writefull() respects total inactivity timeout 2025-01-29 22:34:34 +01:00
Gerhard Rieger
1878ae93fd writefull() uses select()/poll() instead of sleep based polling 2025-01-29 22:34:26 +01:00
Gerhard Rieger
2dd1452f25 Correct undesired logging of complete write() 2025-01-29 22:34:20 +01:00
Gerhard Rieger
29f9e4db92 Test script socks5server-echo.sh for new tests SOCKS5CONNECT_TCP4 and SOCKS5LISTEN_TCP4 2025-01-29 22:21:19 +01:00
Gerhard Rieger
e7df880af5 Fixed ignoring of explicit socksport in socks5 addresses (regression) 2025-01-29 21:59:56 +01:00
Gerhard Rieger
5e56f25285 Fix for old FreeBSD 2025-01-29 21:58:08 +01:00
Gerhard Rieger
fa67d7d380 Corrected regression of ignoreeof 2025-01-29 21:55:18 +01:00
Gerhard Rieger
9968ca4c5b Fixed filan -s displaying "(stream)" instead of "tcp" 2025-01-29 21:51:58 +01:00
Gerhard Rieger
7a90caade5 Fixed build issues on disabled features 2025-01-29 21:49:16 +01:00
Gerhard Rieger
af7d44d751 Fixed a few testing issues 2025-01-28 01:25:22 +01:00
Gerhard Rieger
f38b76f5c8 Fixed display of option phases in help output 2025-01-24 16:13:33 +01:00
Gerhard Rieger
2e21396282 test.sh produces results.txt with numbers, names, results 2025-01-24 16:01:19 +01:00
Gerhard Rieger
69c9eb550c Further improved readline.sh STDERR handling 2025-01-24 15:54:27 +01:00
87 changed files with 5265 additions and 5989 deletions

243
CHANGES
View file

@ -1,4 +1,191 @@

####################### V 1.8.0.3:
Security:
readline.sh has new option -lf <logfile> for stderr. If this option is
not given it logs to a file in . (cwd) only when . is not writable by
other users.
Corrections:
Fixed display of option phases in help output.
filan -s displayed "(stream)" instead of "tcp" with addresses
(regression).
Fixed a bug that made ignoreeof fail in 1.8.0.0 and 1.8.0.1;
corrected test IGNOREEOF.
Thanks to Rusty Bird for the precise problem report.
Fixed the regression introduced with version 1.8.0.1 that in socks5
addresses the explicit socksport (2nd address parameter) was ignored.
Thanks to Jakub Fišer for reporting this bug.
Do not log simple successful write with NOTICE level.
On partial write to not poll with sleep() but use select()/poll().
Partial write situations respect total inactivity timeout when
nonblocking.
Fixed a bug that could lead to error "xiopoll(...): Bad file descriptor"
or to undefined behaviour before terminating Socat with addresses EXEC,
SYSTEM, or SHELL.
Option ip-add-source-membership did not work.
Thanks to Duncan Sands and others for reporting this issue and sending
the fix.
Option ip-add-membership with only two parameters crashed or failed
when malloc() does not initialize memory with zeros.
Thanks to Nicolas Cavallari for reporting and fixing this bug.
The readline() library function does not output the newline of empty
input lines. Changed Socat to explicitly print the newline in this
case.
Fixed implementation of options o-creat, o-excl, and o-cloexec with
POSIXMQ-* addresses.
POSIXMQ addresses are no longer experimental.
With version 1.8.0.0, and with 1.8.0.1 and option -0, the following
command failed:
socat UDP-LISTEN:1234,fork,reuseaddr,bind=127.0.0.1 -
Message: "E xioopen_ipdgram_listen(): unknown address family 0":
Thanks to Brian Woo for reporting this issue.
Test: UDP_LISTEN_BIND4
Protected SSL_connect() from SIGCHLD,SIGUSR1.
Nanosleep() trace output now in decimal form.
UNIX-LISTEN with bind option terminated with INTERNAL error, this is
now handled properly.
Test: UNIX_L_BIND
Removed unused bytes variable from gettimestamp(), corrected #elsif,
and socks4 record length.
Thanks to clang-18 and gcc-13.
Address TCP-CONNECT, when target address resolves to both IPv4 and
IPv6, now tries to take into account bind address for protocol
selection.
Reworked and harmonized ipapp client addresses.
Tests: TCP_CONNECT_RETRY SCTP_CONNECT_RETRY DCCP_CONNECT_RETRY
OPENSSL_CONNECT_RETRY SOCKS4_RETRY SOCKS5_CONNECT_RETRY
PROXY_CONNECT_RETRY
Socks and proxy clients now also support option max-children.
Tests: TCP_CONNECT_MAXCHILDREN SCTP_CONNECT_MAXCHILDREN
DCCP_CONNECT_MAXCHILDREN OPENSSL_CONNECT_MAXCHILDREN
SOCKS4_MAXCHILDREN SOCKS5_CONNECT_MAXCHILDREN PROXY_CONNECT_MAXCHILDREN
On failure of getpwuid() (used in options su and su-d) now consider
errno.
When IP4 was completed deconfigured, UDP6-RECVFROM with range option
failed.
Fixed preprocessor directives in macro invocation.
Thanks to Mario de Weerd for reporting this issue.
CONNECT addresses could use a wrong IPPROTO when getaddrinfo() does not
support the selected one (at least on Debian-4 with SCTP).
socat -h (help) did not show option groups POSIXMQ, SCTP, DCCP, and
UDPLITE of addresses.
Features:
POSIXMQ-RECV now takes option o-nonblock; this, in combination with -T,
makes it possible to terminate Socat in case the queue is empty.
New option posixmq-flush (mq-flush) for POSIXMQ addresses empties the
queue before starting to transfer data.
Test: LINUX_POSIXMQ_FLUSH
New options posixmq-maxmsg, posixmq-msgsize.
Tests: POSIXMQ_MAXMSG POSIXMQ_MSGSIZE
POSIXMQ is now an alias for POSIXMQ-BIDIRECTIONAL. It can also be used
in unidirectional context.
Procan uses getresuid() and getresgid() when available, to determine
the saved set-user-ID.
Procan prints more C-defines, esp.O_*, AI_*, EAI_*; __GLIBC__;
prints some C-defines in oct and hex;
added option -V
Procan tells if char is signed or unsigned
Socat now prints an info message when implicitly setting SO_REUSEADDR.
Thanks to Michael Renner for this suggestion.
Added generic options setsockopt-socket and setsockopt-connected that
are applied after socket() or when connected.
POSIXMQ addresses now print a warning when options posixmq-maxmsg or
posixmq-msgsize were not applied.
New address POSIXMQ-WRITE does the same as POSIXMQ-SEND, as counterpart
of POSIXMQ-READ.
Building:
Disabling certain features during configure could break build process.
Again fixes a few disable problems.
Porting:
Fix for old FreeBSD.
Fixes for old Debian
Fixes for old Scientific/RHEL
Socat failed to build on platforms without flock() function (AIX,
Solaris) due to a missing guard.
Newer Linux distributions do not provide libwrap: do not leave unused
variable.
Newer Linux distributions deprecate usleep, replace it.
OpenSSL-3 loudly deprecates some functions or macros, replace a first
bunch of them.
Fixes for FreeBSD-15 (DCCP)
Fix for compiling on Solaris-11
Testing:
test.sh produces file results.txt with columns of test numbers, names,
and results.
Fixed a few testing issues.
Added test script sock5server-echo.sh for SOCKS5-CONNECT and
SOCKS5-LISTEN, and appropriate tests.
SOCKS5 addresses are no longer experimental.
Tests: SOCKS5CONNECT_TCP4 SOCKS5LISTEN_TCP4
Added a developer test that overwrites malloc'ed memory with non-zeros.
Newer Linux distributions now deprecate usleep; replaced it in test.sh
UDPLITE4STREAM was trice, changed one of them to UDPLITE6STREAM.
Catch problems caused by ISPs that filter *.dest-unreach.net records.
Documentation:
Removed obsolete CHANGES.ISO-8859-1 file.
Corrected lots of misspelling and typos.
Thanks to Mario de Weerd for reporting these issues.
Improved README file.
Better explained benefit of UDP-DATAGRAM address type.
####################### V 1.8.0.2:
Security:
@ -70,6 +257,9 @@ Corrections:
Print warning about not checking CRLs in OpenSSL only in the first
child process.
Fixed preprocessor directives in macro invocation.
Thanks to Mario de Weerd for reporting this issue.
Features:
Total inactivity timeout option -T 0 now means 0.0 seconds; up to
version 1.8.0.0 it meant no total inactivity timeout.
@ -237,11 +427,11 @@ Features:
no IP version is preferred by build, environment, option, or address
type, Socat chooses IPv6 because this might activate both versions (but
check option ipv6-v6only).
Added option ai-passive to control this flag explicitely.
Added option ai-passive to control this flag explicitly.
New option ai-v4mapped (v4mapped) sets or unsets the AI_V4MAPPED flag
of the resolver. For Socat addresses requiring IPv6 addresses, this
resolves IPv4 addresses to the approriate IPv6 address [::ffff:*:*].
resolves IPv4 addresses to the appropriate IPv6 address [::ffff:*:*].
DNS resolver Options (res-*) are now set for the complete open phase of
the address, not per getaddrinfo() invocation.
@ -434,14 +624,14 @@ Porting:
Some corrections for better 32bit systems support.
Testing:
Removed obselete parts from test.sh
Removed obsolete parts from test.sh
test.sh: Introduced function checkcond
Renamed test.sh option -foreign to -internet
Documentation:
Removed obselete file doc/xio.help
Removed obsolete file doc/xio.help
Added doc for option ipv6-join-group (ipv6-add-membership)
Thanks to Martin Buck for sending the patch.
@ -454,7 +644,7 @@ Documentation:
Corrections:
On connect() failure and in some other situations Socat tries to get
detailled information about the error with recvmsg(). Error return of
detailed information about the error with recvmsg(). Error return of
this function is now logged as Info instead of Warn.
Tests of the correction of the "IP_ADD_SOURCE_MEMBERSHIP but not struct
@ -498,7 +688,7 @@ Corrections:
Thanks to Gordon W.Ross for reporting and fixing this issue.
Test: RESTORE_TTY
The OpenSSL client SNI parameter, when not explicitely specified, is
The OpenSSL client SNI parameter, when not explicitly specified, is
derived from option commonname or rom target server name. This is not
useful with IP addresses, which Socat now checks and avoids.
@ -529,7 +719,7 @@ Coding:
fcntl() trace prints flags now in hexadecimal.
Stream dump options -r and -R now open their pathes with CLOEXEC to
Stream dump options -r and -R now open their paths with CLOEXEC to
prevent leaking into sub processes.
Test: EXEC_SNIFF
@ -828,7 +1018,7 @@ Corrections:
Print a message when readbytes option causes EOF
The ip-recverr option had no effect. Corrected and improved its
handling of ancilliary messages, so it is able to analyze ICMP error
handling of ancillary messages, so it is able to analyze ICMP error
packets (Linux only?)
Setgui(), Setuid() calls in xio-progcall.c were useless.
@ -862,11 +1052,11 @@ Corrections:
Under certain conditions OpenSSL stream connections, in particular bulk
data transfer in unidirectional mode, failed during transfer or near
its with Connection reset by peer on receiver side.
its end with Connection reset by peer on receiver side.
This happened with Socat versions 1.7.3.3 to 1.7.4.0. Reasons were
lazy SSL shutdown handling on the sender side in combination with
SSL_MODE_AUTO_RETRY turned off.
Fix: After SSH_shutdown but before socket shutdown call SSL_read()
Fix: After SSL_shutdown() but before socket shutdown call SSL_read()
Test: OPENSSL_STREAM_TO_SERVER
Fixes Red Hat issue 1870279.
@ -966,7 +1156,7 @@ Porting:
ai_protocol=0 and try again
Test: SCTP_SERVICENAME
Per file filesystem options were still named ext2-* and depended on
Per file filesystem options were still named ext2-* and dependent on
<linux/ext2_fs.h>. Now they are called fs-* and depend on <linux/fs.h>.
These fs-* options are also available on old systems with ext2_fs.h
@ -979,14 +1169,14 @@ Porting:
SSL_library_init.
With OPENSSL_API_COMPAT=0x10000000L the files openssl/dh.h, openssl/bn.h
must explicitely be included.
must explicitly be included.
Thanks to Rosen Penev for reporting and sending a patch.
Testing:
test.sh now produces a list of tests that could not be performed for
any reason. This helps to analyse these cases.
OpenSSL s_server appearently started to neglect TCPs half close feature.
OpenSSL s_server apparently started to neglect TCPs half close feature.
Test OPENSSL_TCP4 has been changed to tolerate this.
OpenSSL changed its behaviour when connection is rejected. Tests
@ -1180,7 +1370,7 @@ Corrections:
Porting:
OpenSSL functions TLS1_client_method() and similar are
deprecated. Socat now uses recommended TLS_client_method(). The old
functions and dependend option openssl-method can still be
functions and dependent option openssl-method can still be
used when configuring socat with --enable-openssl-method
Shell scripts in socat distribution are now headed with:
@ -1222,7 +1412,7 @@ Testing:
More corrections to test.sh:
Language settings could still influence test results
netstat was still required
Suppress usleep deprecated messag
Suppress usleep deprecated message
Force use of IPv4 with some certificates
Set timeout for UDPxMAXCHILDREN tests
@ -1375,7 +1565,7 @@ testing:
docu:
Corrected source of socat man page to correctly show man references
like socket(2); removed obseolete entries from See Also
like socket(2); removed obsolete entries from See Also
Docu and some comments mentioned addresses SSL-LISTEN and SSL-CONNECT
that do not exist (OPENSSL-LISTEN, SSL-L; and OPENNSSL-CONNECT, SSL
@ -1410,6 +1600,7 @@ security:
Socat security advisory 7
MSVR-1499
CVE-2016-2217
In the OpenSSL address implementation the hard coded 1024 bit DH p
parameter was not prime. The effective cryptographic strength of a key
exchange using these parameters was weaker than the one one could get by
@ -1417,7 +1608,7 @@ security:
parameters were chosen, the existence of a trapdoor that makes possible
for an eavesdropper to recover the shared secret from a key exchange
that uses them cannot be ruled out.
Futhermore, 1024bit is not considered sufficiently secure.
Furthermore, 1024bit is not considered sufficiently secure.
Fix: generated a new 2048bit prime.
Thanks to Santiago Zanella-Beguelin and Microsoft Vulnerability
Research (MSVR) for finding and reporting this issue.
@ -1431,7 +1622,7 @@ security:
safe functions in signal handlers that could freeze socat, allowing
denial of service attacks.
Many changes in signal handling and the diagnostic messages system were
applied to make the code async signal safe but still provide detailled
applied to make the code async signal safe but still provide detailed
logging from signal handlers:
Coded function vsnprintf_r() as async signal safe incomplete substitute
of libc vsnprintf()
@ -1519,7 +1710,7 @@ corrections:
Issue reported by Hendrik.
Added option termios-cfmakeraw that calls cfmakeraw() and is preferred
over option raw which is now obsolote. On SysV systems this call is
over option raw which is now obsolete. On SysV systems this call is
simulated by appropriate setting.
Thanks to Youfu Zhang for reporting issue with option raw.
@ -1532,7 +1723,7 @@ porting:
Thanks to Ross Burton and Danomi Manchego for reporting this issue.
Debian Bug#764251: Set the build timestamp to a deterministic time:
support external BUILD_DATE env var to allow to build reproducable
support external BUILD_DATE env var to allow to build reproducible
binaries
Joachim Fenkes provided an new adapted spec file.
@ -1653,7 +1844,7 @@ porting:
autoconf now prefers configure.ac over configure.in
Thanks to Michael Vastola for sending a patch.
type of struct cmsghdr.cmsg is system dependend, determine it with
type of struct cmsghdr.cmsg is system dependent, determine it with
configure; some more print format corrections
docu:
@ -1707,7 +1898,7 @@ corrections:
socket using address GOPEN. Thanks to Martin Forssen for bug report and
patch.
UDP-LISTEN would alway set SO_REUSEADDR even without fork option and
UDP-LISTEN would always set SO_REUSEADDR even without fork option and
when user set it to 0. Thanks to Michal Svoboda for reporting this bug.
UNIX-CONNECT did not support half-close. Thanks to Greg Hughes who
@ -1940,7 +2131,7 @@ new features:
added generic socket addresses: SOCKET-CONNECT, SOCKET-LISTEN,
SOCKET-SENDTO, SOCKET-RECVFROM, SOCKET-RECV, SOCKET-DATAGRAM allow
protocol independent socket handling; all parameters are explicitely
protocol independent socket handling; all parameters are explicitly
specified as numbers or hex data
added address options ioctl-void, ioctl-int, ioctl-intp, ioctl-string,
@ -2013,7 +2204,7 @@ corrections:
this bug). test: EXECSPACES
in ignoreeof polling mode socat also blocked data transfer in the other
direction during the 1s wait intervalls (thanks to Jorgen Cederlof for
direction during the 1s wait intervals (thanks to Jorgen Cederlof for
reporting this bug)
corrected alphabetical order of options (proxy-auth)
@ -2439,7 +2630,7 @@ corrections:
check for /proc at runtime, even if configure found it
src.rpm accidently supported SuSE instead of RedHat
src.rpm accidentally supported SuSE instead of RedHat
####################### V 1.3.2.0:
@ -2715,7 +2906,7 @@ solved problems and bugs:
SOLVED: now uses common TCP service resolver
PROBLEM: with PIPE, wrong FDs were shown for data transfer loop
SOLVED: retrieval of FDs now pays respect to PIPE pecularities
SOLVED: retrieval of FDs now pays respect to PIPE peculiarities
PROBLEM: using address EXEC against an address with IGNOREEOF, socat
never terminated

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,7 @@ $ socat \
TCP-LISTEN:8000,crlf \
SYSTEM:"echo HTTP/1.0 200; echo Content-Type\: text/plain; echo; cat"
// A less primitive HTTP echo server that sends back not only the reqest but
// A less primitive HTTP echo server that sends back not only the request but
// also server and client address and port. Might have portability issues with
// echo
$ socat -T 1 -d -d \
@ -131,7 +131,7 @@ $ socat \
///////////////////////////////////////////////////////////////////////////////
// Intrusion testing
// Found an XWindow Server behind IP filters with FTP data hole? (you are
// Found an X-Window Server behind IP filters with FTP data hole? (you are
// lucky!)
// prepare your host:
# rm -f /tmp/.X11-unix/X1
@ -241,7 +241,7 @@ $ socat - /tmp/postoffice
// Uses of filan
// See what your operating system opens for you
$ filan
// or if that was too detailled
// or if that was too detailed
$ filan -s
// See what file descriptors are passed via exec function
$ socat - EXEC:"filan -s",nofork
@ -342,7 +342,7 @@ socat \
// three main versions for entering password:
// 1) from your TTY; have 10 seconds to enter password:
(sleep 10; echo "ls"; sleep 1) |socat - EXEC:'ssh server',pty
// 2) from XWindows (DISPLAY !); again 10 seconds
// 2) from X-Windows (DISPLAY !); again 10 seconds
(sleep 10; echo "ls"; sleep 1) |socat - EXEC:'ssh server',pty,setsid
// 3) from script
(sleep 5; echo PASSWORD; echo ls; sleep 1) |./socat - EXEC:'ssh server',pty,setsid,ctty

2
FAQ
View file

@ -60,7 +60,7 @@ Q: When I specify a dual address (two partial addresses linked with "!!") on
the command line, I get some message "event not found", and my shell history
has the line truncated. Not even protecting the '!'s with '\' helps.
A: '!' is appearently used by your shell as history expansion character. Say
A: '!' is apparently used by your shell as history expansion character. Say
"set +H" and add this line to your (bash) profile.

View file

@ -80,7 +80,7 @@ SHFILES = socat-chain.sh socat-mux.sh socat-broker.sh \
daemon.sh mail.sh ftp.sh readline.sh \
socat_buildscript_for_android.sh
TESTFILES = test.sh socks4echo.sh proxyecho.sh readline-test.sh \
proxy.sh socks4a-echo.sh
proxy.sh socks4a-echo.sh socks5server-echo.sh
all: progs doc

View file

@ -51,7 +51,7 @@ ACTIVE PHASE:
. xioopts.h: enum e_optcode (sorted numerically/alphabetically by name)
. xio-*.c: select the appropriate address file (e.g., xio-tcp.c for
TCP-options) and make a record of type struct optdesc: opt_newoption
. xio-*.h: the declation of struct optdesc
. xio-*.h: the declaration of struct optdesc
. xioopts.c: add records to struct optname optionnames for all appropriate
names (sorted strictly ASCII for binary search)
. filan.c: add the option to the appropriate array (sockopts, ipopts,

15
README
View file

@ -58,18 +58,25 @@ Rocky 9
Cygwin 10.0
install
-------
build
-----
You need at least gcc and make.
A few libraries are required for full features:
Debian: libssl-dev libreadline-dev libwrap0-dev
Red Hat: openssl-devel readline-devel tcp_wrappers-libs
Arch Linux: openssl readline
Get the tarball and extract it:
tar xzf socat.tar.gz
cd socat-1.8.0.2
cd socat-1.8.0.3
./configure
make
su
make install # installs socat, filan, and procan in /usr/local/bin
For compiling socat, gcc (or clang) is recommended.
For compiling socat, gcc or a compatible compiler (e.g. clang) is recommended.
If gcc (or a compiler with similar front end) is not available, the configure
script might fail to determine some features

View file

@ -29,7 +29,7 @@ initializes things so after a fork, the child must reinitialize. When the
ssl code detects a forks occur and if FIPS mode was enabled, it reinitializes
FIPS by disabling and then enabling it again.
To produce Davids enviroment, do the following:
To produce Davids environment, do the following:
To build openssl
download OpenSSL 0.9.7j-fips-dev from
http://www.openssl.org/source/OpenSSL-fips-1.0.tar.gz

View file

@ -24,7 +24,7 @@ avoid accessing files in world-writable directories like /tmp
* When using socat with system, exec, or in a shell script, know what you do
* With system and exec, use absolute pathes or set the path option
* With system and exec, use absolute paths or set the path option
* When starting programs with socat, consider using the chroot option (this
requires root, so use the substuser option too).

View file

@ -1 +1 @@
"1.8.0.2"
"1.8.0.3"

View file

@ -98,6 +98,10 @@ typedef int sig_atomic_t;
# define SOL_IPV6 IPPROTO_IPV6
#endif
#ifndef EAI_NODATA
# define EAI_NODATA 7 /* for old FreeBSD */
#endif
#define F_uint8_t "%hu"
#define F_uint8_x "%02hx"
#define F_int8_t "%hd"

View file

@ -162,6 +162,12 @@
/* Define if you have the clock_gettime function */
#undef HAVE_CLOCK_GETTIME
/* Define if you have the getresuid function */
#undef HAVE_GETRESUID
/* Define if you have the getresgid function */
#undef HAVE_GETRESGID
/* Define if you have the strtoll function */
#undef HAVE_STRTOLL
@ -282,6 +288,9 @@
/* Define if you have the <linux/if_tun.h> header file. */
#undef HAVE_LINUX_IF_TUN_H
/* Define if you have the <netinet/dccp.h> header file. */
#undef HAVE_NETINET_DCCP_H
/* Define if you have the <linux/dccp.h> header file. */
#undef HAVE_LINUX_DCCP_H
@ -333,6 +342,9 @@
/* Define if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
/* Define if you have the <mqueue.h> header file. */
#undef HAVE_MQUEUE_H
/* Define if you have the readline library. */
#undef HAVE_LIBREADLINE

View file

@ -39,7 +39,7 @@ AC_PROG_RANLIB
AC_SUBST(AR)
AC_CHECK_PROG(AR, ar, ar, gar)
#
# we need to explicitely call this here; otherwise, with --disable-libwrap we
# we need to explicitly call this here; otherwise, with --disable-libwrap we
# fail
AC_LANG_COMPILER_REQUIRE()
@ -409,21 +409,33 @@ AC_ARG_ENABLE(dccp, [ --disable-dccp disable DCCP support],
[AC_MSG_RESULT(yes); WITH_DCCP=1 ])
if test -n "$WITH_DCCP"; then
AC_MSG_CHECKING(for IPPROTO_DCCP)
AC_CACHE_VAL(sc_cv_define_ipproto_dccp,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <netinet/in.h>],
[IPPROTO_DCCP;],
[sc_cv_define_ipproto_dccp=yes],
[sc_cv_define_ipproto_dccp=no])])
AC_MSG_RESULT($sc_cv_define_ipproto_dccp)
if test $sc_cv_define_ipproto_dccp = yes; then
AC_DEFINE(WITH_DCCP)
AC_CHECK_HEADER(netinet/dccp.h,
AC_DEFINE(HAVE_NETINET_DCCP_H))
AC_CHECK_HEADER(linux/dccp.h,
AC_DEFINE(HAVE_LINUX_DCCP_H))
else
AC_MSG_WARN([IPPROTO_DCCP undefined, disabling DCCP support])
fi
if test -n "$WITH_DCCP"; then
AC_MSG_CHECKING(for IPPROTO_DCCP)
AC_CACHE_VAL(sc_cv_define_ipproto_dccp,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <netinet/in.h>],
[IPPROTO_DCCP;],
[sc_cv_define_ipproto_dccp=yes],
[sc_cv_define_ipproto_dccp=no; WITH_DCCP=])])
AC_MSG_RESULT($sc_cv_define_ipproto_dccp)
fi
if test -n "$WITH_DCCP"; then
AC_MSG_CHECKING(for SOCK_DCCP)
AC_CACHE_VAL(sc_cv_define_sock_dccp,
[AC_TRY_COMPILE([#include <sys/types.h>
#include <netinet/in.h>],
[SOCK_DCCP;],
[sc_cv_define_sock_dccp=yes],
[sc_cv_define_sock_dccp=no; WITH_DCCP=])])
AC_MSG_RESULT($sc_cv_define_sock_dccp)
fi
if test -n "$WITH_DCCP"; then
AC_DEFINE(WITH_DCCP)
fi
AC_MSG_CHECKING(whether to include vsock support)
@ -489,6 +501,13 @@ AC_ARG_ENABLE(posixmq, [ --disable-posixmq disable POSIX MQ support],
*) WITH_POSIXMQ=1; AC_MSG_RESULT(yes);;
esac],
[WITH_POSIXMQ=1; AC_MSG_RESULT(yes)])
if test "$WITH_POSIXMQ"; then
AC_CHECK_HEADERS(mqueue.h)
if test "x$ac_cv_header_mqueue_h" != xyes; then
AC_MSG_WARN([Header mqueue.h not found, disabling POSIX MQ])
WITH_POSIXMQ=
fi
fi
if test "$WITH_POSIXMQ"; then
case "`uname`" in
Linux) AC_DEFINE(WITH_POSIXMQ)
@ -652,23 +671,16 @@ if test -n "$WITH_OPENSSL"; then
AC_CACHE_VAL(sc_cv_have_openssl_ssl_h,
[AC_TRY_COMPILE([#include <openssl/ssl.h>],[;],
[sc_cv_have_openssl_ssl_h=yes; OPENSSL_BASE=""; ],
[sc_cv_have_openssl_ssl_h=no
if test "$OPENSSL_BASE"; then
Ds="$OPENSSL_BASE"
else
Ds="/sw /usr/local /opt/freeware /usr/sfw /usr/local/ssl"
fi
for D in $Ds; do
I="$D/include"
i="$I/openssl/ssl.h"
if test -r "$i"; then
#V_INCL="$V_INCL -I$I"
CPPFLAGS="$CPPFLAGS -I$I"
AC_MSG_NOTICE(found $i)
sc_cv_have_openssl_ssl_h=yes; OPENSSL_BASE="$D"
break;
fi
done])
[
# Another attempt to compile with OPENSSL_NO_KRB5
AC_MSG_NOTICE(trying with -DOPENSSL_NO_KRB5)
CFLAGS_ORIG="$CFLAGS"
CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
AC_TRY_COMPILE([#include <openssl/ssl.h>],[;],
[sc_cv_have_openssl_ssl_h=yes],
[sc_cv_have_openssl_ssl_h=no
CFLAGS="$CFLAGS_ORIG"])
])
])
if test "$sc_cv_have_openssl_ssl_h" = "yes"; then
AC_DEFINE(HAVE_OPENSSL_SSL_H)
@ -1722,6 +1734,8 @@ AC_CHECK_PROTOTYPE_LIB(gettimeofday)
AC_CHECK_FUNC(clock_gettime, AC_DEFINE(HAVE_CLOCK_GETTIME), AC_CHECK_LIB(rt, clock_gettime, [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)]))
AC_CHECK_FUNCS(getresuid getresgid)
dnl Search for flock()
# with Linux it's in libc, with AIX in libbsd
AC_CHECK_FUNC(flock, AC_DEFINE(HAVE_FLOCK),
@ -2248,7 +2262,7 @@ AC_TRY_COMPILE([#include <resolv.h>],
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
# deny_severity are not explicitly defined. Thus we put the libwrap part to
# the end
AC_MSG_CHECKING(whether to include libwrap support)
AC_ARG_ENABLE(libwrap, [ --disable-libwrap disable libwrap support],
@ -2303,7 +2317,7 @@ int allow_severity,deny_severity;],[hosts_access(0)],
AC_TRY_LINK([#include <sys/types.h>
#include <tcpd.h>
int allow_severity,deny_severity;],[hosts_access(0)],
[sc_cv_have_libwrap='yes'],
[sc_cv_have_libwrap='yes'],
[sc_cv_have_libwrap='no'])
]
)

View file

@ -10,7 +10,7 @@
<h2>Introduction</h2>
<p>Beginning with version 1.7.0 socat provides means to freely control
important aspects of socket handling. This allows to experiment with socket
types and protocols that are not explicitely implemented in socat.
types and protocols that are not explicitly implemented in socat.
</p>
<p>The related socat features fall into three major categories:<p>
@ -216,7 +216,7 @@ struct sockaddr_at {
</p>
<p>The address family component must be omitted from the socket address because
it is added by socat implicitely. The resulting hexadecimal representation of
it is added by socat implicitly. The resulting hexadecimal representation of
the target socket address is therefore:
</p>
<tt>x40x00xff00xf3x00x0000000000000000</tt>
@ -287,7 +287,7 @@ struct sockaddr_at {
and for bind and range options. The basis is the <tt>struct sockaddr_*</tt> for
the respective address family that should be declared in the C include files.
Please keep in mind that their first two bytes (<tt>sa_family</tt> and - on BSD
- <tt>sa_len</tt>) are implicitely prepended by socat.</p>
- <tt>sa_len</tt>) are implicitly prepended by socat.</p>
<h4>Linux on 32bit Intel:</h4>

View file

@ -313,6 +313,7 @@ label(ADDRESS_CREAT)dit(bf(tt(CREATE:<filename>)))
if <filename> refers to a socket, this is an error.nl()
Option groups: link(FD)(GROUP_FD),link(REG)(GROUP_REG),link(NAMED)(GROUP_NAMED) nl()
Useful options:
link(mode)(OPTION_UMASK),
link(mode)(OPTION_MODE),
link(user)(OPTION_USER),
link(group)(OPTION_GROUP),
@ -332,7 +333,7 @@ label(ADDRESS_DCCP_CONNECT)dit(bf(tt(DCCP-CONNECT:<host>:<port>)) (bf(tt(DCCP:<h
link(connect-timeout)(OPTION_CONNECT_TIMEOUT),
link(tos)(OPTION_TOS),
link(dccp-set-ccid)(OPTION_DCCP_SET_CCID),
link(nonblock)(OPTION_NONBLOCK),
link(nonblock)(OPTION_O_NONBLOCK),
link(sourceport)(OPTION_SOURCEPORT),
link(retry)(OPTION_RETRY),
link(readbytes)(OPTION_READBYTES)nl()
@ -583,7 +584,7 @@ label(ADDRESS_OPEN)dit(bf(tt(OPEN:<filename>)))
Option groups: link(FD)(GROUP_FD),link(REG)(GROUP_REG),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl()
Useful options:
link(creat)(OPTION_O_CREAT),
link(excl)(OPTION_EXCL),
link(excl)(OPTION_O_EXCL),
link(noatime)(OPTION_O_NOATIME),
link(nofollow)(OPTION_NOFOLLOW),
link(append)(OPTION_APPEND),
@ -747,7 +748,7 @@ label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
Option groups: link(FD)(GROUP_FD),link(NAMED)(GROUP_NAMED),link(OPEN)(GROUP_OPEN) nl()
Useful options:
link(rdonly)(OPTION_RDONLY),
link(nonblock)(OPTION_NONBLOCK),
link(nonblock)(OPTION_O_NONBLOCK),
link(group)(OPTION_GROUP),
link(user)(OPTION_USER),
link(mode)(OPTION_MODE),
@ -773,50 +774,65 @@ label(ADDRESS_SOCKETPAIR)dit(bf(tt(SOCKETPAIR)))
See also: link(unnamed pipe)(ADDRESS_UNNAMED_PIPE)
label(ADDRESS_POSIXMQ_READ)dit(bf(tt(POSIXMQ-READ:/<mqueue>)))
Opens the specified POSIX message queue and reads messages (packets). It
keeps the boundaries.nl()
Opens or creates the specified POSIX message queue and reads messages
(packets). It keeps the packet boundaries.nl()
This is a read-only address, see options link(-u)(option_u) and
link(-U)(option_U) and link(dual addresses)(ADDRESS_DUAL).nl()
Socat() provides this address type only on Linux because POSIX MQ is based
on UNIX filedescriptors there.nl()
This feature is new in version 1.8.0.0 and might change in the future,
therefore it is link(experimental)(option_experimental).nl()
Useful options:
link(posixmq-priority)(OPTION_POSIXMQ_PRIORITY),
link(unlink-early)(OPTION_UNLINK_EARLY),
link(unlink-close)(OPTION_UNLINK_CLOSE)
link(unlink-close)(OPTION_UNLINK_CLOSE),
link(o-nonblock)(OPTION_O_NONBLOCK),
link(o-creat)(OPTION_O_CREAT),
link(o-excl)(OPTION_O_EXCL),
link(umask)(OPTION_UMASK)
label(ADDRESS_POSIXMQ_RECEIVE)dit(bf(tt(POSIXMQ-RECEIVE:/<mqueue>)))
dit(bf(tt(POSIXMQ-RECV:/<mqueue>)))
Opens the specified POSIX message queue and reads one message (packet).nl()
Opens or creates the specified POSIX message queue and reads one message
(packet).nl()
This is a read-only address. See link(POSIXMQ-READ)(ADDRESS_POSIXMQ_READ)
for more info.nl()
Example: link(POSIX MQ recv with fork)(EXAMPLE_POSIXMQ_RECV_FORK)nl()
This feature is link(experimental)(option_experimental).nl()
Useful options:
link(posixmq-priority)(OPTION_POSIXMQ_PRIORITY),
link(fork)(OPTION_FORK),
link(max-children)(OPTION_MAX_CHILDREN),
link(unlink-early)(OPTION_UNLINK_EARLY),
link(unlink-close)(OPTION_UNLINK_CLOSE)
link(unlink-close)(OPTION_UNLINK_CLOSE),
link(o-creat)(OPTION_O_CREAT),
link(o-excl)(OPTION_O_EXCL),
link(umask)(OPTION_UMASK)
label(ADDRESS_POSIXMQ_SEND)dit(bf(tt(POSIXMQ-SEND:/<mqueue>)))
Opens the specified POSIX message queue and writes messages (packets).nl()
Opens or creates the specified POSIX message queue and writes messages
(packets).nl()
This is a write-only address. See link(POSIXMQ-READ)(ADDRESS_POSIXMQ_READ)
for more info.nl()
(link(Example)(EXAMPLE_POSIXMQ_SEND))nl()
This feature is link(experimental)(option_experimental).nl()
Useful options:
link(posixmq-priority)(OPTION_POSIXMQ_PRIORITY),
link(posixmq-flush)(OPTION_POSIXMQ_FLUSH),
link(fork)(OPTION_FORK),
link(max-children)(OPTION_MAX_CHILDREN),
link(unlink-early)(OPTION_UNLINK_EARLY),
link(unlink-close)(OPTION_UNLINK_CLOSE)
link(unlink-close)(OPTION_UNLINK_CLOSE),
link(o-creat)(OPTION_O_CREAT),
link(o-excl)(OPTION_O_EXCL),
link(umask)(OPTION_UMASK)
label(ADDRESS_POSIXMQ_WRITE)dit(bf(tt(POSIXMQ-WRITE:/<mqueue>)))
Does the same as link(POSIXMQ-SEND)(ADDRESS_POSIXMQ_SEND).
label(ADDRESS_POSIXMQ_BIDIRECTIONAL)dit(bf(tt(POSIXMQ-BIDIRECTIONAL:/mqueue)))
Opens the specified POSIX message queue and writes and reads messages
(packet). This is probably rarely useful but has been implemented for
functional completeness.
dit(bf(tt(POSIXMQ:/mqueue)))
Opens or creates the specified POSIX message queue in read and/or write mode
depending on context, then reads and/or writes messages (packets).
In bidirectional mode this is just another echo service.nl()
See link(POSIXMQ-READ)(ADDRESS_POSIXMQ_READ) and
link(POSIXMQ-SEND)(ADDRESS_POSIXMQ_SEND) for more info.
label(ADDRESS_PROXY_CONNECT)dit(bf(tt(PROXY:<proxy>:<hostname>:<port>)))
Connects to an HTTP proxy server on port 8080 using TCP/IP version 4 or 6
@ -882,7 +898,7 @@ label(ADDRESS_SCTP_CONNECT)dit(bf(tt(SCTP-CONNECT:<host>:<port>)))
link(mtudiscover)(OPTION_MTUDISCOVER),
link(sctp-maxseg)(OPTION_SCTP_MAXSEG),
link(sctp-nodelay)(OPTION_SCTP_NODELAY),
link(nonblock)(OPTION_NONBLOCK),
link(nonblock)(OPTION_O_NONBLOCK),
link(sourceport)(OPTION_SOURCEPORT),
link(retry)(OPTION_RETRY),
link(readbytes)(OPTION_READBYTES)nl()
@ -1103,11 +1119,11 @@ label(ADDRESS_SOCKS4A)dit(bf(tt(SOCKS4A:<socks-server>:<host>:<port>)))
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(SOCKS4)(GROUP_SOCKS),link(RETRY)(GROUP_RETRY) nl()
label(ADDRESS_SOCKS5_CONNECT)dit(bf(tt(SOCKS5-CONNECT:<socks-server>:<socks-port>:<target-host>:<target-port>)))
dit(bf(tt(SOCKS5-CONNECT:<socks-server>:<target-host>:<target-port>)))
Connects via <socks-server> [link(IP address)(TYPE_IP_ADDRESS)]
to <target-host> [link(IPv4 address)(TYPE_IPV4_ADDRESS)]
on <target-port> [link(TCP service)(TYPE_TCP_SERVICE)],
using socks version 5 protocol over TCP. Currently no authentication mechanism is provided.nl()
This address type is experimental.nl()
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(TCP)(GROUP_TCP), link(CHILD)(GROUP_CHILD), link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(socksport)(OPTION_SOCKSPORT),
@ -1122,10 +1138,11 @@ label(ADDRESS_SOCKS5_CONNECT)dit(bf(tt(SOCKS5-CONNECT:<socks-server>:<socks-port
link(TCP)(ADDRESS_TCP_CONNECT)
label(ADDRESS_SOCKS5_LISTEN)dit(bf(tt(SOCKS5-LISTEN:<socks-server>:<socks-port>:<listen-host>:<listen-port>)))
dit(bf(tt(SOCKS5-LISTEN:<socks-server>:<listen-host>:<listen-port>)))
Connects to <socks-server> [link(IP address)(TYPE_IP_ADDRESS)]
using socks version 5 protocol over TCP
and makes it listen for incoming connections on <listen-port> [link(TCP service)(TYPE_TCP_SERVICE)], binding to <-listen-host> [link(IPv4 address)(TYPE_IPV4_ADDRESS)]
Currently not authentication mechanism is provided. This address type is experimental.
Currently not authentication mechanism is provided.nl()
Option groups: link(FD)(GROUP_FD), link(SOCKET)(GROUP_SOCKET), link(IP4)(GROUP_IP4), link(IP6)(GROUP_IP6), link(TCP)(GROUP_TCP), link(CHILD)(GROUP_CHILD), link(RETRY)(GROUP_RETRY)nl()
Useful options:
link(sourceport)(OPTION_SOURCEPORT),
@ -1233,7 +1250,7 @@ label(ADDRESS_TCP_CONNECT)dit(bf(tt(TCP:<host>:<port>)))
link(mtudiscover)(OPTION_MTUDISCOVER),
link(mss)(OPTION_MSS),
link(nodelay)(OPTION_TCP_NODELAY),
link(nonblock)(OPTION_NONBLOCK),
link(nonblock)(OPTION_O_NONBLOCK),
link(readbytes)(OPTION_READBYTES)nl()
See also:
link(TCP4)(ADDRESS_TCP4_CONNECT),
@ -1290,7 +1307,7 @@ label(ADDRESS_TCP6_LISTEN)dit(bf(tt(TCP6-LISTEN:<port>)))
link(ipv6only)(OPTION_IPV6_V6ONLY)nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(RETRY)(GROUP_RETRY) nl()
label(ADDRESS_TUN)dit(bf(tt(TUN[:<if-addr>/<bits>])))
Creates a Linux TUN/TAP device and optionally assignes it the address and
Creates a Linux TUN/TAP device and optionally assigns it the address and
netmask given by the parameters. The resulting network interface is almost
ready for use by other processes; socat serves its "wire side". This address
requires read and write access to the tunnel cloning device, usually
@ -1418,7 +1435,8 @@ label(ADDRESS_UDP_SENDTO)dit(bf(tt(UDP-SENDTO:<host>:<port>)))
link(pf)(OPTION_PROTOCOL_FAMILY). It sends packets to and receives packets
from that peer socket only.
This address effectively implements a datagram client.
It works well with socat UDP-RECVFROM and UDP-RECV address peers.nl()
It works well with socat UDP-RECVFROM and UDP-RECV address peers.
When the peer might send data first, link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM) is preferable.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6) nl()
Useful options:
link(ttl)(OPTION_TTL),
@ -1456,7 +1474,8 @@ label(ADDRESS_UDP_RECVFROM)dit(bf(tt(UDP-RECVFROM:<port>)))
label(NOTE_RECVFROM)Note: When the second address fails before entering the transfer loop the
packet is dropped. Use option link(retry)(OPTION_RETRY) or
link(forever)(OPTION_FOREVER) on the second address to avoid data loss.
nl()
When you know the peer address, link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM) is
preferable.nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(CHILD)(GROUP_CHILD),link(RANGE)(GROUP_RANGE) nl()
Useful options:
link(fork)(OPTION_FORK),
@ -1839,8 +1858,10 @@ label(OPTION_MODE)dit(bf(tt(mode=<mode>)))
system calls, socat() uses the code(chmod()) system call after opening the
filesystem entry or binding to the unixdomain() socket (race condition!).
Otherwise, socat() sets the mode of the stream
using code(fchmod()).
These calls might require ownership or root privilege.
using code(fchmod()) which, btw, might not have any effect.nl()
These calls might require ownership or root privilege.nl()
Note: this option can only tighten the permissions implied by processes
umask. See option link(umask)(OPTION_UMASK) to loosen permissions.
label(OPTION_PERM_LATE)dit(bf(tt(perm-late=<mode>)))
Sets the permissions of the fd to value <mode>
[link(mode_t)(TYPE_MODE_T)] using the code(fchmod()) system call after
@ -1852,7 +1873,7 @@ label(OPTION_APPEND)dit(bf(tt(append[=<bool>])))
socat() uses the code(O_APPEND) flag with the code(open()) system call
(link(example)(EXAMPLE_OPTION_APPEND)).
Otherwise, socat() applies the code(fcntl(fd, F_SETFL, O_APPEND)) call.
label(OPTION_NONBLOCK)dit(bf(tt(nonblock[=<bool>])))
label(OPTION_O_NONBLOCK)dit(bf(tt(nonblock[=<bool>])))
Tries to open or use file in nonblocking mode. Its only effects are that the
code(connect()) call of TCP addresses does not block, and that opening a
named pipe for reading does not block.
@ -1987,13 +2008,13 @@ E.g., option `creat' sets the code(O_CREAT) flag. When the used address does
not use code(open()) (e.g.STDIO), the code(fcntl(..., F_SETFL, ...)) call is
used instead.nl()
See also options link(append)(OPTION_APPEND) and
link(nonblock)(OPTION_NONBLOCK).
link(nonblock)(OPTION_O_NONBLOCK).
startdit()
label(OPTION_O_CREAT)dit(bf(tt(creat[=<bool>])))
Creates the file if it does not exist (link(example)(EXAMPLE_OPTION_CREAT)).
label(OPTION_DSYNC)dit(bf(tt(dsync[=<bool>])))
Blocks code(write()) calls until metainfo is physically written to media.
label(OPTION_EXCL)dit(bf(tt(excl[=<bool>])))
label(OPTION_O_EXCL)dit(bf(tt(excl[=<bool>])))
With option creat, if file exists this is an error.
label(OPTION_LARGEFILE)dit(bf(tt(largefile[=<bool>])))
On 32 bit systems, allows a file larger than 2^31 bytes.
@ -2108,8 +2129,9 @@ label(OPTION_CHDIR)dit(bf(tt(chdir=<filename>))) dit(bf(tt(cd=<filename>)))
label(OPTION_UMASK)dit(bf(tt(umask=<mode>)))
Sets the umask of the process to <mode> [link(mode_t)(TYPE_MODE_T)] before
opening the address. Useful when file system entries are created or a shell
or program is invoked. Usually the value is specified as octal number.nl()
The processes tt(umask) value is inherited by child processes.
or program is invoked. Usually the value is specified as octal number with
leading '0'.nl()
The processes tt(umask) value is inherited by child processes.nl()
Note: umask is an inverted value: creating a file with umask=0026 results in
permissions 0640.
enddit()
@ -2136,7 +2158,7 @@ label(OPTION_SETGID)dit(bf(tt(setgid=<group>)))
processing the address. This call might require root privilege. Please note
that this option does not drop other group related privileges.
label(OPTION_SETGID_EARLY)dit(bf(tt(setgid-early=<group>)))
Like link(setgit)(OPTION_SETGID) but is performed before opening the address.
Like link(setgid)(OPTION_SETGID) but is performed before opening the address.
label(OPTION_SETUID)dit(bf(tt(setuid=<user>)))
Changes the link(<user>)(TYPE_USER) (owner) of the process after processing
the address. This call might require root privilege. Please note that this
@ -2164,9 +2186,9 @@ label(OPTION_SETSID)dit(bf(tt(setsid)))
Makes the process the leader of a new session (link(example)(EXAMPLE_OPTION_SETSID)).
label(OPTION_NETNS)dit(bf(tt(netns=<net-namespace-name>)))
Before opening the address it tries to switch to the named network namespace.
After opening the address it switches back to the previous namespace.
(link(Example with TCP forwarder)(EXAMPLE_OPTION_NETNS),
link(example with virtual network connection)(EXAMPLE_TUN_NETNS).nl()
After opening the address it switches back to the previous namespace
(link(example with TCP forwarder)(EXAMPLE_OPTION_NETNS),
link(example with virtual network connection)(EXAMPLE_TUN_NETNS)).nl()
Only on Linux; requires root; use option tt(--experimental).nl()
enddit()
@ -2189,7 +2211,7 @@ label(OPTION_NOECHO)dit(bf(tt(noecho=<pattern>)))
Specifies a regular pattern for a prompt that prevents the following input
line from being displayed on the screen and from being added to the history.
The prompt is defined as the text that was output to the readline address
after the lastest newline character and before an input character was
after the last newline character and before an input character was
typed. The pattern is a regular expression, e.g.
"^[Pp]assword:.*$" or "([Uu]ser:|[Pp]assword:)". See NOEXPAND(regex(7)) for details.
(link(example)(EXAMPLE_OPTION_NOECHO))
@ -2368,7 +2390,7 @@ COMMENT(label(OPTION_SECURITYENCRYPTIONNETWORK)dit(bf(tt(securityencryptionnetwo
COMMENT(label(OPTION_SECURITYENCRYPTIONTRANSPORT)dit(bf(tt(securityencryptiontransport)))
Set the code(SO_SECURITY_ENCRYPTION_TRANSPORT) socket option.)
COMMENT(label(OPTION_SIOCSPGRP)dit(bf(tt(siocspgrp=<pid_t>)))
Set the SIOCSPGRP with code(ioclt()) to enable SIGIO.)
Set the SIOCSPGRP with code(ioctl()) to enable SIGIO.)
COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
Set the code(SO_USE_IFBUFS) socket option.)
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
@ -2394,6 +2416,12 @@ label(OPTION_SETSOCKOPT_STRING)dit(bf(tt(setsockopt-string=<level>:<optname>:<op
Like tt(setsockopt), but <optval> is a link(string)(TYPE_STRING).
This string is passed to the function with trailing null character, and the
length parameter is automatically derived from the data.
label(OPTION_SETSOCKOPT_SOCKET)dit(bf(tt(setsockopt-socket=<level>:<optname>:<optval>)))
Like tt(setsockopt), but is applied to the socket before other operations
(code(bind()), code(connect()), code(accept()), ...)
label(OPTION_SETSOCKOPT_CONNECTED)dit(bf(tt(setsockopt-connected=<level>:<optname>:<optval>)))
Like tt(setsockopt), but is applied only when the socket has been connected
by a code(connect()) or code(listen()) call.
enddit()
startdit()enddit()nl()
@ -2525,7 +2553,8 @@ dit(bf(tt(ipv6-join-source-group=<multicast-address:interface-index:source-addre
IPv4 variant. The option takes the IP address of the multicast group,
info about the desired network interface and the source IP address of the
multicast traffic. The indices of active network interfaces can be shown
using the utility procan().
using the utility procan().nl()
This feature is experimental.
label(OPTION_IP_MULTICAST_IF)
dit(bf(tt(ip-multicast-if=<hostname>)))
Specifies hostname or address of the network interface to be used for
@ -2976,6 +3005,8 @@ label(OPTION_NOFORK)dit(bf(tt(nofork)))
it() the first socat address cannot be OPENSSL or READLINE
it() socat options -b, -t, -D, -l, -v, -x become useless
it() for both addresses, options ignoreeof, cr, and crnl become useless
it() for both addresses, address specific end/shutdown handling (e.g.,
graceful socket shutdown) and related options become useless
it() for the second address (the one with option nofork), options
append, metaCOMMENT(async,) cloexec, flock, user, group, mode, nonblock,
perm-late, setlk, and setpgid cannot be applied. Some of these could be
@ -3345,7 +3376,7 @@ label(OPTION_OPENSSL_PSEUDO)dit(bf(tt(pseudo)))
gathering daemon can be utilized, this option activates a mechanism for
providing pseudo entropy. This is achieved by taking the current time in
microseconds for feeding the libc pseudo random number generator with an
initial value. openssl is then feeded with output from NOEXPAND(random()) calls.nl()
initial value. openssl is then fed with output from NOEXPAND(random()) calls.nl()
NOTE:This mechanism is not sufficient for generation of secure keys!
label(OPTION_OPENSSL_COMPRESS)dit(bf(tt(compress)))
Enable or disable the use of compression for a connection. Setting this to
@ -3490,6 +3521,15 @@ startdit()
label(OPTION_POSIXMQ_PRIORITY)dit(bf(tt(posixmq-priority (mq-prio))))
Sets the priority of messages (packets) written to the queue, or the minimal
priority of packet read from the queue.
label(OPTION_POSIXMQ_FLUSH)dit(bf(tt(posixmq-flush (mq-flush))))
"Consumes" (drops) all messages currently in the queue before starting
transfers.
label(OPTION_POSIXMQ_MAXMSG)dit(bf(tt(posixmq-maxmsg (mq-maxmsg))))
Sets the maxmsg parameter of the POSIX message queue when creating it.nl()
Note: This option applies only when the queue does not already exist.
label(OPTION_POSIXMQ_MSGSIZE)dit(bf(tt(posixmq-msgsize (mq-msgsize))))
Sets the msgsize parameter of the POSIX message queue when creating it.nl()
Note: This option applies only when the queue does not already exist.
enddit()
@ -3512,7 +3552,8 @@ label(TYPE_COMMAND_LINE)dit(command-line)
A string specifying a program name and its arguments, separated by single
spaces.
label(TYPE_DATA)dit(data)
This is a more general data specification. The given text string contains
This is a more general data specification, "dalan" (low level data
description language). The given text string contains
information about the target data type and value. Generally a leading
character specifies the type of the following data item. In its specific
context a default data type may exist.nl()
@ -3528,12 +3569,12 @@ label(TYPE_DATA)dit(data)
dit(b) A signed byte (signed char).nl()
dit(B) An unsigned byte (unsigned char).nl()
dit(x) Following is an even number of hex digits, stored as sequence of
bytes.nl()
bytes, the data length is the resulting number of bytes.nl()
Example: bf(x7f000001) (IP address 127.0.0.1)
dit(") Following is a string that is used with the common conversions
\n \r \t \f \b \a \e \0; the string must be closed with '"'. Please note
that the quotes and backslashes need to be escaped from shell and socat()
conversion.nl()
conversion. No implicit \0 is appended.nl()
Example: bf("Hello world!\n")
dit(') A single char, with the usual conversions. Please note that the
quotes and backslashes need to be escaped from shell and socat() conversion.
@ -3581,10 +3622,10 @@ label(TYPE_LONG)dit(long)
label(TYPE_LONGLONG)dit(long long)
A number read with code(strtoll()). The value must fit into a C long long.
label(TYPE_OFF)dit(off_t)
An implementation dependend signed number, usually 32 bits, read with strtol
An implementation dependent signed number, usually 32 bits, read with strtol
or strtoll.
label(TYPE_OFF64)dit(off64_t)
An implementation dependend signed number, usually 64 bits, read with strtol
An implementation dependent signed number, usually 64 bits, read with strtol
or strtoll.
label(TYPE_MODE_T)dit(mode_t)
An unsigned integer, read with code(strtoul()), specifying mode (permission)
@ -3972,7 +4013,7 @@ prompts.
label(EXAMPLE_ADDRESS_PTY)
label(EXAMPLE_OPTION_SYMBOLIC_LINK)
label(EXAMPLE_OPTION_WAIT_SLAVE)
label(EXAMPLE_OPTION_NONBLOCK)
label(EXAMPLE_OPTION_O_NONBLOCK)
mancommand(\.LP)
mancommand(\.nf)
mancommand(\fBsocat \\)
@ -4445,14 +4486,14 @@ both devices. Use pppd on device tt(/var/run/ppp) then.
label(EXAMPLE_POSIXMQ_SEND)
mancommand(\.LP)
mancommand(\.nf)
mancommand(\fBsocat --experimental -u \\)
mancommand(\fBsocat -u \\)
mancommand(\.RS)
mancommand(\fBSTDIO \\
POSIXMQ-SEND:/queue1,unlink-early,mq-prio=10\fP)
mancommand(\.RE)
mancommand(\.fi)
htmlcommand(<hr><div class="shell">socat --experimental -u &#x5C;
htmlcommand(<hr><div class="shell">socat -u &#x5C;
STDIO &#x5C;
POSIXMQ-SEND:/queue1,unlink-early,mq-prio=10</div>)
@ -4464,7 +4505,7 @@ label(EXAMPLE_POSIXMQ_RECV_FORK)
mancommand(\.LP)
mancommand(\.nf)
mancommand(\fBsocat --experimental -u \\)
mancommand(\fBsocat -u \\)
mancommand(\.RS)
mancommand(\fBPOSIXMQ-RECV:/queue1,fork,max-children=3 \\
SYSTEM:"worker.sh"\fP)
@ -4472,7 +4513,7 @@ mancommand(\fBPOSIXMQ-RECV:/queue1,fork,max-children=3 \\
mancommand(\.RE)
mancommand(\.fi)
htmlcommand(<hr><div class="shell">socat --experimental -u &#x5C;
htmlcommand(<hr><div class="shell">socat -u &#x5C;
POSIXMQ-RECV:/queue1,fork,max-children=3 &#x5C;
SYSTEM:"worker.sh"</div>)

View file

@ -183,7 +183,7 @@
#define Debug18(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18)
#endif /* !(WITH_MSGLEVEL <= E_DEBUG) */
/* message with software controlled serverity */
/* message with software controlled severity */
#if WITH_MSGLEVEL <= E_FATAL
#define Msg(l,m) msg(l,"%s",m)
#define Msg1(l,m,a1) msg(l,m,a1)

View file

@ -226,7 +226,7 @@ int sockname(int fd, FILE *outfile, char style) {
#define FDNAME_OPTLEN 256
#define FDNAME_NAMELEN 256
socklen_t optlen;
#if HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R
#if (WITH_IP4 || WITH_IP6) && ( HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R )
struct protoent protoent, *protoentp;
#endif
#define PROTONAMEMAX 1024
@ -278,7 +278,7 @@ int sockname(int fd, FILE *outfile, char style) {
Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
#endif
#if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
#if (WITH_IP4 || WITH_IP6) && ( defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) )
#if HAVE_GETPROTOBYNUMBER_R==1 /* Linux */
rc = getprotobynumber_r(proto, &protoent, protoname, sizeof(protoname), &protoentp);
if (protoentp == NULL) {

10
filan.c
View file

@ -393,7 +393,7 @@ int filan_stat(
break;
#ifdef S_IFLNK
case (S_IFLNK): /* 10, symbolic link */
/* we wait for freadlink() sytem call */
/* we wait for freadlink() system call */
break;
#endif /* S_IFLNK */
break;
@ -804,13 +804,13 @@ int ipan(int fd, FILE *outfile) {
}
/* want to pass the fd to the next layer protocol. */
#if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
if (Getsockopt(fd, SOL_SOCKET,
if (
#ifdef SO_PROTOCOL
SO_PROTOCOL,
Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &optproto, &optlen)
#elif defined(SO_PROTOTYPE)
SO_PROTOTYPE,
Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &optproto, &optlen)
#endif
&optproto, &optlen) >= 0) {
>= 0) {
switch (optproto) {
#if WITH_TCP
case IPPROTO_TCP: tcpan(fd, outfile); break;

View file

@ -167,7 +167,7 @@ int main(int argc, const char *argv[]) {
Nanosleep(&waittime, NULL);
if (style == 0) {
/* this style gives detailled infos, but requires a file descriptor */
/* This style gives detailed infos, but requires a file descriptor */
if (filename) {
#if LATER /* this is just in case that S_ISSOCK does not work */
struct stat buf;

View file

@ -33,6 +33,11 @@ int hostan(FILE *outfile) {
#endif
fprintf(outfile, "sizeof(size_t) = %u\n", (unsigned int)sizeof(size_t));
if ((char)-1 > 0)
fprintf(outfile, "typedef unsigned char char;\n");
else
fprintf(outfile, "typedef signed char char;\n");
# if HAVE_BASIC_SIZE_T==2
fprintf(outfile, "typedef unsigned short size_t; /* sizeof(size_t) = %u */\n", (unsigned int)sizeof(size_t));
#elif HAVE_BASIC_SIZE_T==4

View file

@ -15,30 +15,91 @@
#include "procan.h"
int procan_cdefs(FILE *outfile) {
/* basic C/system constants */
/* System constants */
#ifdef __KERNEL__
fprintf(outfile, "__KERNEL__ = \"%s\"\n", __KERNEL__);
#endif
#ifdef __GLIBC__
fprintf(outfile, "__GLIBC__ = %d\n", __GLIBC__);
#endif
/* Basic C/system constants */
#ifdef FD_SETSIZE
fprintf(outfile, "#define FD_SETSIZE %u\n", FD_SETSIZE);
fprintf(outfile, "#define FD_SETSIZE %u\n", FD_SETSIZE);
#endif
#ifdef NFDBITS
fprintf(outfile, "#define NFDBITS %d\n", (int)NFDBITS);
fprintf(outfile, "#define NFDBITS %d\n", (int)NFDBITS);
#endif
#ifdef O_RDONLY
fprintf(outfile, "#define O_RDONLY %u\n", O_RDONLY);
fprintf(outfile, "#define O_RDONLY %u\n", O_RDONLY);
#endif
#ifdef O_WRONLY
fprintf(outfile, "#define O_WRONLY %u\n", O_WRONLY);
fprintf(outfile, "#define O_WRONLY %u\n", O_WRONLY);
#endif
#ifdef O_RDWR
fprintf(outfile, "#define O_RDWR %u\n", O_RDWR);
fprintf(outfile, "#define O_RDWR %u\n", O_RDWR);
#endif
#ifdef O_CREAT
fprintf(outfile, "#define O_CREAT 0x%06x /* 0%08o */\n", O_CREAT, O_CREAT);
#endif
#ifdef O_EXCL
fprintf(outfile, "#define O_EXCL 0x%06x /* 0%08o */\n", O_EXCL, O_EXCL);
#endif
#ifdef O_NOCTTY
fprintf(outfile, "#define O_NOCTTY 0x%06x /* 0%08o */\n", O_NOCTTY, O_NOCTTY);
#endif
#ifdef O_TRUNC
fprintf(outfile, "#define O_TRUNC 0x%06x /* 0%08o */\n", O_TRUNC, O_TRUNC);
#endif
#ifdef O_APPEND
fprintf(outfile, "#define O_APPEND 0x%06x /* 0%08o */\n", O_APPEND, O_APPEND);
#endif
#ifdef O_NONBLOCK
fprintf(outfile, "#define O_NONBLOCK 0x%06x /* 0%08o */\n", O_NONBLOCK, O_NONBLOCK);
#endif
#ifdef O_NDELAY
fprintf(outfile, "#define O_NDELAY 0x%06x /* 0%08o */\n", O_NDELAY, O_NDELAY);
#endif
#ifdef O_SYNC
fprintf(outfile, "#define O_SYNC 0x%06x /* 0%08o */\n", O_SYNC, O_SYNC);
#endif
#ifdef O_FSYNC
fprintf(outfile, "#define O_FSYNC 0x%06x /* 0%08o */\n", O_FSYNC, O_FSYNC);
#endif
#ifdef O_LARGEFILE
fprintf(outfile, "#define O_LARGEFILE 0x%06x /* 0%08o */\n", O_LARGEFILE, O_LARGEFILE);
#endif
#ifdef O_DIRECTORY
fprintf(outfile, "#define O_DIRECTORY 0x%06x /* 0%08o */\n", O_DIRECTORY, O_DIRECTORY);
#endif
#ifdef O_NOFOLLOW
fprintf(outfile, "#define O_NOFOLLOW 0x%06x /* 0%08o */\n", O_NOFOLLOW, O_NOFOLLOW);
#endif
#ifdef O_CLOEXEC
fprintf(outfile, "#define O_CLOEXEC 0x%06x /* 0%08o */\n", O_CLOEXEC, O_CLOEXEC);
#endif
#ifdef O_DIRECT
fprintf(outfile, "#define O_DIRECT 0x%06x /* 0%08o */\n", O_DIRECT, O_DIRECT);
#endif
#ifdef O_NOATIME
fprintf(outfile, "#define O_NOATIME 0x%06x /* 0%08o */\n", O_NOATIME, O_NOATIME);
#endif
#ifdef O_PATH
fprintf(outfile, "#define O_PATH 0x%06x /* 0%08o */\n", O_PATH, O_PATH);
#endif
#ifdef O_DSYNC
fprintf(outfile, "#define O_DSYNC 0x%06x /* 0%08o */\n", O_SYNC, O_SYNC);
#endif
#ifdef O_TMPFILE
fprintf(outfile, "#define O_TMPFILE 0x%06x /* 0%08o */\n", O_TMPFILE, O_TMPFILE);
#endif
#ifdef SHUT_RD
fprintf(outfile, "#define SHUT_RD %u\n", SHUT_RD);
fprintf(outfile, "#define SHUT_RD %u\n", SHUT_RD);
#endif
#ifdef SHUT_WR
fprintf(outfile, "#define SHUT_WR %u\n", SHUT_WR);
fprintf(outfile, "#define SHUT_WR %u\n", SHUT_WR);
#endif
#ifdef SHUT_RDWR
fprintf(outfile, "#define SHUT_RDWR %u\n", SHUT_RDWR);
fprintf(outfile, "#define SHUT_RDWR %u\n", SHUT_RDWR);
#endif
/* Compile time controls */
@ -51,40 +112,40 @@ int procan_cdefs(FILE *outfile) {
/* termios constants */
#ifdef CRDLY
fprintf(outfile, "#define CRDLY 0%011o\n", CRDLY);
fprintf(outfile, "#define CRDLY 0x%08x /* 0%011o */\n", CRDLY, CRDLY);
#endif
#ifdef CR0
fprintf(outfile, "#define CR0 0%011o\n", CR0);
fprintf(outfile, "#define CR0 0x%08x /* 0%011o */\n", CR0, CR0);
#endif
#ifdef CR1
fprintf(outfile, "#define CR1 0%011o\n", CR1);
fprintf(outfile, "#define CR1 0x%08x /* 0%011o */\n", CR1, CR1);
#endif
#ifdef CR2
fprintf(outfile, "#define CR2 0%011o\n", CR2);
fprintf(outfile, "#define CR2 0x%08x /* 0%011o */\n", CR2, CR2);
#endif
#ifdef CR3
fprintf(outfile, "#define CR3 0%011o\n", CR3);
fprintf(outfile, "#define CR3 0x%08x /* 0%011o */\n", CR3, CR3);
#endif
#ifdef TABDLY
fprintf(outfile, "#define TABDLY 0%011o\n", TABDLY);
fprintf(outfile, "#define TABDLY 0x%08x /* 0%011o */\n", TABDLY, TABDLY);
#endif
#ifdef TAB0
fprintf(outfile, "#define TAB0 0%011o\n", TAB0);
fprintf(outfile, "#define TAB0 0x%08x /* 0%011o */\n", TAB0, TAB0);
#endif
#ifdef TAB1
fprintf(outfile, "#define TAB1 0%011o\n", TAB1);
fprintf(outfile, "#define TAB1 0x%08x /* 0%011o */\n", TAB1, TAB1);
#endif
#ifdef TAB2
fprintf(outfile, "#define TAB2 0%011o\n", TAB2);
fprintf(outfile, "#define TAB2 0x%08x /* 0%011o */\n", TAB2, TAB2);
#endif
#ifdef TAB3
fprintf(outfile, "#define TAB3 0%011o\n", TAB3);
fprintf(outfile, "#define TAB3 0x%08x /* 0%011o */\n", TAB3, TAB3);
#endif
#ifdef CSIZE
fprintf(outfile, "#define CSIZE 0%011o\n", CSIZE);
fprintf(outfile, "#define CSIZE 0x%08x /* 0%011o */\n", CSIZE, CSIZE);
#endif
#ifdef TIOCEXCL
fprintf(outfile, "#define TIOCEXCL 0x%lx\n", (unsigned long)TIOCEXCL);
fprintf(outfile, "#define TIOCEXCL 0x%lx\n", (unsigned long)TIOCEXCL);
#endif
/* stdio constants */
@ -188,5 +249,78 @@ int procan_cdefs(FILE *outfile) {
#ifdef TCP_MAXSEG
fprintf(outfile, "#define TCP_MAXSEG %d\n", TCP_MAXSEG);
#endif
#ifdef AI_PASSIVE
fprintf(outfile, "#define AI_PASSIVE 0x%02x\n", AI_PASSIVE);
#endif
#ifdef AI_CANONNAME
fprintf(outfile, "#define AI_CANONNAME 0x%02x\n", AI_CANONNAME);
#endif
#ifdef AI_NUMERICHOST
fprintf(outfile, "#define AI_NUMERICHOST 0x%02x\n", AI_NUMERICHOST);
#endif
#ifdef AI_V4MAPPED
fprintf(outfile, "#define AI_V4MAPPED 0x%02x\n", AI_V4MAPPED);
#endif
#ifdef AI_ALL
fprintf(outfile, "#define AI_ALL 0x%02x\n", AI_ALL);
#endif
#ifdef AI_ADDRCONFIG
fprintf(outfile, "#define AI_ADDRCONFIG 0x%02x\n", AI_ADDRCONFIG);
#endif
#ifdef EAI_BADFLAGS
fprintf(outfile, "#define EAI_BADFLAGS %d\n", EAI_BADFLAGS);
#endif
#ifdef EAI_NONAME
fprintf(outfile, "#define EAI_NONAME %d\n", EAI_NONAME);
#endif
#ifdef EAI_AGAIN
fprintf(outfile, "#define EAI_AGAIN %d\n", EAI_AGAIN);
#endif
#ifdef EAI_FAIL
fprintf(outfile, "#define EAI_FAIL %d\n", EAI_FAIL);
#endif
#ifdef EAI_FAMILY
fprintf(outfile, "#define EAI_FAMILY %d\n", EAI_FAMILY);
#endif
#ifdef EAI_SOCKTYPE
fprintf(outfile, "#define EAI_SOCKTYPE %d\n", EAI_SOCKTYPE);
#endif
#ifdef EAI_SERVICE
fprintf(outfile, "#define EAI_SERVICE %d\n", EAI_SERVICE);
#endif
#ifdef EAI_MEMORY
fprintf(outfile, "#define EAI_MEMORY %d\n", EAI_MEMORY);
#endif
#ifdef EAI_SYSTEM
fprintf(outfile, "#define EAI_SYSTEM %d\n", EAI_SYSTEM);
#endif
#ifdef EAI_OVERFLOW
fprintf(outfile, "#define EAI_OVERFLOW %d\n", EAI_OVERFLOW);
#endif
#ifdef EAI_NODATA
fprintf(outfile, "#define EAI_NODATA %d\n", EAI_NODATA);
#endif
#ifdef EAI_ADDRFAMILY
fprintf(outfile, "#define EAI_ADDRFAMILY %d\n", EAI_ADDRFAMILY);
#endif
#ifdef EAI_INPROGRESS
fprintf(outfile, "#define EAI_INPROGRESS %d\n", EAI_INPROGRESS);
#endif
#ifdef EAI_CANCELED
fprintf(outfile, "#define EAI_CANCELED %d\n", EAI_CANCELED);
#endif
#ifdef EAI_NOTCANCELED
fprintf(outfile, "#define EAI_NOTCANCELED %d\n", EAI_NOTCANCELED);
#endif
#ifdef EAI_ALLDONE
fprintf(outfile, "#define EAI_ALLDONE %d\n", EAI_ALLDONE);
#endif
#ifdef EAI_INTR
fprintf(outfile, "#define EAI_INTR %d\n", EAI_INTR);
#endif
#ifdef EAI_IDN_ENCODE
fprintf(outfile, "#define EAI_IDN_ENCODE %d\n", EAI_IDN_ENCODE);
#endif
return 0;
}

View file

@ -187,10 +187,30 @@ int procan(FILE *outfile) {
fprintf(outfile, "process group id if fg process / stderr = "F_pid"\n", Tcgetpgrp(2));
/* process owner, groups */
#if HAVE_GETRESUID
{
uid_t ruid, euid, suid;
getresuid(&ruid, &euid, &suid);
fprintf(outfile, "user id = "F_uid"\n", ruid);
fprintf(outfile, "effective user id = "F_uid"\n", euid);
fprintf(outfile, "saved set-user id = "F_uid"\n", suid);
}
#else /* !HAVE_GETRESUID */
fprintf(outfile, "user id = "F_uid"\n", Getuid());
fprintf(outfile, "effective user id = "F_uid"\n", Geteuid());
#endif /* !HAVE_GETRESUID */
#if HAVE_GETRESGID
{
gid_t rgid, egid, sgid;
getresgid(&rgid, &egid, &sgid);
fprintf(outfile, "group id = "F_gid"\n", rgid);
fprintf(outfile, "effective group id = "F_gid"\n", egid);
fprintf(outfile, "saved set-group id = "F_gid"\n", sgid);
}
#else /* !HAVE_GETRESGID */
fprintf(outfile, "group id = "F_gid"\n", Getgid());
fprintf(outfile, "effective group id = "F_gid"\n", Getegid());
#endif /* !HAVE_GETRESGID */
/* Simple process features */
fprintf(outfile, "\n");

View file

@ -13,6 +13,9 @@ const char copyright[] = "procan by Gerhard Rieger and contributors - send bug r
#if HAVE_SYS_SELECT_H
#include <sys/select.h> /* select(), fdset on FreeBSD */
#endif
#if HAVE_SYS_UTSNAME_H
#include <sys/utsname.h> /* uname(), struct utsname */
#endif
#include "mytypes.h"
#include "error.h"
#include "procan.h"
@ -22,6 +25,13 @@ const char copyright[] = "procan by Gerhard Rieger and contributors - send bug r
#define WITH_HELP 1
static void procan_usage(FILE *fd);
static void procan_version(FILE *fd);
const char copyright_procan[] = "procan by Gerhard Rieger and contributors - see www.dest-unreach.org";
static const char procanversion[] =
#include "./VERSION"
;
static const char timestamp[] = BUILD_DATE;
int main(int argc, const char *argv[]) {
@ -39,8 +49,8 @@ int main(int argc, const char *argv[]) {
case '?': case 'h': procan_usage(stdout); exit(0);
#endif /* WITH_HELP */
case 'c': procan_cdefs(stdout); exit(0);
#if LATER
case 'V': procan_version(stdout); exit(0);
#if LATER
case 'l': diag_set(arg1[0][2], &arg1[0][3]); break;
case 'd': diag_set('d', NULL); break;
#endif
@ -80,9 +90,7 @@ static void procan_usage(FILE *fd) {
fputs("Usage:\n", fd);
fputs("procan [options]\n", fd);
fputs(" options:\n", fd);
#if LATER
fputs(" -V print version information to stdout, and exit\n", fd);
#endif
#if WITH_HELP
fputs(" -?|-h print a help text describing command line options\n", fd);
#endif
@ -100,3 +108,17 @@ static void procan_usage(FILE *fd) {
#endif
}
#endif /* WITH_HELP */
void procan_version(
FILE *fd)
{
struct utsname ubuf;
fputs(copyright_procan, fd); fputc('\n', fd);
fprintf(fd, "procan version %s on %s\n", procanversion, timestamp);
uname(&ubuf);
fprintf(fd, " running on %s version %s, release %s, machine %s\n",
ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
return;
}

View file

@ -36,7 +36,7 @@ $ECHO
if [ "$USERNAME" != "$CREDUSER" -o "$PASSWORD" != "$CREDPASS" ]; then
$ECHO "Authentication failed" >&2
exit -1
exit 1
fi
while $ECHO "$PROMPT\c"; read -r COMMAND; do

View file

@ -4,15 +4,19 @@
# Published under the GNU General Public License V.2, see file COPYING
# this is an attempt for a socat based readline wrapper
# usage: readline.sh <command>
# usage: readline.sh [options] <program>
withhistfile=1
STDERR=
while true; do
case "X$1" in
X-nh|X-nohist*) withhistfile=; shift; continue ;;
*) break;;
X-lf?*) STDERR="${1:3}" ;;
X-lf) shift; STDERR="$1" ;;
X-nh|X-nohist*) withhistfile= ;;
*) break;;
esac
shift
done
PROGRAM="$@"
@ -25,12 +29,18 @@ fi
#
#
if test -w .; then
#if test -w .; then
if [ -z "$STDERR" ] && find . -maxdepth 0 -user $USER ! -perm /022 -print |grep ^ >/dev/null; then
# When cwd is owned by $USER and it is neither group nor world writable
STDERR=./socat-readline.${1##*/}.log
rm -f $STDERR
else
echo "$0: logs go to $STDERR" >&2
elif [ -z "$STDERR" ]; then
echo "$0: insecure working directory, no logs are written" >&2
STDERR=/dev/null
else
echo "$0: logs go to $STDERR" >&2
fi
exec socat -d readline"$HISTOPT",noecho='[Pp]assword:' exec:"$PROGRAM",sigint,pty,setsid,ctty,raw,echo=0,stderr 2>$STDERR
exec socat -d READLINE"$HISTOPT",noecho='[Pp]assword:' EXEC:"$PROGRAM",sigint,pty,setsid,ctty,raw,echo=0,stderr 2>$STDERR

View file

@ -37,6 +37,7 @@ while [ "$1" ]; do
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X--experimental) ;;
X-) break ;;
X-*) echo "Unknown option \"$1\"" >&2
usage >&2

View file

@ -77,6 +77,7 @@ while [ "$1" ]; do
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X--experimental) ;;
X-) break ;;
X-*) echo "$0: Unknown option \"$1\"" >&2
usage >&2

View file

@ -2,7 +2,7 @@
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Shell script to build a many-to-one, one-to-all communication
# Shell script to establish many-to-one, one-to-all communications.
# It starts two Socat instances that communicate via IPv4 broadcast,
# the first of which forks a child process for each connected client.
@ -43,6 +43,7 @@ while [ "$1" ]; do
X-q) QUIET=1; OPTS="-d0" ;;
X-d*|X-l?*) OPTS="$OPTS $1" ;;
X-b|X-S|X-t|X-T|X-l) OPT=$1; shift; OPTS="$OPTS $OPT $1" ;;
X--experimental) ;;
X-) break ;;
X-*) echo "$0: Unknown option \"$1\"" >&2
usage >&2

31
socat.c
View file

@ -282,6 +282,8 @@ int main(int argc, const char *argv[]) {
socat_opts.total_timeout.tv_usec =
(rto-socat_opts.total_timeout.tv_sec) * 1000000;
}
xioparms.total_timeout.tv_sec = socat_opts.total_timeout.tv_sec;
xioparms.total_timeout.tv_usec = socat_opts.total_timeout.tv_usec;
break;
case 'u': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
socat_opts.lefttoright = true; break;
@ -783,7 +785,7 @@ int socat(const char *address1, const char *address2) {
int i;
for (i = 0; i < NUMUNKNOWN; ++i) {
if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown[i]) {
/* child has alread died... but it might have put regular data into
/* Child has already died... but it might have put regular data into
the communication channel, so continue */
Info2("child "F_pid" has already died with status %d",
XIO_RDSTREAM(sock1)->para.exec.pid, statunknown[i]);
@ -826,7 +828,7 @@ int socat(const char *address1, const char *address2) {
int i;
for (i = 0; i < NUMUNKNOWN; ++i) {
if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown[i]) {
/* child has alread died... but it might have put regular data into
/* Child has already died... but it might have put regular data into
the communication channel, so continue */
Info2("child "F_pid" has already died with status %d",
XIO_RDSTREAM(sock2)->para.exec.pid, statunknown[i]);
@ -863,11 +865,12 @@ int childleftdata(xiofile_t *xfd) {
XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
struct timeval timeout = { 0, 0 };
if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
in.fd = XIO_GETRDFD(xfd);
in.events = POLLIN/*|POLLRDBAND*/;
in.revents = 0;
}
if (XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)
return 0;
in.fd = XIO_GETRDFD(xfd);
in.events = POLLIN/*|POLLRDBAND*/;
in.revents = 0;
do {
int _errno;
retval = xiopoll(&in, 1, &timeout);
@ -875,7 +878,7 @@ int childleftdata(xiofile_t *xfd) {
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
Error5("xiopoll({%d,0%o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
strerror(errno));
return -1;
@ -1013,7 +1016,7 @@ int _socat(void) {
/* for ignoreeof */
if (polling) {
if (!wasaction) {
if (socat_opts.total_timeout.tv_usec <= 1000000) {
if (socat_opts.total_timeout.tv_usec < 1000000) {
if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
total_timeout.tv_usec += 1000000;
total_timeout.tv_sec -= 1;
@ -1131,7 +1134,7 @@ int _socat(void) {
*/
if (retval < 0) {
Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
Error11("xiopoll({%d,0%o}{%d,0%o}{%d,0%o}{%d,0%o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
fds[0].fd, fds[0].events, fds[1].fd, fds[1].events,
fds[2].fd, fds[2].events, fds[3].fd, fds[3].events,
timeout.tv_sec, timeout.tv_usec, strerror(errno));
@ -1336,7 +1339,6 @@ int _socat(void) {
should be at least MAXTIMESTAMPLEN bytes long.
returns 0 on success or -1 if an error occurred */
int gettimestamp(char *timestamp) {
size_t bytes;
#if HAVE_CLOCK_GETTIME
struct timespec now;
#elif HAVE_PROTOTYPE_LIB_gettimeofday
@ -1364,17 +1366,16 @@ int gettimestamp(char *timestamp) {
}
#endif
#if HAVE_STRFTIME
bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
#if HAVE_CLOCK_GETTIME
bytes += sprintf(timestamp+19, "."F_tv_nsec" ", now.tv_nsec/1000);
sprintf(timestamp+19, "."F_tv_nsec" ", now.tv_nsec/1000);
#elif HAVE_PROTOTYPE_LIB_gettimeofday
bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
#else
strncpy(&timestamp[bytes++], " ", 2);
#endif
#else
strcpy(timestamp, ctime(&nowt));
bytes = strlen(timestamp);
#endif
return 0;
}

View file

@ -1,6 +1,6 @@
%define majorver 1.8
%define minorver 0.2
%define minorver 0.3
Summary: socat - multipurpose relay
Name: socat

View file

@ -37,7 +37,7 @@ esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
echo "$0: cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
@ -58,7 +58,7 @@ else
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
echo "$0 invalid socks version requested" >&2
exit
fi
@ -69,7 +69,7 @@ else
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
echo "$0: invalid socks operation requested" >&2
exit
fi
@ -82,7 +82,7 @@ a=$(dd bs=1 count=6 2>/dev/null)
if [ "$a" != "$($ECHO "}m\0\0\0\01")" ]; then
sleep 1
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address or port requested" >&2
echo "$0: wrong socks address or port requested" >&2
exit
fi
@ -93,7 +93,7 @@ else
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested" >&2
echo "$0: wrong socks user requested" >&2
exit
fi
@ -104,7 +104,7 @@ else
fi
if [ "$h" != "localhost" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks address requested" >&2
echo "$0: wrong socks address requested" >&2
exit
fi

View file

@ -9,6 +9,7 @@
# it is required for test.sh
# for TCP, use this script as:
# socat tcp-l:1080,reuseaddr,crlf system:"socks4echo.sh"
# Then connect with a socks4 request for 32.98.76.54:32109 and user nobody
# older bash and ksh do not have -n option to read command; we try dd then
#if echo a |read -n 1 null >/dev/null 2>&1; then
@ -36,7 +37,7 @@ esac
if [ $(echo "x\c") = "x" ]; then E=""
elif [ $(echo -e "x\c") = "x" ]; then E="-e"
else
echo "cannot suppress trailing newline on echo" >&2
echo "$0: cannot suppress trailing newline on echo" >&2
exit 1
fi
ECHO="echo $E"
@ -57,7 +58,7 @@ else
fi
if [ "$vn" != $($ECHO "\04") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks version requested" >&2
echo "$0: invalid socks version requested" >&2
exit
fi
@ -68,7 +69,7 @@ else
fi
if [ "$cd" != $($ECHO "\01") ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "invalid socks operation requested" >&2
echo "$0: invalid socks operation requested" >&2
exit
fi
@ -91,7 +92,7 @@ else
fi
if [ "$u" != "nobody" ]; then
$ECHO "$SOCKSREPLY_FAILED"
echo "wrong socks user requested (expected \"nobody\")" >&2
echo "$0: wrong socks user requested (expected \"nobody\")" >&2
exit
fi

67
socks5server-echo.sh Executable file
View file

@ -0,0 +1,67 @@
#! /usr/bin/env bash
# Source: socks5connect-echo.sh
# Copyright Gerhard Rieger and contributors (see file CHANGES)
# Published under the GNU General Public License V.2, see file COPYING
# Performs primitive simulation of a socks5 server with echo function via stdio.
# Accepts and answers SOCKS5 CONNECT request without authentication to
# 8.8.8.8:80, however is does not connect there but just echoes data.
# It is required for test.sh
# For TCP, use this script as:
# socat TCP-L:1080,reuseaddr EXEC:"socks5connect-echo.sh"
#set -vx
if [ "$SOCAT" ]; then
:
elif type socat >/dev/null 2>&1; then
SOCAT=socat
else
SOCAT=./socat
fi
case `uname` in
HP-UX|OSF1)
CAT="$SOCAT -u STDIN STDOUT"
;;
*)
CAT=cat
;;
esac
A="7f000001"
P="0050"
# Read and parse SOCKS5 greeting
read _ v b c _ <<<"$($SOCAT -u -,readbytes=3 - |od -t x1)"
#echo "$v $b $c" >&2
if [ "$v" != 05 ]; then echo "$0: Packet1: expected version x05, got \"$v\"" >&2; exit 1; fi
if [ "$b" != 01 ]; then echo "$0: Packet1: expected 01 auth methods, got \"$b\"" >&2; exit 1; fi
if [ "$c" != 00 ]; then echo "$0: Packet1: expected auth method 00, got \"$c\"" >&2; exit 1; fi
# Send answer
echo -en "\x05\x00"
# Read and parse SOCKS5 connect request
read _ v b c d a1 a2 a3 a4 p1 p2 _ <<<"$($SOCAT -u -,readbytes=10 - |od -t x1)"
#echo "$v $b $c $d $a1 $a2 $a3 $a4 $p1 $p2" >&2
a="$a1$a2$a3$a4"
p="$p1$p2"
if [ "$v" != 05 ]; then echo "$0: Packet2: expected version x05, got \"$v\"" >&2; exit 1; fi
if [ "$b" != 01 ] && [ "$b" != 02 ]; then echo "$0: Packet2: expected connect request 01 or bind request 02, got \"$b\"" >&2; exit 1; fi
if [ "$c" != 00 ]; then echo "$0: Packet2: expected reserved 00, got \"$c\"" >&2; exit 1; fi
if [ "$d" != 01 ]; then echo "$0: Packet2: expected address type 01, got \"$d\"" >&2; exit 1; fi
if [ "$a" != "$A" ]; then echo "$0: Packet2: expected address $A, got \"$a\"" >&2; exit 1; fi
if [ "$p" != "$P" ]; then echo "$0: Packet2: expected port $P, got \"$p\"" >&2; exit 1; fi
if [ "$z" != "" ]; then echo "$0: Packet2: trailing data \"$z\"" >&2; exit 1; fi
# Send answer
echo -en "\x05\x00\x00\x01\x10\x00\x1f\x64\x1f\x64"
# Bind/listen/passive mode
if [ "$b" == 02 ]; then
sleep 1 # pretend to be waiting for connection
echo -en "\x05\x00\x00\x01\x10\xff\x1f\x64\x23\x28"
fi
# perform echo function
$CAT

View file

@ -368,6 +368,7 @@ int sycSSL_connect(SSL *ssl) {
int result;
Debug1("SSL_connect(%p)", ssl);
result = SSL_connect(ssl);
if (!diag_in_handler) diag_flush();
Debug1("SSL_connect() -> %d", result);
return result;
}

19
sycls.c
View file

@ -1421,11 +1421,11 @@ unsigned int Sleep(unsigned int seconds) {
#if HAVE_NANOSLEEP
unsigned int Nanosleep(const struct timespec *req, struct timespec *rem) {
int retval, _errno;
Debug3("nanosleep({"F_time",%ld},%p)", req->tv_sec, req->tv_nsec, rem);
Debug3("nanosleep({"F_time".%09ld}, %p)", req->tv_sec, req->tv_nsec, rem);
retval = nanosleep(req, rem);
_errno = errno;
if (rem) {
Debug3("nanosleep(,{"F_time",%ld}) -> %d",
Debug3("nanosleep(,{"F_time".%09ld}) -> %d",
rem->tv_sec, rem->tv_nsec, retval);
} else {
Debug1("nanosleep() -> %d", retval);
@ -1513,6 +1513,9 @@ void *Malloc(size_t size) {
Error1("malloc("F_Zd"): out of memory", size);
return NULL;
}
#if WITH_DEVTESTS
memset(result, 0x55, size);
#endif /* WITH_DEVTESTS */
return result;
}
@ -1540,6 +1543,18 @@ void *Realloc(void *ptr, size_t size) {
return result;
}
/* Like Realloc(), but gets info about old size for overwrite test */
void *Realloc3(void *ptr, size_t size, size_t oldsize) {
void *result = Realloc(ptr, size);
if (result == NULL)
return result;
#if WITH_DEVTESTS
if (size > oldsize)
memset(result+oldsize, 0x55, size-oldsize);
#endif /* WITH_DEVTESTS */
return result;
}
#if _WITH_TERMIOS
int Tcgetattr(int fd, struct termios *termios_p) {
int i, result, _errno;

View file

@ -148,6 +148,7 @@ struct hostent *Getipnodebyname(const char *name, int af, int flags,
void *Malloc(size_t size);
void *Calloc(size_t nmemb, size_t size);
void *Realloc(void *ptr, size_t size);
void *Realloc3(void *ptr, size_t size, size_t oldsize);
int Tcgetattr(int fd, struct termios *termios_p);
int Tcsetattr(int fd, int optional_actions, struct termios *termios_p);
char *Ttyname(int fd);
@ -257,6 +258,7 @@ void Add_history(const char *string);
#define Malloc(s) malloc(s)
#define Calloc(n,s) calloc(n,s)
#define Realloc(p,s) realloc(p,s)
#define Realloc3(p,s,o) realloc(p,s)
#define Tcgetattr(f,t) tcgetattr(f,t)
#define Tcsetattr(f,o,t) tcsetattr(f,o,t)
#define Ttyname(f) ttyname(f)

View file

@ -150,6 +150,9 @@
#if HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif
#if HAVE_NETINET_DCCP_H
#include <netinet/dccp.h>
#endif
#if HAVE_LINUX_DCCP_H
#include <linux/dccp.h>
#endif
@ -182,7 +185,7 @@
#if WITH_NAMESPACES && HAVE_SCHED_H
#include <sched.h>
#endif
#if WITH_POSIXMQ
#if WITH_POSIXMQ && HAVE_MQUEUE_H
#include <mqueue.h> /* POSIX MQ */
#endif
#if WITH_READLINE

View file

@ -27,9 +27,22 @@ const int one = 1;
Returns <0 on unhandled error, errno valid
Will only return <0 or bytes
*/
ssize_t writefull(int fd, const void *buff, size_t bytes) {
/* Assuming your pipe size is 65536 - find out with:
filan -i 1 |grep F_GETPIPE_SZ |sed 's|.*\(F_GETPIPE_SZ=[1-9][0-9]*\).*|\1|'
Then we can test partial write with something like:
socat -d4 -lu -b 262144 -u /dev/zero,readbytes=262144 -,o-nonblock |{ sleep 3; wc -c; }
*/
ssize_t writefull(
int fd,
const void *buff,
size_t bytes,
const struct timeval *tmo0) {
size_t writt = 0;
ssize_t chk;
struct pollfd pfd;
struct timeval tmo = { 0 };
int rc;
while (1) {
chk = Write(fd, (const char *)buff + writt, bytes - writt);
if (chk < 0) {
@ -40,15 +53,34 @@ ssize_t writefull(int fd, const void *buff, size_t bytes) {
case EWOULDBLOCK:
#endif
Warn4("write(%d, %p, "F_Zu"): %s", fd, (const char *)buff+writt, bytes-writt, strerror(errno));
Sleep(1); continue;
default: return -1;
pfd.fd = fd;
pfd.events = POLLOUT;
pfd.revents = 0;
if (tmo0 != NULL) {
tmo.tv_sec = tmo0->tv_sec;
tmo.tv_usec = tmo0->tv_usec;
}
rc = xiopoll(&pfd, 1, (tmo.tv_sec!=0 || tmo.tv_usec!=0) ? &tmo : NULL);
if (rc == 0) {
Notice("inactivity timeout triggered");
errno = ETIMEDOUT;
return -1;
}
continue;
default:
return -1;
}
} else if (chk == bytes) {
/* First attempt, complete write */
return chk;
} else if (writt+chk < bytes) {
Warn4("write(%d, %p, "F_Zu"): only wrote "F_Zu" bytes, trying to continue (rev.direction is blocked)",
Warn4("write(%d, %p, "F_Zu"): only wrote "F_Zu" bytes, trying to continue (meanwhile, other direction is blocked)",
fd, (const char *)buff+writt, bytes-writt, chk);
writt += chk;
} else {
writt = bytes;
} else if (writt == 0) {
/* First attempt, write complete - no extra message */
return chk;
} else { /* write completed */
break;
}
}
@ -548,7 +580,7 @@ int getusergroups(const char *user, gid_t *list, int *ngroups) {
/* we prefer getgrouplist because it may be much faster with many groups, but it is not standard */
gid_t grp, twogrps[2];
int two = 2;
/* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an abitrary supplementary group id that we then pass in a second call to getgrouplist. */
/* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an arbitrary supplementary group id that we then pass in a second call to getgrouplist. */
grp = 0;
Getgrouplist(user, grp, twogrps, &two);
if (two == 1) {
@ -677,7 +709,7 @@ int xiopoll(struct pollfd fds[], unsigned long nfds, struct timeval *timeout) {
}
#if WITH_TCP || WITH_UDP
#if WITH_TCP || WITH_UDP || WITH_SCTP || WITH_DCCP || WITH_UDPLITE
/* returns port in network byte order;
ipproto==IPPROTO_UDP resolves as UDP service, every other value resolves as
TCP */
@ -702,10 +734,10 @@ int parseport(const char *portname, int ipproto) {
return se->s_port;
}
#endif /* WITH_TCP || WITH_UDP */
#endif /* WITH_TCP || WITH_UDP || WITH_SCTP || WITH_DCCP || WITH_UDPLITE */
#if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
#if WITH_IP4 || WITH_IP6 || _WITH_INTERFACE
/* check the systems interfaces for ifname and return its index
or -1 if no interface with this name was found
The system calls require an arbitrary socket; the calling program may
@ -729,8 +761,8 @@ int ifindexbyname(const char *ifname, int anysock) {
}
if (anysock >= 0) {
s = anysock;
} else if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
} else if ((s = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
return -1;
}
@ -756,10 +788,10 @@ int ifindexbyname(const char *ifname, int anysock) {
return -1;
#endif /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
}
#endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
#endif /* WITH_IP4 || WITH_IP6 || _WITH_INTERFACE */
#if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
#if WITH_IP4 || WITH_IP6 || _WITH_INTERFACE
/* like ifindexbyname(), but also allows the index number as input - in this
case it does not lookup the index.
writes the resulting index to *ifindex and returns 0,
@ -783,7 +815,7 @@ int ifindex(const char *ifname, unsigned int *ifindex, int anysock) {
*ifindex = val;
return 0;
}
#endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
#endif /* WITH_IP4 || WITH_IP6 || _WITH_INTERFACE */
int _xiosetenv(const char *envname, const char *value, int overwrite, const char *sep) {

View file

@ -47,7 +47,7 @@ struct xiorange {
extern const int one;
#endif
extern ssize_t writefull(int fd, const void *buff, size_t bytes);
extern ssize_t writefull(int fd, const void *buff, size_t bytes, const struct timeval *tmo0);
#if _WITH_SOCKET
extern socklen_t socket_init(int af, union sockaddr_union *sa);

6283
test.sh

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@
#include "xio-ascii.h"
/* for each 6 bit pattern we have an ASCII character in the arry */
/* For each 6 bit pattern we have an ASCII character in the array */
const static int base64chars[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',

View file

@ -84,7 +84,8 @@ static int xioopen_exec(
while (*strp == ' ') {
while (*++strp == ' ') ;
if ((pargc & 0x07) == 0) {
pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
/*0 pargv = Realloc(pargv, (pargc+8)*sizeof(char *)); */
pargv = Realloc3(pargv, (pargc+8)*sizeof(char *), pargc*sizeof(char *));
if (pargv == NULL) return STAT_RETRYLATER;
}
pargv[pargc++] = tokp;

View file

@ -31,7 +31,7 @@ const struct optdesc opt_o_noinherit = { "o-noinherit", "noinherit", OPT_O_NOINH
const struct optdesc opt_o_noatime = { "o-noatime", "noatime", OPT_O_NOATIME, GROUP_OPEN|GROUP_FD, PH_FD, TYPE_BOOL, OFUNC_FCNTL, F_SETFL, O_NOATIME };
#endif
/****** for ALL addresses - with fcntl(F_SETFD) ******/
const struct optdesc opt_cloexec = { "cloexec", NULL, OPT_CLOEXEC, GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFD, FD_CLOEXEC };
const struct optdesc opt_cloexec = { "cloexec", NULL, OPT_O_CLOEXEC, GROUP_FD, PH_LATE, TYPE_BOOL, OFUNC_FCNTL, F_SETFD, FD_CLOEXEC };
/****** ftruncate() ******/
/* this record is good for ftruncate() or ftruncate64() if available */
#if HAVE_FTRUNCATE64

View file

@ -20,7 +20,7 @@ static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xiof
const struct optdesc opt_o_rdonly = { "o-rdonly", "rdonly", OPT_O_RDONLY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_RDONLY, O_ACCMODE };
const struct optdesc opt_o_wronly = { "o-wronly", "wronly", OPT_O_WRONLY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_WRONLY, O_ACCMODE };
const struct optdesc opt_o_rdwr = { "o-rdwr", "rdwr", OPT_O_RDWR, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG_PATTERN, O_RDWR, O_ACCMODE };
const struct optdesc opt_o_create = { "o-create", "creat", OPT_O_CREATE, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_CREAT };
const struct optdesc opt_o_creat = { "o-creat", "creat", OPT_O_CREAT, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_CREAT };
const struct optdesc opt_o_excl = { "o-excl", "excl", OPT_O_EXCL, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_EXCL };
const struct optdesc opt_o_noctty = { "o-noctty", "noctty", OPT_O_NOCTTY, GROUP_OPEN, PH_OPEN, TYPE_BOOL, OFUNC_FLAG, O_NOCTTY };
#ifdef O_SYNC

View file

@ -8,7 +8,7 @@
extern const struct optdesc opt_o_rdonly;
extern const struct optdesc opt_o_wronly;
extern const struct optdesc opt_o_rdwr;
extern const struct optdesc opt_o_create;
extern const struct optdesc opt_o_creat;
extern const struct optdesc opt_o_excl;
extern const struct optdesc opt_o_noctty;
extern const struct optdesc opt_o_sync;

View file

@ -87,7 +87,7 @@ const struct optdesc opt_fs_noatime = { "fs-noatime", "noatime",
#endif /* FS_NOATIME_FL */
/* FS_DIRTY_FL ??? */
/* FS_COMPRBLK_FL one ore more compress clusters */
/* FS_COMPRBLK_FL one or more compress clusters */
/* FS_NOCOMPR_FL access raw compressed data */
/* FS_ECOMPR_FL compression error */
/* FS_BTREE_FL btree format dir */

View file

@ -71,7 +71,7 @@ int _xioopen_interface(const char *ifname,
if (ifindex(ifname, &ifidx, -1) < 0) {
Error1("unknown interface \"%s\"", ifname);
ifidx = 0; /* desparate attempt to continue */
ifidx = 0; /* desperate attempt to continue */
}
if (sfd->howtoend == END_UNSPEC)
@ -276,7 +276,7 @@ int _xiointerface_apply_iff(
#if HAVE_STRUCT_CMSGHDR && HAVE_STRUCT_TPACKET_AUXDATA
/* Converts the ancillary message in *cmsg into a form useable for further
/* Converts the ancillary message in *cmsg into a form usable for further
processing. Knows the specifics of common message types.
On PACKET_AUXDATA it stored the ancillary data in the XFD.
For other types:

122
xio-ip.c
View file

@ -68,7 +68,7 @@ const struct optdesc opt_ip_multicast_if ={"ip-multicast-if", "multicast-if",
#ifdef IP_PKTOPTIONS
const struct optdesc opt_ip_pktoptions = { "ip-pktoptions", "pktopts", OPT_IP_PKTOPTIONS, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_PKTOPTIONS };
#endif
#ifdef IP_ADD_MEMBERSHIP
#if defined(HAVE_STRUCT_IP_MREQ) || defined(HAVE_STRUCT_IP_MREQN)
const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SPEC, SOL_IP, IP_ADD_MEMBERSHIP };
#endif
#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
@ -161,6 +161,79 @@ int Res_init(void) {
#endif /* HAVE_RESOLV_H */
/* Looks for a bind option and, if found, passes it to resolver;
for IP (v4, v6) and raw (PF_UNSPEC);
returns list of addrinfo results;
returns STAT_OK if option exists and could be resolved,
STAT_NORETRY if option exists but had error,
or STAT_NOACTION if it does not exist */
int retropt_bind_ip(
struct opt *opts,
int af,
int socktype,
int ipproto,
struct addrinfo ***bindlist,
int feats, /* TCP etc: 1..address allowed,
3..address and port allowed
*/
const int ai_flags[2])
{
const char portsep[] = ":";
const char *ends[] = { portsep, NULL };
const char *nests[] = { "[", "]", NULL };
bool portallowed;
char *bindname, *bindp;
char hostname[512], *hostp = hostname, *portp = NULL;
size_t hostlen = sizeof(hostname)-1;
int parsres;
int ai_flags2[2];
int result;
if (retropt_string(opts, OPT_BIND, &bindname) < 0) {
return STAT_NOACTION;
}
bindp = bindname;
portallowed = (feats>=2);
parsres =
nestlex((const char **)&bindp, &hostp, &hostlen, ends, NULL, NULL, nests,
true, false, false);
if (parsres < 0) {
Error1("option too long: \"%s\"", bindp);
return STAT_NORETRY;
} else if (parsres > 0) {
Error1("syntax error in \"%s\"", bindp);
return STAT_NORETRY;
}
*hostp++ = '\0';
if (!strncmp(bindp, portsep, strlen(portsep))) {
if (!portallowed) {
Error("port specification not allowed in this bind option");
return STAT_NORETRY;
} else {
portp = bindp + strlen(portsep);
}
}
/* Set AI_PASSIVE, except when it is explicitely disabled */
ai_flags2[0] = ai_flags[0];
ai_flags2[1] = ai_flags[1];
if (!(ai_flags2[1] & AI_PASSIVE))
ai_flags2[0] |= AI_PASSIVE;
if ((result =
xiogetaddrinfo(hostname[0]!='\0'?hostname:NULL, portp,
af, socktype, ipproto,
bindlist, ai_flags2))
!= STAT_OK) {
Error2("error resolving bind option \"%s\" with af=%d", bindname, af);
return STAT_NORETRY;
}
return STAT_OK;
}
#if WITH_DEVTESTS
/* Have a couple of hard coded sockaddr records, to be copied and adapted when
@ -386,6 +459,7 @@ int _xiogetaddrinfo(const char *node, const char *service,
#else /* HAVE_PROTOTYPE_LIB_getipnodebyname || nothing */
struct hostent *host;
#endif
bool restore_proto = false;
int error_num;
Debug8("_xiogetaddrinfo(node=\"%s\", service=\"%s\", family=%d, socktype=%d, protoco=%d, ai_flags={0x%04x/0x%04x} }, res=%p",
@ -512,15 +586,16 @@ int _xiogetaddrinfo(const char *node, const char *service,
return EAI_SERVICE;
}
/* Probably unsupported protocol (e.g. UDP-Lite), fallback to 0 */
restore_proto = true;
hints.ai_protocol = 0;
continue;
}
if ((error_num = Getaddrinfo(node, service, &hints, res)) != 0) {
Warn7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %d",
Warn7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
node?node:"NULL", service?service:"NULL",
hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol,
error_num);
gai_strerror(error_num));
if (numnode)
free(numnode);
@ -540,6 +615,14 @@ int _xiogetaddrinfo(const char *node, const char *service,
#endif /* WITH_MSGLEVEL <= E_DEBUG */
}
if (restore_proto) {
struct addrinfo *record = *res;
while (record) {
record->ai_protocol = protocol;
record = record->ai_next;
}
}
#elif HAVE_PROTOTYPE_LIB_getipnodebyname /* !HAVE_GETADDRINFO */
if (node != NULL) {
@ -592,7 +675,7 @@ int _xiogetaddrinfo(const char *node, const char *service,
freehostent(host);
}
#elsif 0 /* !HAVE_PROTOTYPE_LIB_getipnodebyname */
#elif 0 /* !HAVE_PROTOTYPE_LIB_getipnodebyname */
if (node != NULL) {
/* this is not a typical IP6 resolver function - but Linux
@ -760,6 +843,9 @@ void xiofreeaddrinfo(struct addrinfo **ai_sorted) {
int ain;
struct addrinfo *res;
if (ai_sorted == NULL)
return;
/* Find the original *res from getaddrinfo past NULL */
ain = 0;
while (ai_sorted[ain] != NULL)
@ -843,7 +929,7 @@ int xioresolve(const char *node, const char *service,
}
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* Converts the ancillary message in *cmsg into a form useable for further
/* Converts the ancillary message in *cmsg into a form usable for further
processing. knows the specifics of common message types.
These are valid for IPv4 and IPv6
Returns the number of resulting syntax elements in *num
@ -902,16 +988,20 @@ int xiolog_ancillary_ip(
'\0',
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr),
scratch3, sizeof(scratch3)));
#if HAVE_PKTINFO_IPI_SPEC_DST
Notice3("Ancillary message: interface \"%s\", locaddr=%s, dstaddr=%s",
xiogetifname(pktinfo->ipi_ifindex, scratch1, -1),
#if HAVE_PKTINFO_IPI_SPEC_DST
inet4addr_info(ntohl(pktinfo->ipi_spec_dst.s_addr),
scratch2, sizeof(scratch2)),
#else
"",
#endif
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr),
scratch3, sizeof(scratch3)));
#else
Notice3("Ancillary message: interface \"%s\", locaddr=%s, dstaddr=%s",
xiogetifname(pktinfo->ipi_ifindex, scratch1, -1),
"",
inet4addr_info(ntohl(pktinfo->ipi_addr.s_addr),
scratch3, sizeof(scratch3)));
#endif
}
return STAT_OK;
#endif /* defined(IP_PKTINFO) && HAVE_STRUCT_IN_PKTINFO */
@ -1001,7 +1091,7 @@ int xiolog_ancillary_ip(
cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgctr = -1;
/*!!!*/
break;
#if XIO_ANCILLARY_TYPE_SOLARIS
#if defined(IP_RECVTOS) && XIO_ANCILLARY_TYPE_SOLARIS
case IP_RECVTOS:
#else
case IP_TOS:
@ -1112,13 +1202,14 @@ int xiotype_ip_add_membership(
opt->value2.u_string/*param2*/,
opt->value3.u_string/*ifindex*/);
} else {
/*0 opt->value3.u_string = NULL; / * is NULL from init */
opt->value3.u_string = NULL; /* is not NULL from init! */
Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
ent->desc->defname,
opt->value.u_string/*multiaddr*/,
opt->value2.u_string/*param2*/);
}
#else /* !HAVE_STRUCT_IP_MREQN */
opt->value3.u_string = NULL;
Info3("setting option \"%s\" to {\"%s\",\"%s\"}",
ent->desc->defname,
opt->value.u_string/*multiaddr*/,
@ -1128,6 +1219,9 @@ int xiotype_ip_add_membership(
}
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
#if _WITH_IP4
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
int xioapply_ip_add_membership(
struct single *sfd,
@ -1352,7 +1446,7 @@ int xioapply_ip_add_source_membership(struct single *sfd, struct opt *opt) {
}
ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr;
/* second parameter is interface address */
rc = xioresolve(opt->value.u_string/*ifaddr*/, NULL,
rc = xioresolve(opt->value2.u_string/*ifaddr*/, NULL,
sfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr2, &socklen2, sfd->para.socket.ip.ai_flags);
@ -1361,7 +1455,7 @@ int xioapply_ip_add_source_membership(struct single *sfd, struct opt *opt) {
}
ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr;
/* third parameter is source address */
rc = xioresolve(opt->value.u_string/*srcaddr*/, NULL,
rc = xioresolve(opt->value3.u_string/*srcaddr*/, NULL,
sfd->para.socket.la.soa.sa_family,
SOCK_DGRAM, IPPROTO_IP,
&sockaddr3, &socklen3, sfd->para.socket.ip.ai_flags);
@ -1386,6 +1480,8 @@ int xioapply_ip_add_source_membership(struct single *sfd, struct opt *opt) {
#endif /* HAVE_STRUCT_IP_MREQ_SOURCE */
#endif /* _WITH_IP4 */
#if WITH_RESOLVE
#if HAVE_RESOLV_H

View file

@ -49,6 +49,7 @@ extern const struct optdesc opt_res_nsaddr;
extern int xioinit_ip(int *pf, char ipv);
extern int retropt_bind_ip(struct opt *opts, int af, int socktype, int ipproto, struct addrinfo ***bindlist, int feats, const int ai_flags[2]);
extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo ***ai_sorted, const int ai_flags[2]);
extern void xiofreeaddrinfo(struct addrinfo **ai_sorted);
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);

View file

@ -23,7 +23,7 @@ static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen);
#ifdef IPV6_V6ONLY
const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY };
#endif
#ifdef IPV6_JOIN_GROUP
#if defined(HAVE_STRUCT_IP_MREQ) || defined(HAVE_STRUCT_IP_MREQN)
const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SPEC, SOL_IPV6, IPV6_JOIN_GROUP };
#endif
#ifdef MCAST_JOIN_SOURCE_GROUP
@ -249,7 +249,7 @@ int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) {
#if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
/* provides info about the ancillary message:
converts the ancillary message in *cmsg into a form useable for further
converts the ancillary message in *cmsg into a form usable for further
processing. knows the specifics of common message types.
returns the number of resulting syntax elements in *num
returns a sequence of \0 terminated type strings in *typbuff

View file

@ -6,7 +6,7 @@
#include "xiosysincludes.h"
#if WITH_TCP || WITH_UDP
#if WITH_TCP || WITH_UDP || WITH_SCTP || WITH_DCCP || WITH_UDPLITE
#include "xioopen.h"
#include "xio-socket.h"
@ -19,7 +19,8 @@ const struct optdesc opt_sourceport = { "sourceport", "sp", OPT_SOURCEPORT
/*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
const struct optdesc opt_lowport = { "lowport", NULL, OPT_LOWPORT, GROUP_IPAPP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
#if WITH_IP4
#if _WITH_IP4 || _WITH_IP6
/* we expect the form "host:port" */
int xioopen_ipapp_connect(
int argc,
@ -31,20 +32,18 @@ int xioopen_ipapp_connect(
{
struct single *sfd = &xxfd->stream;
struct opt *opts0 = NULL;
const char *hostname = argv[1], *portname = argv[2];
int pf = addrdesc->arg3;
int socktype = addrdesc->arg1;
int ipproto = addrdesc->arg2;
int pf = addrdesc->arg3;
const char *hostname = argv[1], *portname = argv[2];
bool dofork = false;
int maxchildren = 0;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo **themarr, *themp;
char infobuff[256];
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
bool needbind = false;
bool lowport = false;
int level;
int i;
int level = E_ERROR;
int result;
if (argc != 3) {
@ -52,97 +51,84 @@ int xioopen_ipapp_connect(
return STAT_NORETRY;
}
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
/* Apply and retrieve some options */
result = _xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
if (applyopts_single(sfd, opts, PH_INIT) < 0)
return -1;
applyopts(sfd, -1, opts, PH_INIT);
opts0 = opts; /* save remaining options for each loop */
opts = NULL;
retropt_bool(opts, OPT_FORK, &dofork);
if (dofork) {
if (!(xioflags & XIO_MAYFORK)) {
Error("option fork not allowed here");
return STAT_NORETRY;
}
sfd->flags |= XIO_DOESFORK;
}
Notice2("opening connection to %s:%s", hostname, portname);
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
if (! dofork && maxchildren) {
Error("option max-children not allowed without option fork");
return STAT_NORETRY;
}
if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, us, &uslen, &needbind, &lowport,
socktype) != STAT_OK) {
return STAT_NORETRY;
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
if (xioparms.logopt == 'm') {
Info("starting connect loop, switching to syslog");
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
} else {
Info("starting connect loop");
}
do { /* loop over retries, and forks */
/* Loop over themarr (which had been "ai_sorted") */
result = STAT_RETRYLATER;
i = 0;
themp = themarr[i++];
while (themp != NULL) {
Notice1("opening connection to %s",
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
infobuff, sizeof(infobuff)));
do { /* loop over retries and/or forks */
int _errno;
#if WITH_RETRY
if (sfd->forever || sfd->retry) {
level = E_INFO;
} else if (themarr[i] != NULL) {
level = E_WARN;
} else
if (sfd->forever || sfd->retry) {
level = E_NOTICE;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
level = E_WARN;
result =
_xioopen_connect(sfd,
needbind?us:NULL, uslen,
themp->ai_addr, themp->ai_addrlen,
opts, pf?pf:themp->ai_family, socktype, ipproto,
lowport, level);
if (result == STAT_OK)
break;
themp = themarr[i++];
if (themp == NULL) {
result = STAT_RETRYLATER;
}
}
opts = copyopts(opts0, GROUP_ALL);
result =
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
pf, socktype, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, &bindarr, &bindport, &needbind, &lowport);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry) {
--sfd->retry;
if (result == STAT_RETRYLATER) {
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
}
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
default:
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
free(opts0);free(opts);
freeopts(opts);
freeopts(opts0);
return result;
}
result =
_xioopen_ipapp_connect(sfd, hostname, opts, themarr,
needbind, bindarr, bindport, lowport, level);
_errno = errno;
if (bindarr != NULL)
xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
Error4("%s:%s:%s: %s", argv[0], argv[1], argv[2],
_errno?strerror(_errno):"(See above)");
freeopts(opts);
freeopts(opts0);
return result;
}
@ -155,16 +141,18 @@ int xioopen_ipapp_connect(
so Notice is too weak */
}
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
if (sfd->forever || --sfd->retry) {
Nanosleep(&sfd->intervall, NULL); continue;
if (sfd->forever || sfd->retry--) {
Nanosleep(&sfd->intervall, NULL);
continue;
}
xiofreeaddrinfo(themarr);
free(opts0);
freeopts(opts);
freeopts(opts0);
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
sfd->forever = false; sfd->retry = 0;
sfd->forever = false;
sfd->retry = 0;
break;
}
@ -176,107 +164,269 @@ int xioopen_ipapp_connect(
Info1("all %d allowed children are active, waiting", maxchildren);
Nanosleep(&sfd->intervall, NULL);
}
dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
freeopts(opts);
continue; /* with next socket() bind() connect() */
} else
#endif /* WITH_RETRY */
{
break;
}
} while (true);
} while (true); /* end of loop over retries and/or forks */
/* only "active" process breaks (master without fork, or child) */
xiofreeaddrinfo(themarr);
if ((result = _xio_openlate(sfd, opts)) < 0) {
free(opts0);free(opts);
return result;
}
free(opts0); free(opts);
return 0;
Notice2("successfully connected to %s:%s", hostname, portname);
result = _xio_openlate(sfd, opts);
freeopts(opts);
freeopts(opts0);
return result;
}
/* returns STAT_OK on success or some other value on failure
/* This function performs static initializations for addresses like TCP-CONNECT
before start of the outer loop:
it retrieves some options
returns STAT_OK on success or some other value on failure;
applies and consumes the following options:
PH_INIT, OPT_FORK, OPT_MAX_CHILDREN, OPT_PROTOCOL_FAMILY, OPT_SO_TYPE,
OPT_SO_PROTOTYPE
*/
int _xioopen_ipapp_init(
struct single *sfd,
int xioflags,
struct opt *opts,
bool *dofork,
int *maxchildren,
int *pf,
int *socktype,
int *ipproto)
{
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
if (applyopts_single(sfd, opts, PH_INIT) < 0)
return -1;
if (applyopts(sfd, -1, opts, PH_INIT) < 0)
return -1;
retropt_bool(opts, OPT_FORK, dofork);
if (dofork) {
if (!(xioflags & XIO_MAYFORK)) {
Error1("%s: option fork not allowed here", sfd->addr->defname);
return STAT_NORETRY;
}
sfd->flags |= XIO_DOESFORK;
}
retropt_int(opts, OPT_MAX_CHILDREN, maxchildren);
if (! dofork && maxchildren) {
Error1("%s: option max-children not allowed without option fork", sfd->addr->defname);
return STAT_NORETRY;
}
retropt_socket_pf(opts, pf);
retropt_int(opts, OPT_SO_TYPE, socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, ipproto);
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
if (xioparms.logopt == 'm') {
Info("starting connect loop, switching to syslog");
diag_set('y', xioparms.syslogfac);
xioparms.logopt = 'y';
} else {
Info("starting connect loop");
}
return STAT_OK;
}
/* This function performs preparations for addresses like TCP-CONNECT
at the beginning of the outer (retry/fork) loop:
it evaluates some options and performs name resolution of both server
(target, "them") address and bind ("us") address.
It is intended to be invoked before the connect loop starts;
returns STAT_OK on success or some other value on failure;
applies and consumes the following options:
PH_EARLY
OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
*/
int
_xioopen_ipapp_prepare(
struct opt *opts,
struct opt **opts0,
const char *hostname,
const char *portname,
int *pf,
int protocol,
const int ai_flags[2],
struct addrinfo ***themarr,
union sockaddr_union *us,
socklen_t *uslen,
bool *needbind,
bool *lowport,
int socktype) {
OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
returns STAT_OK, STAT_RETRYLATER, or STAT_NORETRY (+errno)
*/
int _xioopen_ipapp_prepare(
struct opt **opts,
struct opt *opts0,
const char *hostname,
const char *portname,
int pf,
int socktype,
int protocol,
const int ai_flags[2],
struct addrinfo ***themarr, /* always from getaddrinfo(); xiofreeaddrinfo()! */
struct addrinfo ***bindarr, /* on bind from getaddrinfo(); xiofreeaddrinfo()! */
uint16_t *bindport, /* for bind without address */
bool *needbind,
bool *lowport)
{
uint16_t port;
int rc;
retropt_socket_pf(opts, pf);
*opts = copyopts(opts0, GROUP_ALL);
if (hostname != NULL || portname != NULL) {
rc = xiogetaddrinfo(hostname, portname, *pf, socktype, protocol,
rc = xiogetaddrinfo(hostname, portname, pf, socktype, protocol,
themarr, ai_flags);
if (rc == EAI_AGAIN) {
Warn4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
hostname?hostname:"NULL", portname?portname:"NULL",
*pf, gai_strerror(rc));
pf, gai_strerror(rc));
errno = EAGAIN;
return STAT_RETRYLATER;
} else if (rc != 0) {
Error4("_xioopen_ipapp_prepare(node=\"%s\", service=\"%s\", pf=%d, ...): %s",
hostname?hostname:"NULL", portname?portname:"NULL",
*pf, (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
pf, (rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
errno = 0; /* unspecified */
return STAT_NORETRY; /*! STAT_RETRYLATER? */
}
}
applyopts(NULL, -1, opts, PH_EARLY);
applyopts(NULL, -1, *opts, PH_EARLY);
/* 3 means: IP address AND port accepted */
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family,
socktype, protocol, (struct sockaddr *)us, uslen, 3,
ai_flags)
if (retropt_bind_ip(*opts, pf, socktype, protocol, bindarr, 3, ai_flags)
!= STAT_NOACTION) {
*needbind = true;
} else {
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
#if WITH_IP4
case PF_INET: socket_in_init(&us->ip4); *uslen = sizeof(us->ip4); break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6: socket_in6_init(&us->ip6); *uslen = sizeof(us->ip6); break;
#endif /* WITH_IP6 */
default: Error("unsupported protocol family");
}
}
if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
switch ((*pf!=PF_UNSPEC)?*pf:(**themarr)->ai_family) {
if (retropt_2bytes(*opts, OPT_SOURCEPORT, &port) >= 0) {
if (*bindarr) {
struct addrinfo **bindp;
bindp = *bindarr;
switch ((*bindp)->ai_family) {
#if WITH_IP4
case PF_INET: us->ip4.sin_port = htons(port); break;
case PF_INET: ((struct sockaddr_in *)(*bindp)->ai_addr)->sin_port = htons(port); break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6: us->ip6.sin6_port = htons(port); break;
case PF_INET6: ((struct sockaddr_in6 *)(*bindp)->ai_addr)->sin6_port = htons(port); break;
#endif /* WITH_IP6 */
default: Error("unsupported protocol family");
default:
Error("unsupported protocol family");
errno = EPROTONOSUPPORT;
return STAT_NORETRY;
}
} else {
*bindport = port;
}
*needbind = true;
}
retropt_bool(opts, OPT_LOWPORT, lowport);
*opts0 = copyopts(opts, GROUP_ALL);
retropt_bool(*opts, OPT_LOWPORT, lowport);
return STAT_OK;
}
#endif /* WITH_IP4 */
#endif /* _WITH_IP4 || _WITH_IP6 */
/* Tries to connect to the addresses in themarr, for each one it tries to bind
to the addresses in bindarr.
Ends on success or when all attempts failed.
Returns STAT_OK on success, or STAT_RETRYLATER (+errno) on failure. */
int _xioopen_ipapp_connect(struct single *sfd,
const char *hostname,
struct opt *opts,
struct addrinfo **themarr,
bool needbind,
struct addrinfo **bindarr,
uint16_t bindport,
bool lowport,
int level)
{
struct addrinfo **themp;
struct addrinfo **bindp;
union sockaddr_union bindaddr = {0};
union sockaddr_union *bindaddrp = NULL;
socklen_t bindlen = 0;
char infobuff[256];
int _errno;
int result = STAT_OK;
--level;
/* Loop over server addresses (themarr) */
themp = themarr;
while (*themp != NULL) {
Notice1("opening connection to %s",
sockaddr_info((*themp)->ai_addr, (*themp)->ai_addrlen,
infobuff, sizeof(infobuff)));
if (*(themp+1) == NULL) {
++level; /* last attempt */
}
/* Loop over array (list) of bind addresses */
if (needbind && bindarr != NULL) {
/* Bind by hostname, use resolvers results list */
bindp = bindarr;
while (*bindp != NULL) {
if ((*bindp)->ai_family == (*themp)->ai_family)
break;
++bindp;
}
if (*bindp == NULL) {
Warn3("%s: No bind address with matching address family (%d) of %s available",
sfd->addr->defname, (*themp)->ai_family, hostname);
++themp;
if ((*themp) == NULL) {
result = STAT_RETRYLATER;
}
_errno = ENOPROTOOPT;
continue;
}
bindaddrp = (union sockaddr_union *)(*bindp)->ai_addr;
bindlen = (*bindp)->ai_addrlen;
} else if (needbind && bindport) {
/* Bind by sourceport option */
switch ((*themp)->ai_family) {
#if WITH_IP4
case PF_INET:
bindaddr.ip4.sin_family = (*themp)->ai_family;
bindaddr.ip4.sin_port = htons(bindport);
bindaddrp = &bindaddr;
bindlen = sizeof(bindaddr.ip4);
break;
#endif
#if WITH_IP6
case PF_INET6:
bindaddr.ip6.sin6_family = (*themp)->ai_family;
bindaddr.ip6.sin6_port = htons(bindport);
bindaddrp = &bindaddr;
bindlen = sizeof(bindaddr.ip6);
break;
#endif
}
}
result =
_xioopen_connect(sfd,
bindaddrp, bindlen,
(*themp)->ai_addr, (*themp)->ai_addrlen,
opts, /*pf?pf:*/(*themp)->ai_family, (*themp)->ai_socktype, (*themp)->ai_protocol,
lowport, level);
if (result == STAT_OK)
break;
_errno = errno;
++themp;
if (*themp == NULL)
result = STAT_RETRYLATER;
} /* end of loop over target addresses */
if (result != STAT_OK)
errno = _errno;
return result;
}
#if WITH_TCP && WITH_LISTEN
@ -303,7 +453,7 @@ int _xioopen_ipapp_listen_prepare(
retropt_string(opts, OPT_BIND, &bindname);
/* Set AI_PASSIVE, except when it is explicitely disabled */
/* Set AI_PASSIVE, except when it is explicitly disabled */
ai_flags2[0] = ai_flags[0];
ai_flags2[1] = ai_flags[1];
if (!(ai_flags2[1] & AI_PASSIVE))
@ -382,6 +532,6 @@ int xioopen_ipapp_listen(
return result;
return 0;
}
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
#endif /* WITH_TCP && WITH_LISTEN */
#endif /* WITH_TCP || WITH_UDP */
#endif /* WITH_TCP || WITH_UDP || WITH_SCTP || WITH_DCCP || WITH_UDPLITE */

View file

@ -15,11 +15,9 @@ extern const struct optdesc opt_sourceport;
extern const struct optdesc opt_lowport;
extern int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
extern int _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0, const char *hostname, const char *portname, int *pf, int protocol, const int ai_flags[2], struct addrinfo ***themlist, union sockaddr_union *us, socklen_t *uslen, bool *needbind, bool *lowport, int socktype);
extern int _xioopen_ip4app_connect(const char *hostname, const char *portname,
struct single *xfd,
int socktype, int ipproto, void *protname,
struct opt *opts);
extern int _xioopen_ipapp_init(struct single *sfd, int xioflags, struct opt *opts, bool *dofork, int *maxchildren, int *pf, int *socktype, int *protocol);
extern int _xioopen_ipapp_prepare(struct opt **opts, struct opt *opts0, const char *hostname, const char *portname, int pf, int socktype, int protocol, const int ai_flags[2], struct addrinfo ***themarr, struct addrinfo ***bindarr, uint16_t *bindport, bool *needbind, bool *lowport);
extern int _xioopen_ipapp_connect(struct single *sfd, const char *hostname, struct opt *opts, struct addrinfo **themarr, bool needbind, struct addrinfo **bindarr, uint16_t bindport, bool lowport, int level);
extern int xioopen_ipapp_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
extern int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0, const char *portname, int *pf, int ipproto, const int ai_flags[2], union sockaddr_union *us, socklen_t *uslen, int socktype);

View file

@ -5,7 +5,7 @@
/* this file contains the implementation of the openssl addresses */
#include "xiosysincludes.h"
#if WITH_OPENSSL /* make this address configure dependend */
#if WITH_OPENSSL /* make this address configure dependent */
#include <openssl/conf.h>
#include <openssl/x509v3.h>
@ -26,7 +26,6 @@
(not only tcp, but also pipes, stdin, files...)
for tcp we want to provide support for socks and proxy.
read and write functions must use the openssl crypt versions.
but currently only plain tcp4 is implemented.
*/
/* Linux: "man 3 ssl" */
@ -239,13 +238,13 @@ static int xioopen_openssl_connect(
int socktype = SOCK_STREAM;
int ipproto = IPPROTO_TCP;
bool dofork = false;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo **themarr, *themp;
int maxchildren = 0;
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
bool needbind = false;
bool lowport = false;
int level = E_ERROR;
int i;
SSL_CTX* ctx;
bool opt_ver = true; /* verify peer certificate */
char *opt_cert = NULL; /* file name of client certificate */
@ -255,7 +254,7 @@ static int xioopen_openssl_connect(
int result;
if (!(xioflags & XIO_MAYCONVERT)) {
Error("address with data processing not allowed here");
Error1("%s: address with data processing not allowed here", argv[0]);
return STAT_NORETRY;
}
sfd->flags |= XIO_DOESCONVERT;
@ -267,20 +266,12 @@ static int xioopen_openssl_connect(
hostname = argv[1];
portname = argv[2];
if (hostname[0] == '\0') {
/* we catch this explicitely because empty commonname (peername) disables
/* We catch this explicitly because empty commonname (peername) disables
commonName check of peer certificate */
Error1("%s: empty host name", argv[0]);
return STAT_NORETRY;
}
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
if (applyopts_single(sfd, opts, PH_INIT) < 0)
return -1;
applyopts(sfd, -1, opts, PH_INIT);
retropt_bool(opts, OPT_FORK, &dofork);
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
#if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
@ -316,73 +307,83 @@ static int xioopen_openssl_connect(
socktype = SOCK_DGRAM;
ipproto = IPPROTO_UDP;
}
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
result =
_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, us, &uslen,
&needbind, &lowport, socktype);
if (result != STAT_OK) return STAT_NORETRY;
/* Apply and retrieve some options */
result = _xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
if (xioparms.logopt == 'm') {
Info("starting connect loop, switching to syslog");
diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
} else {
Info("starting connect loop");
}
opts0 = opts; /* save remaining options for each loop */
opts = NULL;
do { /* loop over failed connect and SSL handshake attempts */
Notice2("opening OpenSSL connection to %s:%s", hostname, portname);
/* Loop over themarr (which had been "ai_sorted") */
i = 0;
themp = themarr[i++];
while (themp != NULL) {
do { /* loop over retries (failed connect and SSL handshake attempts) and/or forks */
int _errno;
#if WITH_RETRY
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
level = E_INFO;
} else
if (sfd->forever || sfd->retry) {
level = E_NOTICE;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
level = E_WARN;
/* This cannot fork because we retrieved fork option above */
result =
_xioopen_connect(sfd,
needbind?us:NULL, uslen,
themp->ai_addr, themp->ai_addrlen,
opts, pf?pf:themp->ai_addr->sa_family, socktype, ipproto, lowport, level);
if (result == STAT_OK)
break;
themp = themarr[i++];
if (themp == NULL) {
result = STAT_RETRYLATER;
}
}
opts = copyopts(opts0, GROUP_ALL);
result =
_xioopen_ipapp_prepare(&opts, opts0, hostname, portname,
pf, socktype, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, &bindarr, &bindport, &needbind, &lowport);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry) {
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
Notice2("opening connection to server %s:%s", hostname, portname);
result =
_xioopen_ipapp_connect(sfd, hostname, opts, themarr,
needbind, bindarr, bindport, lowport, level);
_errno = errno;
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
--sfd->retry;
freeopts(opts);
continue;
}
xiofreeaddrinfo(themarr);
return STAT_NORETRY;
#endif /* WITH_RETRY */
default:
xiofreeaddrinfo(themarr);
return result;
}
/*! isn't this too early? */
if ((result = _xio_openlate(sfd, opts)) < 0) {
xiofreeaddrinfo(themarr);
Error4("%s:%s:%s: %s", argv[0], hostname, portname,
_errno?strerror(_errno):"(See above)");
freeopts(opts0);
freeopts(opts);
return result;
}
@ -393,19 +394,19 @@ static int xioopen_openssl_connect(
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry) {
Close(sfd->fd);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
--sfd->retry;
freeopts(opts);
Close(sfd->fd);
continue;
}
#endif /* WITH_RETRY */
default:
xiofreeaddrinfo(themarr);
return STAT_NORETRY;
freeopts(opts);
freeopts(opts0);
return result;
}
if (dofork) {
@ -420,15 +421,19 @@ static int xioopen_openssl_connect(
level = E_WARN;
}
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
if (sfd->forever || --sfd->retry) {
Nanosleep(&sfd->intervall, NULL); continue;
if (sfd->forever || sfd->retry--) {
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
sfd->forever = false; sfd->retry = 0;
sfd->forever = false;
sfd->retry = 0;
break;
}
@ -438,21 +443,29 @@ static int xioopen_openssl_connect(
sfd->para.openssl.ssl = NULL;
/* with and without retry */
Nanosleep(&sfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
while (maxchildren > 0 && num_child >= maxchildren) {
Info1("all %d allowed children are active, waiting", maxchildren);
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue; /* with next socket() bind() connect() */
}
#endif /* WITH_RETRY */
break;
} while (true); /* drop out on success */
xiofreeaddrinfo(themarr);
openssl_conn_loginfo(sfd->para.openssl.ssl);
free((void *)opt_commonname);
free((void *)opt_snihost);
/* fill in the fd structure */
return STAT_OK;
Notice2("successfully connected to SSL server %s:%s", hostname, portname);
result = _xio_openlate(sfd, opts);
freeopts(opts);
freeopts(opts0);
return result;
}
@ -702,7 +715,7 @@ int _xioopen_openssl_listen(struct single *sfd,
const char *opt_commonname,
SSL_CTX *ctx,
int level) {
char error_string[120];
char error_string[256];
unsigned long err;
int errint, ret;
@ -764,7 +777,7 @@ int _xioopen_openssl_listen(struct single *sfd,
while (err = ERR_get_error()) {
ERR_error_string_n(err, error_string, sizeof(error_string));
Msg4(level, "SSL_accept(): %s / %s / %s / %s", error_string,
ERR_lib_error_string(err), ERR_func_error_string(err),
ERR_lib_error_string(err), error_string,
ERR_reason_error_string(err));
}
/* Msg1(level, "SSL_accept(): %s", ERR_error_string(e, buf));*/
@ -793,7 +806,7 @@ int _xioopen_openssl_listen(struct single *sfd,
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
/* In OpenSSL 0.9.7 compression methods could be added using
* SSL_COMP_add_compression_method(3), but the implemntation is not compatible
* SSL_COMP_add_compression_method(3), but the implementation is not compatible
* with the standard (RFC3749).
*/
static int openssl_setup_compression(SSL_CTX *ctx, char *method)
@ -1976,12 +1989,20 @@ static int xioSSL_set_fd(struct single *sfd, int level) {
should not retry for any reason. */
static int xioSSL_connect(struct single *sfd, const char *opt_commonname,
bool opt_ver, int level) {
char error_string[120];
int errint, status, ret;
sigset_t masksigs, oldsigs;
char error_string[256];
int errint, status, _errno, ret;
unsigned long err;
sigemptyset(&masksigs);
sigaddset(&masksigs, SIGCHLD);
sigaddset(&masksigs, SIGUSR1);
Sigprocmask(SIG_BLOCK, &masksigs, &oldsigs);
/* connect via SSL by performing handshake */
if ((ret = sycSSL_connect(sfd->para.openssl.ssl)) <= 0) {
ret = sycSSL_connect(sfd->para.openssl.ssl);
_errno = errno;
Sigprocmask(SIG_SETMASK, &oldsigs, NULL);
if (ret <= 0) {
/*if (ERR_peek_error() == 0) Msg(level, "SSL_connect() failed");*/
errint = SSL_get_error(sfd->para.openssl.ssl, ret);
switch (errint) {
@ -2005,14 +2026,14 @@ static int xioSSL_connect(struct single *sfd, const char *opt_commonname,
if (ret == 0) {
Msg(level, "SSL_connect(): socket closed by peer");
} else if (ret == -1) {
Msg1(level, "SSL_connect(): %s", strerror(errno));
Msg1(level, "SSL_connect(): %s", strerror(_errno));
}
} else {
Msg(level, "I/O error"); /*!*/
while (err = ERR_get_error()) {
ERR_error_string_n(err, error_string, sizeof(error_string));
Msg4(level, "SSL_connect(): %s / %s / %s / %s", error_string,
ERR_lib_error_string(err), ERR_func_error_string(err),
ERR_lib_error_string(err), error_string,
ERR_reason_error_string(err));
}
}
@ -2037,7 +2058,7 @@ static int xioSSL_connect(struct single *sfd, const char *opt_commonname,
/* on result < 0: errno is set (at least to EIO) */
ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) {
unsigned long err;
char error_string[120];
char error_string[256];
int _errno = EIO; /* if we have no better idea about nature of error */
int errint, ret;
@ -2072,7 +2093,7 @@ ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) {
while (err = ERR_get_error()) {
ERR_error_string_n(err, error_string, sizeof(error_string));
Error4("SSL_read(): %s / %s / %s / %s", error_string,
ERR_lib_error_string(err), ERR_func_error_string(err),
ERR_lib_error_string(err), error_string,
ERR_reason_error_string(err));
}
}
@ -2098,7 +2119,7 @@ ssize_t xiopending_openssl(struct single *pipe) {
/* on result < 0: errno is set (at least to EIO) */
ssize_t xiowrite_openssl(struct single *pipe, const void *buff, size_t bufsiz) {
unsigned long err;
char error_string[120];
char error_string[256];
int _errno = EIO; /* if we have no better idea about nature of error */
int errint, ret;
@ -2131,7 +2152,7 @@ ssize_t xiowrite_openssl(struct single *pipe, const void *buff, size_t bufsiz) {
while (err = ERR_get_error()) {
ERR_error_string_n(err, error_string, sizeof(error_string));
Error4("SSL_write(): %s / %s / %s / %s", error_string,
ERR_lib_error_string(err), ERR_func_error_string(err),
ERR_lib_error_string(err), error_string,
ERR_reason_error_string(err));
}
}

View file

@ -5,7 +5,7 @@
#ifndef __xio_openssl_included
#define __xio_openssl_included 1
#if WITH_OPENSSL /* make this address configure dependend */
#if WITH_OPENSSL /* make this address configure dependent */
#define SSLIO_BASE 0x53530000 /* "SSxx" */
#define SSLIO_MASK 0xffff0000

View file

@ -15,18 +15,21 @@
#if WITH_POSIXMQ
static int _posixmq_unlink(
const char *name,
int level); /* message level on error */
static int _posixmq_flush(struct single *sfd);
static int _posixmq_unlink(const char *name, int level);
static int xioopen_posixmq(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
const struct addrdesc xioaddr_posixmq_bidir = { "POSIXMQ-BIDIRECTIONAL", 1+XIO_RDWR, xioopen_posixmq, GROUP_FD|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY, XIO_RDWR, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_read = { "POSIXMQ-READ", 1+XIO_RDONLY, xioopen_posixmq, GROUP_FD|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY, XIO_RDONLY, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_receive = { "POSIXMQ-RECEIVE", 1+XIO_RDONLY, xioopen_posixmq, GROUP_FD|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY|GROUP_CHILD, XIO_RDONLY, XIOREAD_RECV_ONESHOT, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_send = { "POSIXMQ-SEND", 1+XIO_WRONLY, xioopen_posixmq, GROUP_FD|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY|GROUP_CHILD, XIO_WRONLY, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_bidir = { "POSIXMQ-BIDIRECTIONAL", 1+XIO_RDWR, xioopen_posixmq, GROUP_FD|GROUP_OPEN|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY, XIO_RDWR, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_read = { "POSIXMQ-READ", 1+XIO_RDONLY, xioopen_posixmq, GROUP_FD|GROUP_OPEN|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY, XIO_RDONLY, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_receive = { "POSIXMQ-RECEIVE", 1+XIO_RDONLY, xioopen_posixmq, GROUP_FD|GROUP_OPEN|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY|GROUP_CHILD, XIO_RDONLY, XIOREAD_RECV_ONESHOT, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_send = { "POSIXMQ-SEND", 1+XIO_WRONLY, xioopen_posixmq, GROUP_FD|GROUP_OPEN|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY|GROUP_CHILD, XIO_WRONLY, 0, 0 HELP(":<mqname>") };
const struct addrdesc xioaddr_posixmq_write = { "POSIXMQ-WRITE", 1+XIO_WRONLY, xioopen_posixmq, GROUP_FD|GROUP_OPEN|GROUP_NAMED|GROUP_POSIXMQ|GROUP_RETRY|GROUP_CHILD, XIO_WRONLY, 0, 0 HELP(":<mqname>") };
const struct optdesc opt_posixmq_priority = { "posixmq-priority", "mq-pri", OPT_POSIXMQ_PRIORITY, GROUP_POSIXMQ, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.posixmq.prio), XIO_SIZEOF(para.posixmq.prio), 0 };
const struct optdesc opt_posixmq_priority = { "posixmq-priority", "mq-prio", OPT_POSIXMQ_PRIORITY, GROUP_POSIXMQ, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.posixmq.prio), XIO_SIZEOF(para.posixmq.prio), 0 };
const struct optdesc opt_posixmq_flush = { "posixmq-flush", "mq-flush", OPT_POSIXMQ_FLUSH, GROUP_POSIXMQ, PH_EARLY, TYPE_BOOL, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_posixmq_maxmsg = { "posixmq-maxmsg", "mq-maxmsg", OPT_POSIXMQ_MAXMSG, GROUP_POSIXMQ, PH_OPEN, TYPE_LONG, OFUNC_SPEC, 0, 0, 0 };
const struct optdesc opt_posixmq_msgsize = { "posixmq-msgsize", "mq-msgsize", OPT_POSIXMQ_MSGSIZE, GROUP_POSIXMQ, PH_OPEN, TYPE_LONG, OFUNC_SPEC, 0, 0, 0 };
/* _read(): open immediately, stay in transfer loop
_recv(): wait until data (how we know there is??), oneshot, opt.fork
@ -45,8 +48,18 @@ static int xioopen_posixmq(
int dirs = addrdesc->arg1;
int oneshot = addrdesc->arg2;
bool opt_unlink_early = false;
bool nonblock = 0;
bool flush = false;
long maxmsg;
long msgsize;
struct mq_attr attr = { 0 };
bool setopts = false;
int oflag;
bool opt_o_creat = true;
bool opt_o_excl = false;
#ifdef O_CLOEXEC
bool opt_o_cloexec = true;
#endif
mode_t opt_mode = 0666;
mqd_t mqd;
int _errno;
@ -55,10 +68,6 @@ static int xioopen_posixmq(
bool with_intv = false;
int result = 0;
if (!xioparms.experimental) {
Error1("%s: use option --experimental to acknowledge unmature state", argv[0]);
return STAT_NORETRY;
}
if (argc != 2) {
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
return STAT_NORETRY;
@ -77,7 +86,10 @@ static int xioopen_posixmq(
with_intv = true;
}
}
if (dirs == XIO_RDWR) {
/* Bidirectional ADDRESS in unidirectional mode? Adapt dirs */
dirs = (xioflags & XIO_ACCMODE);
}
retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
if (! dofork && maxchildren) {
Error("option max-children not allowed without option fork");
@ -94,8 +106,54 @@ static int xioopen_posixmq(
Error1("strdup(\"%s\"): out of memory", name);
}
retropt_bool(opts, OPT_O_EXCL, &opt_o_excl);
retropt_mode(opts, OPT_PERM, &opt_mode);
retropt_bool(opts, OPT_O_CREAT, &opt_o_creat);
retropt_bool(opts, OPT_O_EXCL, &opt_o_excl);
#ifdef O_CLOEXEC
retropt_bool(opts, OPT_O_CLOEXEC, &opt_o_cloexec);
#endif
retropt_mode(opts, OPT_PERM, &opt_mode);
retropt_bool(opts, OPT_POSIXMQ_FLUSH, &flush);
retropt_long(opts, OPT_POSIXMQ_MAXMSG, &maxmsg) ||
(setopts = true);
retropt_long(opts, OPT_POSIXMQ_MSGSIZE, &msgsize) ||
(setopts = true);
/* When just one of mq-maxmsg and mq-msgsize options has been provided,
we must nevertheless set the other option value in struct mq_attr.
For this we have to find the default, read it from /proc fs */
if (setopts) {
int pfd;
const static char *PROC_MAXMSG = "/proc/sys/fs/mqueue/msg_default";
const static char *PROC_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
char buff[21]; /* fit a 64bit num in decimal */
ssize_t bytes;
if (maxmsg == 0) {
if ((pfd = Open(PROC_MAXMSG, O_RDONLY, 0)) < 0) {
Warn2("open(\"%s\", O_RDONLY, 0): %s", PROC_MAXMSG, strerror(errno));
} else if ((bytes = Read(pfd, buff, sizeof(buff)-1)) < 0) {
Warn4("read(%d /* \"%s\" */, buff, "F_Zd"): %s",
pfd, PROC_MAXMSG, sizeof(buff)-1, strerror (errno));
Close(pfd);
} else {
sscanf(buff, "%ld", &maxmsg);
Close(pfd);
}
}
if (msgsize == 0) {
if ((pfd = Open(PROC_MSGSIZE, O_RDONLY, 0)) < 0) {
Warn2("open(\"%s\", O_RDONLY, 0): %s", PROC_MSGSIZE, strerror(errno));
} else if ((bytes = Read(pfd, buff, sizeof(buff)-1)) < 0) {
Warn4("read(%d /* \"%s\" */, buff, "F_Zd"): %s",
pfd, PROC_MSGSIZE, sizeof(buff)-1, strerror (errno));
Close(pfd);
} else {
sscanf(buff, "%ld", &msgsize);
Close(pfd);
}
}
}
retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early);
if (opt_unlink_early) {
@ -106,26 +164,65 @@ static int xioopen_posixmq(
sfd->howtoend = END_CLOSE;
sfd->dtype = XIODATA_POSIXMQ | oneshot;
oflag = O_CREAT;
if (opt_o_excl) oflag |= O_EXCL;
oflag = 0;
if (opt_o_creat) oflag |= O_CREAT;
if (opt_o_excl) oflag |= O_EXCL;
#ifdef O_CLOEXEC
if (opt_o_cloexec) oflag |= O_CLOEXEC; /* does not seem to work (Ubuntu-20) */
#endif
switch (dirs) {
case XIO_RDWR: oflag |= O_RDWR; break;
case XIO_RDONLY: oflag |= O_RDONLY; break;
case XIO_WRONLY: oflag |= O_WRONLY; break;
}
if (retropt_bool(opts, OPT_O_NONBLOCK, &nonblock) >= 0 && nonblock)
oflag |= O_NONBLOCK;
if (flush) {
if (_posixmq_flush(sfd) != STAT_OK)
return STAT_NORETRY;
}
/* Now open the message queue */
Debug3("mq_open(\"%s\", %d, "F_mode", NULL)", name, oflag, opt_mode);
mqd = mq_open(name, oflag, opt_mode, NULL);
if (setopts) {
attr.mq_maxmsg = maxmsg;
attr.mq_msgsize = msgsize;
Debug8("%s: mq_open(\"%s\", "F_mode", "F_mode", {flags=%ld, maxmsg=%ld, msgsize=%ld, curmsgs=%ld} )", argv[0], name, oflag, opt_mode, attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
} else {
Debug4("%s: mq_open(\"%s\", "F_mode", "F_mode", NULL)", argv[0], name, oflag, opt_mode);
}
mqd = mq_open(name, oflag, opt_mode, setopts ? &attr : NULL);
_errno = errno;
Debug1("mq_open() -> %d", mqd);
if (mqd < 0) {
Error3("%s: mq_open(\"%s\"): %s", argv[0], name, strerror(errno));
if (setopts)
Error9("%s: mq_open(\"%s\", "F_mode", "F_mode", {flags=%ld, maxmsg=%ld, msgsize=%ld, curmsgs=%ld} ): %s", argv[0], name, oflag, opt_mode, attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs, strerror(errno));
else
Error5("%s: mq_open(\"%s\", "F_mode", "F_mode", NULL): %s", argv[0], name, oflag, opt_mode, strerror(errno));
errno = _errno;
return STAT_RETRYLATER;
}
/* applyopts_cloexec(mqd, opts); */ /* does not seem to work too (Ubuntu-20) */
sfd->fd = mqd;
Debug1("mq_getattr(%d, ...)", mqd);
if (mq_getattr(mqd, &attr) < 0) {
Warn4("mq_getattr(%d[\"%s\"], %p): %s",
mqd, sfd->para.posixmq.name, &attr, strerror(errno));
mq_close(mqd);
return STAT_NORETRY;
}
Info5("POSIXMQ queue \"%s\" attrs: { flags=%ld, maxmsg=%ld, msgsize=%ld, curmsgs=%ld }",
name, attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
if (setopts) {
if (attr.mq_maxmsg != maxmsg)
Warn2("mq_open(): requested maxmsg=%ld, but result is %ld",
maxmsg, attr.mq_maxmsg);
if (attr.mq_msgsize != msgsize)
Warn2("mq_open(): requested msgsize=%ld, but result is %ld",
msgsize, attr.mq_msgsize);
}
if (!dofork && !oneshot) {
return STAT_OK;
}
@ -155,6 +252,8 @@ static int xioopen_posixmq(
do {
struct pollfd pollfd;
if (oflag & O_NONBLOCK)
break;
pollfd.fd = sfd->fd;
pollfd.events = (dirs==XIO_RDONLY?POLLIN:POLLOUT);
if (xiopoll(&pollfd, 1, NULL) > 0) {
@ -231,6 +330,81 @@ static int xioopen_posixmq(
}
/* With option flush try to open the queue and "consume" its current contents */
static int _posixmq_flush(
struct single *sfd)
{
mqd_t mqd;
struct mq_attr attr;
void *buff;
size_t bufsiz;
int _errno;
int p = 0; /* number of messages flushed */
size_t b = 0; /* number of bytes flushed */
Info1("flushing POSIXMQ queue \"%s\"", sfd->para.posixmq.name);
Debug1("mq_open(\"%s\", O_RDONLY|O_NONBLOCK, 0, NULL)",
sfd->para.posixmq.name);
mqd = mq_open(sfd->para.posixmq.name, O_RDONLY|O_NONBLOCK, 0, NULL);
_errno = errno;
Debug1("mq_open() -> %d", mqd);
if (mqd < 0 && _errno == ENOENT) {
Info("this queue does not exist, no need to flush it");
return STAT_OK;
}
if (mqd < 0) {
Warn2("mq_open(\"%s\", ...): %s", sfd->para.posixmq.name,
strerror(_errno));
return STAT_NORETRY;
}
Debug1("mq_getattr(%d, ...)", mqd);
if (mq_getattr(mqd, &attr) < 0) {
Warn4("mq_getattr(%d[\"%s\"], %p): %s",
mqd, sfd->para.posixmq.name, &attr, strerror(errno));
mq_close(mqd);
return STAT_NORETRY;
}
if (attr.mq_curmsgs == 0) {
Info1("POSIXMQ \"%s\" is empty", sfd->para.posixmq.name);
mq_close(mqd);
return STAT_OK;
}
bufsiz = attr.mq_msgsize;
if ((buff = Malloc(bufsiz)) == NULL) {
mq_close(mqd);
return STAT_RETRYLATER;
}
/* Now read all messages to null */
while (true) {
ssize_t bytes;
Debug3("mq_receive(mqd=%d, %p, "F_Zu", {} )", mqd, buff, bufsiz);
bytes = mq_receive(mqd, buff, bufsiz, &sfd->para.posixmq.prio);
_errno = errno;
Debug1("mq_receive() -> "F_Zd, bytes);
errno = _errno;
if (bytes == 0 || (bytes < 0 && _errno == EAGAIN)) {
break;
}
if (bytes < 0) {
Warn2("flushing POSIXMQ \"%s\" failed: %s",
sfd->para.posixmq.name, strerror(_errno));
free(buff);
mq_close(mqd);
return STAT_NORETRY;
}
++p;
b += bytes;
}
Info3("flushed "F_Zu" bytes in %u packets from queue \"%s\"", b, p,
sfd->para.posixmq.name);
free(buff);
mq_close(mqd);
return STAT_OK;
}
ssize_t xiowrite_posixmq(
struct single *sfd,
const void *buff,
@ -283,6 +457,9 @@ ssize_t xioclose_posixmq(
struct single *sfd)
{
int res;
if (sfd->fd < 0)
return 0;
Debug1("xioclose_posixmq(): mq_close(%d)", sfd->fd);
res = mq_close(sfd->fd);
if (res < 0) {

View file

@ -9,8 +9,12 @@ extern const struct addrdesc xioaddr_posixmq_bidir;
extern const struct addrdesc xioaddr_posixmq_read;
extern const struct addrdesc xioaddr_posixmq_receive;
extern const struct addrdesc xioaddr_posixmq_send;
extern const struct addrdesc xioaddr_posixmq_write;
extern const struct optdesc opt_posixmq_maxmsg;
extern const struct optdesc opt_posixmq_msgsize;
extern const struct optdesc opt_posixmq_priority;
extern const struct optdesc opt_posixmq_flush;
extern ssize_t xioread_posixmq(struct single *file, void *buff, size_t bufsiz);
extern ssize_t xiopending_posixmq(struct single *pipe);

View file

@ -12,6 +12,7 @@
#include "xio-progcall.h"
#include "xio-socket.h"
#include "xio-socketpair.h"
/* these options are used by address pty too */
@ -23,7 +24,7 @@ const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_P
#endif
const struct optdesc opt_sitout_eio = { "sitout-eio", NULL, OPT_SITOUT_EIO, GROUP_PTY, PH_OFFSET, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.exec.sitout_eio), XIO_SIZEOF(para.exec.sitout_eio) };
#if WITH_EXEC || WITH_SYSTEM
#if WITH_EXEC || WITH_SYSTEM || WITH_SHELL
#define MAXPTYNAMELEN 64
@ -623,7 +624,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
*optsp = popts;
return pid; /* indicate parent (main) process */
}
#endif /* WITH_EXEC || WITH_SYSTEM */
#endif /* WITH_EXEC || WITH_SYSTEM || WITH_SHELL */
int setopt_path(struct opt *opts, char **path) {

View file

@ -83,18 +83,18 @@ static int xioopen_proxy_connect(
xiofile_t *xxfd,
const struct addrdesc *addrdesc)
{
/* we expect the form: host:host:port */
/* we expect the form: host:host:port */
struct single *sfd = &xxfd->stream;
struct opt *opts0 = NULL;
struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
/* variables to be filled with address option values */
bool dofork = false;
int maxchildren = 0;
/* */
int pf = PF_UNSPEC;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo **themarr, *themp;
int i;
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
const char *proxyname; char *proxyport = NULL;
const char *targetname, *targetport;
int ipproto = IPPROTO_TCP;
@ -112,90 +112,123 @@ static int xioopen_proxy_connect(
targetname = argv[2];
targetport = argv[3];
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
if (applyopts_single(sfd, opts, PH_INIT) < 0)
return -1;
applyopts(sfd, 1, opts, PH_INIT);
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_FORK, &dofork);
if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
if ((proxyport = strdup(PROXYPORT)) == NULL) {
errno = ENOMEM; return -1;
}
}
result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport,
sfd->para.socket.ip.ai_flags);
if (result != STAT_OK)
return result;
Notice4("opening connection to %s:%u via proxy %s:%s",
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
i = 0;
do { /* loop over retries (failed connect and proxy-request attempts) */
level = E_INFO;
result =
_xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
&pf, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, us, &uslen,
&needbind, &lowport, socktype);
result =
_xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
/* Loop over themlist */
i = 0;
themp = themarr[i++];
while (themp != NULL) {
Notice4("opening connection to %s:%u via proxy %s:%s",
proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);
#if WITH_RETRY
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
level = E_INFO;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
result = _xioopen_proxy_init(proxyvars, opts, targetname, targetport);
if (result != STAT_OK)
return result;
result =
_xioopen_connect(sfd,
needbind?us:NULL, uslen,
themp->ai_addr, themp->ai_addrlen,
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
if (result == STAT_OK)
break;
themp = themarr[i++];
if (themp == NULL) {
result = STAT_RETRYLATER;
}
opts0 = opts; /* save remaining options for each loop */
opts = NULL;
Notice4("opening connection to %s:%s via proxy %s:%s",
targetname, targetport, proxyname, proxyport);
do { /* loop over retries (failed connect and proxy-request attempts)
and/or forks */
int _errno;
#if WITH_RETRY
if (sfd->forever || sfd->retry) {
level = E_NOTICE;
} else
#endif /* WITH_RETRY */
level = E_WARN;
opts = copyopts(opts0, GROUP_ALL);
result =
_xioopen_ipapp_prepare(&opts, opts0, proxyname, proxyport,
pf, socktype, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, &bindarr, &bindport, &needbind, &lowport);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry) {
--sfd->retry;
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
default:
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
}
xiofreeaddrinfo(themarr);
applyopts(sfd, -1, opts, PH_ALL);
if ((result = _xio_openlate(sfd, opts)) < 0)
result =
_xioopen_proxy_prepare(proxyvars, opts, targetname, targetport,
sfd->para.socket.ip.ai_flags);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
Notice2("opening connection to proxy %s:%s", proxyname, proxyport);
result =
_xioopen_ipapp_connect(sfd, proxyname, opts, themarr,
needbind, bindarr, bindport, lowport, level);
_errno = errno;
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
Error4("%s:%s:...,proxyport=%s: %s", argv[0], proxyname, proxyport,
_errno?strerror(_errno):"(See above)");
freeopts(opts0);
freeopts(opts);
return result;
}
result = _xioopen_proxy_connect(sfd, proxyvars, level);
switch (result) {
@ -204,11 +237,16 @@ static int xioopen_proxy_connect(
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
freeopts(opts);
freeopts(opts0);
return result;
}
@ -225,21 +263,32 @@ static int xioopen_proxy_connect(
}
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
if (sfd->forever || --sfd->retry) {
Nanosleep(&sfd->intervall, NULL); continue;
if (sfd->retry > 0)
--sfd->retry;
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
freeopts(opts);
freeopts(opts0);
return STAT_RETRYLATER;
}
if (pid == 0) { /* child process */
sfd->forever = false; sfd->retry = 0;
sfd->forever = false;
sfd->retry = 0;
break;
}
/* parent process */
Close(sfd->fd);
/* With and without retry */
Nanosleep(&sfd->intervall, NULL);
dropopts(opts, PH_ALL);
opts = copyopts(opts0, GROUP_ALL);
while (maxchildren > 0 && num_child >= maxchildren) {
Info1("all %d allowed children are active, waiting", maxchildren);
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
} else
#endif /* WITH_RETRY */
@ -248,25 +297,25 @@ static int xioopen_proxy_connect(
}
} while (true); /* end of complete open loop - drop out on success */
/* Only "active" process breaks (master without fork, or child) */
Notice4("successfully connected to %s:%u via proxy %s:%s",
proxyvars->targetaddr, proxyvars->targetport,
proxyname, proxyport);
return 0;
result = _xio_openlate(sfd, opts);
freeopts(opts);
freeopts(opts0);
return result;
}
int _xioopen_proxy_prepare(
int _xioopen_proxy_init(
struct proxyvars *proxyvars,
struct opt *opts,
const char *targetname,
const char *targetport,
const int ai_flags[2]) {
union sockaddr_union host;
socklen_t socklen = sizeof(host);
int rc;
const char *targetport)
{
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
@ -316,6 +365,28 @@ int _xioopen_proxy_prepare(
Close(authfd);
}
if (!proxyvars->doresolve) {
proxyvars->targetaddr = strdup(targetname);
if (proxyvars->targetaddr == NULL) {
Error1("strdup(\"%s\"): out of memory", targetname);
return STAT_RETRYLATER;
}
}
return STAT_OK;
}
int _xioopen_proxy_prepare(
struct proxyvars *proxyvars,
struct opt *opts,
const char *targetname,
const char *targetport,
const int ai_flags[2])
{
union sockaddr_union host;
socklen_t socklen = sizeof(host);
int rc;
if (proxyvars->doresolve) {
/* currently we only resolve to IPv4 addresses. This is in accordance to
RFC 2396; however once it becomes clear how IPv6 addresses should be
@ -325,6 +396,10 @@ int _xioopen_proxy_prepare(
&host, &socklen, ai_flags);
if (rc != STAT_OK) {
proxyvars->targetaddr = strdup(targetname);
if (proxyvars->targetaddr == NULL) {
Error1("strdup(\"%s\"): out of memory", targetname);
return STAT_RETRYLATER;
}
} else {
#define LEN 16 /* www.xxx.yyy.zzz\0 */
if ((proxyvars->targetaddr = Malloc(LEN)) == NULL) {
@ -337,8 +412,6 @@ int _xioopen_proxy_prepare(
((unsigned char *)&host.ip4.sin_addr.s_addr)[3]);
#undef LEN
}
} else {
proxyvars->targetaddr = strdup(targetname);
}
proxyvars->targetport = htons(parseport(targetport, IPPROTO_TCP));
@ -376,7 +449,7 @@ int _xioopen_proxy_connect(struct single *sfd,
* xiosanitize(request, strlen(request), textbuff) = '\0';
Info1("sending \"%s\"", textbuff);
/* write errors are assumed to always be hard errors, no retry */
if (writefull(sfd->fd, request, strlen(request)) < 0) {
if (writefull(sfd->fd, request, strlen(request), NULL) < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
sfd->fd, request, strlen(request), strerror(errno));
if (Close(sfd->fd) < 0) {
@ -406,7 +479,7 @@ int _xioopen_proxy_connect(struct single *sfd,
*next = '\0';
Info1("sending \"%s\\r\\n\"", header);
*next++ = '\r'; *next++ = '\n'; *next++ = '\0';
if (writefull(sfd->fd, header, strlen(header)) < 0) {
if (writefull(sfd->fd, header, strlen(header), NULL) < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
sfd->fd, header, strlen(header), strerror(errno));
if (Close(sfd->fd) < 0) {
@ -419,7 +492,7 @@ int _xioopen_proxy_connect(struct single *sfd,
}
Info("sending \"\\r\\n\"");
if (writefull(sfd->fd, "\r\n", 2) < 0) {
if (writefull(sfd->fd, "\r\n", 2, NULL) < 0) {
Msg2(level, "write(%d, \"\\r\\n\", 2): %s",
sfd->fd, strerror(errno));
if (Close(sfd->fd) < 0) {

View file

@ -25,9 +25,8 @@ extern const struct optdesc opt_proxy_authorization_file;
extern const struct addrdesc xioaddr_proxy_connect;
extern int _xioopen_proxy_init(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport);
extern int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts, const char *targetname, const char *targetport, const int ai_flags[2]);
int _xioopen_proxy_connect(struct single *xfd,
struct proxyvars *proxyvars,
int level);
extern int _xioopen_proxy_connect(struct single *xfd, struct proxyvars *proxyvars, int level);
#endif /* !defined(__xio_proxy_h_included) */

View file

@ -184,7 +184,7 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
/* we must carriage return, because readline will first print the
prompt */
ssize_t writt;
writt = writefull(pipe->fd, "\r", 1);
writt = writefull(pipe->fd, "\r", 1, NULL);
if (writt < 0) {
Warn2("write(%d, \"\\r\", 1): %s",
pipe->fd, strerror(errno));
@ -204,6 +204,9 @@ ssize_t xioread_readline(struct single *pipe, void *buff, size_t bufsiz) {
if (line == NULL) {
return 0; /* EOF */
}
if (strlen(line) == 0) {
Write(STDOUT_FILENO, "\n", 1);
}
#if _WITH_TERMIOS
xiotermios_clrflag(pipe->fd, 3, ECHO);
xiotermios_flush(pipe->fd);

View file

@ -81,7 +81,7 @@ static int xioopen_shell(
Setenv("SHELL", shellpath, 1);
Info1("executing shell command \"%s\"", string);
Debug3("execl(\"%s\", \"%s\", \"-c\", \"%s\", NULL",
Debug3("execl(\"%s\", \"%s\", \"-c\", \"%s\", NULL)",
shellpath, shellname, string);
result = execl(shellpath, shellname, "-c", string, (char *)NULL);
if (result != 0) {

View file

@ -7,8 +7,6 @@
#include "xiosysincludes.h"
#if _WITH_SOCKET
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
@ -30,6 +28,8 @@
#include "xio-tcpwrap.h"
#if _WITH_SOCKET
static int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
static int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
static int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
@ -191,6 +191,8 @@ const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_listen = { "setsockopt-listen", "sockopt-listen", OPT_SETSOCKOPT_LISTEN, GROUP_SOCKET,PH_PREBIND, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_socket = { "setsockopt-socket", "sockopt-sock", OPT_SETSOCKOPT_SOCKET, GROUP_SOCKET,PH_PASTSOCKET, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_connected = { "setsockopt-connected", "sockopt-conn", OPT_SETSOCKOPT_CONNECTED, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.null_eof) };
@ -262,8 +264,13 @@ static int xioopen_socket_connect(
sfd->dtype = XIOREAD_STREAM|XIOWRITE_STREAM;
socket_init(0, &us);
if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3,
sfd->para.socket.ip.ai_flags)
if (retropt_bind(opts, pf, socktype, proto, (struct sockaddr *)&us, &uslen, -1,
#if _WITH_IP4 || _WITH_IP6
sfd->para.socket.ip.ai_flags
#else
NULL
#endif /* _WITH_IP4 || _WITH_IP6 */
)
!= STAT_NOACTION) {
needbind = true;
us.soa.sa_family = pf;
@ -540,7 +547,12 @@ int xioopen_socket_recvfrom(
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &sfd->para.socket.range,
sfd->para.socket.ip.ai_flags)
#if _WITH_IP4 || _WITH_IP6
sfd->para.socket.ip.ai_flags
#else
NULL
#endif /* _WITH_IP4 */
)
< 0) {
free(rangename);
return STAT_NORETRY;
@ -626,7 +638,12 @@ int xioopen_socket_recv(
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &sfd->para.socket.range,
sfd->para.socket.ip.ai_flags)
#if _WITH_IP4 || _WITH_IP6
sfd->para.socket.ip.ai_flags
#else
NULL
#endif /* _WITH_IP4 */
)
< 0) {
free(rangename);
return STAT_NORETRY;
@ -712,7 +729,12 @@ static int xioopen_socket_datagram(
/* which reply sockets will accept - determine by range option */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, 0, &sfd->para.socket.range,
sfd->para.socket.ip.ai_flags)
#if _WITH_IP4 || _WITH_IP6
sfd->para.socket.ip.ai_flags
#else
NULL
#endif /* _WITH_IP4 */
)
< 0) {
free(rangename);
return STAT_NORETRY;
@ -779,13 +801,13 @@ int xiogetpacketinfo(struct single *sfd, int fd)
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
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_O_CLOEXEC
Does not fork, does not retry.
Alternate (alt) bind semantics are:
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
with UNIX and abstract sockets: uses tmpname() to find a free file system
entry.
returns 0 on success.
Returns STAT_OK on success, or STAT_RETRYLATER (+errno) on failure.
*/
int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
struct sockaddr *them, size_t themlen,
@ -815,7 +837,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
applyopts_cloexec(sfd->fd, opts);
if (xiobind(sfd, us, uslen, opts, pf, alt, level) < 0) {
return -1;
return STAT_RETRYLATER;
}
applyopts(sfd, -1, opts, PH_CONNECT);
@ -855,6 +877,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
Msg4(level, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec"."F_tv_usec"): %s",
sfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
if (result == 0) {
@ -862,6 +885,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
strerror(ETIMEDOUT));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
if (writefd.revents & POLLERR) {
@ -877,15 +901,19 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno));
#endif
_errno = errno;
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
/* otherwise OK or network error */
result = Getsockopt(sfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
if (result != 0) {
_errno = errno;
Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s",
sfd->fd, strerror(err));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
Debug2("getsockopt(%d, SOL_SOCKET, SO_ERROR, { %d }) -> 0",
@ -895,6 +923,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(err));
Close(sfd->fd);
errno = err;
return STAT_RETRYLATER;
}
Fcntl_l(sfd->fd, F_SETFL, fcntl_flags);
@ -925,6 +954,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
sfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
themlen, strerror(errno));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
} else { /* result >= 0 */
@ -952,7 +982,7 @@ int _xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
PH_CONNECTED, PH_LATE,
OFUNC_OFFSET,
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_O_CLOEXEC
returns 0 on success.
*/
int xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
@ -1052,7 +1082,7 @@ int xioopen_connect(struct single *sfd, union sockaddr_union *us, size_t uslen,
applies and consumes the following option:
PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
OFUNC_OFFSET
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_O_CLOEXEC
*/
int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
union sockaddr_union *us, socklen_t uslen,
@ -1202,6 +1232,7 @@ int _xioopen_dgram_recvfrom(struct single *sfd, int xioflags,
}
#endif
#if WITH_IP4 || WITH_IP6
/* for generic sockets, this has already been retrieved */
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, pf, &sfd->para.socket.range,
@ -1213,6 +1244,7 @@ int _xioopen_dgram_recvfrom(struct single *sfd, int xioflags,
free(rangename);
sfd->para.socket.dorange = true;
}
#endif /* WITH_IP4 || WITH_IP6 */
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
xio_retropt_tcpwrap(sfd, opts);
@ -1424,6 +1456,7 @@ int _xioopen_dgram_recv(struct single *sfd, int xioflags,
}
#endif
#if WITH_IP4 || WITH_IP6
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, pf, &sfd->para.socket.range,
sfd->para.socket.ip.ai_flags)
@ -1434,6 +1467,7 @@ int _xioopen_dgram_recv(struct single *sfd, int xioflags,
free(rangename);
sfd->para.socket.dorange = true;
}
#endif /* WITH_IP4 || WITH_IP6 */
#if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
xio_retropt_tcpwrap(sfd, opts);
@ -1449,7 +1483,10 @@ int _xioopen_dgram_recv(struct single *sfd, int xioflags,
return STAT_OK;
}
#endif /* _WITH_SOCKET */
#if _WITH_SOCKET || _WITH_SOCKETPAIR
int retropt_socket_pf(struct opt *opts, int *pf) {
char *pfname;
@ -1478,8 +1515,11 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
}
return -1;
}
#endif /* _WITH_SOCKET || _WITH_SOCKETPAIR */
#if _WITH_SOCKET
/* 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.
@ -1651,7 +1691,7 @@ int xiocheckpeer(xiosingle_t *sfd,
char infobuff[256];
int result;
#if WITH_IP4
#if WITH_IP4 || WITH_IP6
if (sfd->para.socket.dorange) {
if (pa == NULL) { return -1; }
if (xiocheckrange(pa, &sfd->para.socket.range) < 0) {
@ -1736,7 +1776,7 @@ int xiocheckpeer(xiosingle_t *sfd,
#if HAVE_STRUCT_CMSGHDR
/* converts the ancillary message in *cmsg into a form useable for further
/* Converts the ancillary message in *cmsg into a form usable for further
processing. knows the specifics of common message types.
returns the number of resulting syntax elements in *num
returns a sequence of \0 terminated type strings in *typbuff
@ -1957,7 +1997,7 @@ int xioparserange(
return -1;
}
/* we have parsed the address and mask; now we make sure that the stored
address has 0 where mask is 0, to simplify comparisions */
address has 0 where mask is 0, to simplify comparisons */
switch (pf) {
#if WITH_IP4
case PF_INET:
@ -2055,15 +2095,12 @@ int xiosetsockaddrenv(const char *lr,
# undef XIOSOCKADDRENVLEN
}
#endif /* _WITH_SOCKET */
/* these do sockets internally */
/* These do sockets internally */
/* retrieves options so-type and so-prototype from opts, calls socket, and
ev. generates an appropriate error message.
returns 0 on success or -1 if an error occurred. */
int
xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
returns 0 on success or -1 (and errno) if an error occurred. */
int xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
int result;
retropt_int(opts, OPT_SO_TYPE, &socktype);
@ -2080,24 +2117,6 @@ xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
return result;
}
/* retrieves options so-type and so-prototype from opts, calls socketpair, and
ev. generates an appropriate error message.
returns 0 on success or -1 if an error occurred. */
int
xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
int result;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
result = Socketpair(pf, socktype, proto, sv);
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
pf, socktype, proto, sv, strerror(errno));
return -1;
}
return result;
}
/* Binds a socket to a socket address. Handles IP (internet protocol), UNIX
domain, Linux abstract UNIX domain.
The bind address us may be NULL in which case no bind() happens, except with
@ -2106,6 +2125,7 @@ xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
with IP sockets: lowport (selects randomly a free port from 640 to 1023)
with UNIX and abstract sockets: uses a method similar to tmpname() to
find a free file system entry.
On success returns STAT_OK, otherwise errno is set.
*/
int xiobind(
struct single *sfd,
@ -2142,18 +2162,20 @@ int xiobind(
usrname = strndup(us->un.sun_path, sizeof(us->un.sun_path));
if (usrname == NULL) {
int _errno = errno;
Error2("strndup(\"%s\", "F_Zu"): out of memory",
Msg2(level, "strndup(\"%s\", "F_Zu"): out of memory",
us->un.sun_path, sizeof(us->un.sun_path));
errno = _errno;
return -1;
return STAT_RETRYLATER;
}
}
do { /* loop over tempnam bind() attempts */
sockname = xio_tempnam(usrname, abstract);
if (sockname == NULL) {
int _errno = errno;
Error2("tempnam(\"%s\"): %s", usrname, strerror(errno));
free(usrname);
errno = _errno;
return -1;
}
strncpy(us->un.sun_path+(abstract?1:0), sockname, sizeof(us->un.sun_path));
@ -2167,8 +2189,10 @@ int xiobind(
infobuff, sizeof(infobuff)),
uslen, strerror(errno));
if (errno != EADDRINUSE) {
int _errno = errno;
free(usrname);
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
} else {
@ -2181,10 +2205,12 @@ int xiobind(
if (us != NULL) {
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
int _errno = errno;
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
@ -2206,8 +2232,12 @@ int xiobind(
if (us) {
sinp = us;
} else {
if (pf == AF_INET) {
if (0) {
;
#if WITH_IP4
} else if (pf == AF_INET) {
socket_in_init(&sin.ip4);
#endif
#if WITH_IP6
} else {
socket_in6_init(&sin.ip6);
@ -2252,12 +2282,14 @@ int xiobind(
do { /* loop over lowport bind() attempts */
*port = htons(i);
if (Bind(sfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
int _errno = errno;
Msg4(errno==EADDRINUSE?E_INFO:level,
"bind(%d, {%s}, "F_Zd"): %s", sfd->fd,
sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
sizeof(*sinp), strerror(errno));
if (errno != EADDRINUSE) {
if (_errno != EADDRINUSE) {
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
} else {
@ -2266,8 +2298,8 @@ int xiobind(
--i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
if (i == N) {
Msg(level, "no low port available");
/*errno = EADDRINUSE; still assigned */
Close(sfd->fd);
errno = EADDRINUSE;
return STAT_RETRYLATER;
}
} while (i != N);
@ -2278,24 +2310,26 @@ int xiobind(
if (us) {
applyopts(sfd, sfd->fd, opts, PH_BIND);
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
int _errno = errno;
Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
sfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
uslen, strerror(errno));
Close(sfd->fd);
errno = _errno;
return STAT_RETRYLATER;
}
}
}
applyopts(sfd, -1, opts, PH_PASTBIND);
return 0;
return STAT_OK;
}
/* Handles the SO_REUSEADDR socket option for TCP LISTEN addresses depending on
Socat option so-reuseaddr:
Option not applied: set it to 1
Option applied with a value: set it to the value
Option applied eith empty value "so-reuseaddr=": do not call setsockopt() for
Option applied with empty value "so-reuseaddr=": do not call setsockopt() for
SO_REUSEADDR
Return 0 on success, or -1 with errno when an error occurred.
*/
@ -2303,15 +2337,25 @@ int xiosock_reuseaddr(int fd, int ipproto, struct opt *opts)
{
union integral val;
union integral notnull;
int result;
int _errno;
val.u_int = 0;
notnull.u_bool = false;
#if WITH_TCP
if (ipproto == IPPROTO_TCP) {
val.u_int = 1;
notnull.u_bool = true;
}
retropt_2integrals(opts, OPT_SO_REUSEADDR, &val, &notnull);
#endif /* WITH_TCP */
result = retropt_2integrals(opts, OPT_SO_REUSEADDR, &val, &notnull);
#if WITH_TCP
if (ipproto == IPPROTO_TCP && result < 0) {
Info("Setting SO_REUSADDR on TCP listen socket implicitly");
val.u_int = 1;
notnull.u_bool = true;
}
#endif /* WITH_TCP */
if (notnull.u_bool) {
if (Setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val.u_int, sizeof(int))
!= 0) {
@ -2324,3 +2368,6 @@ int xiosock_reuseaddr(int fd, int ipproto, struct opt *opts)
}
return 0;
}
#endif /* _WITH_SOCKET */

View file

@ -83,6 +83,8 @@ extern const struct optdesc opt_setsockopt_bin;
extern const struct optdesc opt_setsockopt_string;
extern const struct optdesc opt_setsockopt_listen;
extern const struct optdesc opt_null_eof;
extern const struct optdesc opt_setsockopt_socket;
extern const struct optdesc opt_setsockopt_connected;
extern
@ -135,8 +137,6 @@ extern int xioparserange(const char *rangename, int pf, struct xiorange *range,
extern int
xiosocket(struct opt *opts, int pf, int socktype, int proto, int level);
extern int
xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]);
extern int xiosock_reuseaddr(int fd, int ipproto, struct opt *opts);
#endif /* !defined(__xio_socket_h_included) */

View file

@ -95,3 +95,26 @@ static int xioopen_socketpair(
}
#endif /* WITH_SOCKETPAIR */
#if _WITH_SOCKETPAIR
/* retrieves options so-type and so-prototype from opts, calls socketpair, and
ev. generates an appropriate error message.
returns 0 on success or -1 if an error occurred. */
int
xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
int result;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
result = Socketpair(pf, socktype, proto, sv);
if (result < 0) {
Error5("socketpair(%d, %d, %d, %p): %s",
pf, socktype, proto, sv, strerror(errno));
return -1;
}
return result;
}
#endif /* _WITH_SOCKETPAIR */

View file

@ -7,4 +7,6 @@
const extern struct addrdesc xioaddr_socketpair;
extern int xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]);
#endif /* !defined(__xio_socketpair_h_included) */

View file

@ -6,14 +6,16 @@
#include "xiosysincludes.h"
#if WITH_SOCKS4 || WITH_SOCKS4A
#include "xioopen.h"
#include "xio-ascii.h"
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ipapp.h"
#define SOCKSPORT "1080"
#if WITH_SOCKS4 || WITH_SOCKS4A
#include "xio-socks.h"
@ -24,7 +26,6 @@ enum {
SOCKS_CD_IDENTFAILED
} ;
#define SOCKSPORT "1080"
#define BUFF_LEN (SIZEOF_STRUCT_SOCKS4+512)
static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
@ -53,13 +54,12 @@ static int xioopen_socks4_connect(
int pf = PF_UNSPEC;
int ipproto = IPPROTO_TCP;
bool dofork = false;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo **themarr, *themp;
int i;
int maxchildren = 0;
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
bool needbind = false;
bool lowport = false;
char infobuff[256];
unsigned char buff[BUFF_LEN];
struct socks4 *sockhead = (struct socks4 *)buff;
size_t buflen = sizeof(buff);
@ -75,41 +75,43 @@ static int xioopen_socks4_connect(
targetname = argv[2];
targetport = argv[3];
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
applyopts(sfd, 1, opts, PH_INIT);
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_FORK, &dofork);
result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
/* Apply and retrieve some options */
result = _xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
result = _xioopen_socks4_init(targetport, opts, &socksport, sockhead,
&buflen);
if (result != STAT_OK)
return result;
opts0 = opts; /* save remaining options for each loop */
opts = NULL;
Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
targetname,
ntohs(sockhead->port),
targetname, ntohs(sockhead->port),
sockdname, socksport, sockhead->userid);
i = 0;
do { /* loop over retries (failed connect and socks-request attempts) */
do { /* loop over retries (failed connect and socks-request attempts)
and/or forks */
int _errno;
level = E_INFO;
#if WITH_RETRY
if (sfd->forever || sfd->retry) {
level = E_NOTICE;
} else
#endif /* WITH_RETRY */
level = E_WARN;
opts = copyopts(opts0, GROUP_ALL);
result =
_xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
&pf, ipproto,
_xioopen_ipapp_prepare(&opts, opts0, sockdname, socksport,
pf, socktype, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, us, &uslen,
&needbind, &lowport, socktype);
/* we try to resolve the target address _before_ connecting to the socks
server: this avoids unnecessary socks connects and timeouts */
result =
_xioopen_socks4_connect0(sfd, targetname, socks4a, sockhead,
(ssize_t *)&buflen, level);
&themarr, &bindarr, &bindport, &needbind, &lowport);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
@ -118,60 +120,78 @@ static int xioopen_socks4_connect(
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
default:
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
/* loop over themarr */
i = 0;
themp = themarr[i++];
while (themp != NULL) {
Notice1("opening connection to %s",
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
infobuff, sizeof(infobuff)));
#if WITH_RETRY
if (sfd->forever || sfd->retry || themarr[i] != NULL) {
level = E_INFO;
} else
#endif /* WITH_RETRY */
level = E_ERROR;
/* this cannot fork because we retrieved fork option above */
result =
_xioopen_connect(sfd,
needbind?us:NULL, uslen,
themp->ai_addr, themp->ai_addrlen,
opts, pf?pf:themp->ai_family, socktype, IPPROTO_TCP, lowport, level);
if (result == STAT_OK)
break;
themp = themarr[i++];
if (themp == NULL)
result = STAT_RETRYLATER;
}
/* we try to resolve the target address _before_ connecting to the socks
server: this may avoid unnecessary connects and timeouts */
result =
_xioopen_socks4_prepare(sfd, targetname, socks4a, sockhead,
(ssize_t *)&buflen, level);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry) {
--sfd->retry;
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
xiofreeaddrinfo(themarr);
applyopts(sfd, -1, opts, PH_ALL);
if ((result = _xio_openlate(sfd, opts)) < 0)
Notice2("opening connection to sockd %s:%s", sockdname, socksport);
result =
_xioopen_ipapp_connect(sfd, sockdname, opts, themarr,
needbind, bindarr, bindport, lowport, level);
_errno = errno;
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
errno = _errno;
Error4("%s:%s:...,socksport=%s: %s", argv[0], sockdname, socksport,
_errno?strerror(_errno):"(See above)");
freeopts(opts0);
freeopts(opts);
return result;
}
result = _xioopen_socks4_connect(sfd, sockhead, buflen, level);
switch (result) {
@ -180,11 +200,16 @@ static int xioopen_socks4_connect(
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
freeopts(opts);
freeopts(opts0);
return result;
}
@ -201,10 +226,13 @@ static int xioopen_socks4_connect(
so Notice is too weak */
}
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
if (sfd->forever || --sfd->retry) {
if (sfd->forever || sfd->retry--) {
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
freeopts(opts);
freeopts(opts0);
return STAT_RETRYLATER;
}
@ -216,8 +244,13 @@ static int xioopen_socks4_connect(
/* parent process */
Close(sfd->fd);
/* with and without retry */
Nanosleep(&sfd->intervall, NULL);
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
while (maxchildren > 0 && num_child >= maxchildren) {
Info1("all %d allowed children are active, waiting", maxchildren);
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
} else
#endif /* WITH_RETRY */
@ -226,9 +259,19 @@ static int xioopen_socks4_connect(
}
} while (true); /* end of complete open loop - drop out on success */
return 0;
/* only "active" process breaks (master without fork, or child) */
Notice4("successfully connected to %s:%s via sockd %s:%s",
targetname, targetport, sockdname, socksport);
result = _xio_openlate(sfd, opts);
freeopts(opts);
freeopts(opts0);
return result;
}
#endif /* WITH_SOCKS4 || WITH_SOCKS4A */
#if WITH_SOCKS4 || WITH_SOCKS4A || WITH_SOCKS5
int _xioopen_opt_socksport(
struct opt *opts,
@ -236,7 +279,8 @@ int _xioopen_opt_socksport(
{
struct servent *se;
if (retropt_string(opts, OPT_SOCKSPORT, socksport) < 0) {
if (retropt_string(opts, OPT_SOCKSPORT, socksport) < 0 &&
*socksport == NULL) {
if ((se = getservbyname("socks", "tcp")) != NULL) {
Debug1("\"socks/tcp\" resolves to %u", ntohs(se->s_port));
if ((*socksport = Malloc(6)) == NULL) {
@ -253,8 +297,16 @@ int _xioopen_opt_socksport(
return 0;
}
#endif /* WITH_SOCKS4 || WITH_SOCKS4A || WITH_SOCKS5 */
#if WITH_SOCKS4 || WITH_SOCKS4A
int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen) {
int _xioopen_socks4_init(
const char *targetport,
struct opt *opts,
char **socksport,
struct socks4 *sockhead,
size_t *headlen)
{
char *userid;
/* generate socks header - points to final target */
@ -280,14 +332,14 @@ int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **soc
/* called within retry/fork loop, before connect() */
int
_xioopen_socks4_connect0(struct single *sfd,
const char *hostname, /* socks target host */
int socks4a,
struct socks4 *sockhead,
ssize_t *headlen, /* get available space,
return used length*/
int level) {
int _xioopen_socks4_prepare(
struct single *sfd,
const char *hostname, /* socks target host */
int socks4a,
struct socks4 *sockhead,
ssize_t *headlen, /* get available space, return used length*/
int level)
{
int result;
if (!socks4a) {
@ -364,7 +416,7 @@ int _xioopen_socks4_connect(struct single *sfd,
}
}
#endif /* WITH_MSGLEVEL <= E_DEBUG */
if (writefull(sfd->fd, sockhead, headlen) < 0) {
if (writefull(sfd->fd, sockhead, headlen, NULL) < 0) {
Msg4(level, "write(%d, %p, "F_Zu"): %s",
sfd->fd, sockhead, headlen, strerror(errno));
if (Close(sfd->fd) < 0) {
@ -429,16 +481,7 @@ int _xioopen_socks4_connect(struct single *sfd,
switch (replyhead->action) {
case SOCKS_CD_GRANTED:
/* Notice("socks: connect request succeeded"); */
#if 0
if (Getsockname(sfd->fd, (struct sockaddr *)&us, &uslen) < 0) {
Warn4("getsockname(%d, %p, {%d}): %s",
sfd->fd, &us, uslen, strerror(errno));
}
Notice1("successfully connected from %s via socks4",
sockaddr_info((struct sockaddr *)&us, infobuff, sizeof(infobuff)));
#else
Notice("successfully connected via socks4");
#endif
break;
case SOCKS_CD_FAILED:

View file

@ -10,9 +10,9 @@ struct socks4 {
uint8_t action;
uint16_t port;
uint32_t dest;
char userid[1]; /* just to have access via this struct */
char userid[0]; /* just to have access via this struct */
} ;
#define SIZEOF_STRUCT_SOCKS4 8
#define SIZEOF_STRUCT_SOCKS4 ((size_t)&((struct socks4 *)0)->userid)
extern const struct optdesc opt_socksport;
extern const struct optdesc opt_socksuser;
@ -21,15 +21,8 @@ extern const struct addrdesc xioaddr_socks4_connect;
extern const struct addrdesc xioaddr_socks4a_connect;
extern int _xioopen_opt_socksport(struct opt *opts, char **socksport);
extern int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
extern int
_xioopen_socks4_connect0(struct single *xfd,
const char *hostname, /* socks target host */
int socks4a,
struct socks4 *sockhead,
ssize_t *headlen, /* get available space,
return used length*/
int level);
extern int _xioopen_socks4_init(const char *targetport, struct opt *opts, char **socksport, struct socks4 *sockhead, size_t *headlen);
extern int _xioopen_socks4_prepare(struct single *xfd, const char *hostname, int socks4a, struct socks4 *sockhead, ssize_t *headlen, int level);
extern int _xioopen_socks4_connect(struct single *xfd,
struct socks4 *sockhead,
size_t headlen,

View file

@ -53,7 +53,7 @@ static int xioopen_socks5(int argc, const char *argv[], struct opt *opts, int xi
const struct addrdesc xioaddr_socks5_connect = { "SOCKS5-CONNECT", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_CONNECT, 0, 0 HELP(":<socks-server>[:<socks-port>]:<target-host>:<target-port>") };
const struct addrdesc xioaddr_socks5_listen = { "SOCKS5-LISTEN", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_BIND, 0, 0 HELP(":<socks-server>[:<socks-port>]:<listen-host>:<listen-port>") };
const struct addrdesc xioaddr_socks5_listen = { "SOCKS5-LISTEN", 1+XIO_RDWR, xioopen_socks5, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, SOCKS5_COMMAND_BIND, 0, 0 HELP(":<socks-server>[:<socks-port>]:<listen-host>:<listen-port>") };
static const char * _xioopen_socks5_strerror(uint8_t r)
{
@ -136,7 +136,7 @@ static int _xioopen_socks5_handshake(struct single *sfd, int level)
}
#endif
if (writefull(sfd->fd, client_hello, client_hello_size) < 0) {
if (writefull(sfd->fd, client_hello, client_hello_size, NULL) < 0) {
Msg4(level, "write(%d, %p, %d): %s",
sfd->fd, client_hello, client_hello_size,
strerror(errno));
@ -188,6 +188,8 @@ static int _xioopen_socks5_handshake(struct single *sfd, int level)
return STAT_RETRYLATER;
}
Debug2("received SOCKS5 server hello %02x %02x",
server_hello_ptr[0], server_hello_ptr[1]);
Info2("received SOCKS5 server hello version=%d method=%d",
server_hello.version,
server_hello.method);
@ -332,6 +334,12 @@ static int _xioopen_socks5_read_reply(
}
return STAT_RETRYLATER;
}
Debug5("received SOCKS5 reply %02x %02x %02x %02x %02x",
((unsigned char *)reply+bytes_read)[0],
((unsigned char *)reply+bytes_read)[1],
((unsigned char *)reply+bytes_read)[2],
((unsigned char *)reply+bytes_read)[3],
((unsigned char *)reply+bytes_read)[4]);
bytes_read += result;
/* Once we've read 5 bytes, figure out total message length and
@ -418,7 +426,7 @@ static int _xioopen_socks5_request(
}
#endif
if (writefull(sfd->fd, req, bytes) < 0) {
if (writefull(sfd->fd, req, bytes, NULL) < 0) {
Msg4(level, "write(%d, %p, %d): %s",
sfd->fd, req, bytes, strerror(errno));
if (Close(sfd->fd) < 0) {
@ -504,6 +512,7 @@ static int xioopen_socks5(
{
int socks_command = addrdesc->arg1;
bool dofork = false;
int maxchildren = 0;
int socktype = SOCK_STREAM;
int pf = PF_UNSPEC;
int ipproto = IPPROTO_TCP;
@ -511,17 +520,12 @@ static int xioopen_socks5(
struct opt *opts0 = NULL;
struct single *sfd = &xxfd->stream;
const char *socks_server, *target_name, *target_port, *socks_port;
union sockaddr_union us_sa, *us = &us_sa;
socklen_t uslen = sizeof(us_sa);
struct addrinfo **themarr, *themp;
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
bool needbind = false;
bool lowport = false;
char infobuff[256];
if (!xioparms.experimental) {
Error1("%s: use option --experimental to acknowledge unmature state", argv[0]);
return STAT_NORETRY;
}
if (argc < 4 || argc > 5) {
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
return STAT_NORETRY;
@ -533,78 +537,120 @@ static int xioopen_socks5(
target_name = argv[3];
target_port = argv[4];
} else {
socks_port = NULL;
target_name = argv[2];
target_port = argv[3];
}
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
applyopts(sfd, -1, opts, PH_INIT);
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_FORK, &dofork);
/* Apply and retrieve some options */
result = _xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
if (_xioopen_opt_socksport(opts, (char **)&socks_port) < 0) {
return STAT_NORETRY;
}
/*! possible memory leak */
result = _xioopen_ipapp_prepare(opts, &opts0, socks_server, socks_port,
&pf, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, us, &uslen,
&needbind, &lowport, socktype);
opts0 = opts;
opts = NULL;
Notice2("connecting to socks5 server %s:%s",
socks_server, socks_port);
Notice4("opening connection to %s:%s vis socks5 server %s:%s",
target_name, target_port, socks_server, socks_port);
do {
do { /* loop over retries (failed connect and socks-request attempts)
and/or forks */
int _errno;
#if WITH_RETRY
if (sfd->forever || sfd->retry) {
level = E_INFO;
} else {
level = E_ERROR;
}
level = E_NOTICE;
} else
#endif
level = E_WARN;
/* loop over themarr */
themp = themarr[0];
while (themp != NULL) {
Notice1("opening connection to %s",
sockaddr_info(themp->ai_addr, themp->ai_addrlen,
infobuff, sizeof(infobuff)));
result = _xioopen_connect(sfd, needbind?us:NULL, sizeof(*us),
themp->ai_addr, themp->ai_addrlen,
opts, pf?pf:themp->ai_family, socktype,
IPPROTO_TCP, lowport, level);
if (result == STAT_OK)
break;
themp = themp->ai_next;
if (themp == NULL)
result = STAT_RETRYLATER;
opts = copyopts(opts0, GROUP_ALL);
switch(result){
break;
result =
_xioopen_ipapp_prepare(&opts, opts0, socks_server, socks_port,
pf, socktype, ipproto,
sfd->para.socket.ip.ai_flags,
&themarr, &bindarr, &bindport, &needbind,
&lowport);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry-- ) {
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
continue;
}
#endif
default:
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
return result;
freeopts(opts);
continue;
}
}
xiofreeaddrinfo(themarr);
applyopts(sfd, -1, opts, PH_ALL);
if ((result = _xio_openlate(sfd, opts)) < 0)
#endif /* WITH_RETRY */
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
if ((result = _xioopen_socks5_handshake(sfd, level)) != STAT_OK) {
Notice2("opening connection to socks5 server %s:%s",
socks_server, socks_port);
result =
_xioopen_ipapp_connect(sfd, socks_server, opts, themarr,
needbind, bindarr, bindport, lowport, level);
_errno = errno;
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
Error4("%s:%s:%s:...: %s",
argv[0], socks_server, socks_port,
_errno?strerror(_errno):"(See above)");
freeopts(opts0);
freeopts(opts);
return result;
}
result = _xioopen_socks5_handshake(sfd, level);
switch (result) {
case STAT_OK: break;
#if WITH_RETRY
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if (sfd->forever || sfd->retry--) {
if (result == STAT_RETRYLATER) {
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
}
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
Error3("%s:%s:%s: Connection failed", argv[0], socks_server, socks_port);
freeopts(opts0);
freeopts(opts);
return result;
}
@ -616,11 +662,16 @@ static int xioopen_socks5(
case STAT_RETRYLATER:
case STAT_RETRYNOW:
if ( sfd->forever || sfd->retry-- ) {
if (result == STAT_RETRYLATER) Nanosleep(&sfd->intervall, NULL);
if (result == STAT_RETRYLATER)
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
#endif
#endif /* WITH_RETRY */
/* FALLTHROUGH */
default:
freeopts(opts);
freeopts(opts0);
return result;
}
@ -636,12 +687,18 @@ static int xioopen_socks5(
level = E_WARN;
}
while ((pid = xio_fork(false, level, sfd->shutup)) < 0) {
if (sfd->forever || --sfd->retry) {
if (sfd->forever || sfd->retry) {
if (sfd->retry > 0)
--sfd->retry;
Nanosleep(&sfd->intervall, NULL);
freeopts(opts);
continue;
}
freeopts(opts);
freeopts(opts0);
return STAT_RETRYLATER;
}
if ( pid == 0 ) {
sfd->forever = false;
sfd->retry = 0;
@ -650,17 +707,26 @@ static int xioopen_socks5(
Close(sfd->fd);
Nanosleep(&sfd->intervall, NULL);
dropopts(opts, PH_ALL);
opts = copyopts(opts0, GROUP_ALL);
while (maxchildren > 0 && num_child >= maxchildren) {
Info1("all %d allowed children are active, waiting", maxchildren);
Nanosleep(&sfd->intervall, NULL);
}
freeopts(opts);
continue;
} else
#endif
#endif /* WITH_RETRY */
{
break;
}
} while (true);
return 0;
Notice4("successfully connected to %s:%s via socks5 server %s:%s",
target_name, target_port, socks_server, socks_port);
result = _xio_openlate(sfd, opts);
freeopts(opts);
freeopts(opts0);
return STAT_OK;
}
#endif /* WITH_SOCKS5 */

View file

@ -17,7 +17,7 @@ static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xio
static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
/* we specify all option groups that we can imagine for a FD, becasue the
/* We specify all option groups that we can imagine for a FD, because the
changed parsing mechanism does not allow us to check the type of FD before
applying the options */
const struct addrdesc xioaddr_stdio = { "STDIO", 3, xioopen_stdio, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) };

View file

@ -65,7 +65,7 @@ void dummy(void) {
#else /* !defined(ENABLE_APPLYOPT) */
#include "xiosysincludes.h"
#if WITH_STREAMS /* make this address configure dependend */
#if WITH_STREAMS /* make this address configure dependent */
#include "xioopen.h"
#include "xio-fd.h"

View file

@ -79,7 +79,7 @@ int xio_retropt_tcpwrap(
}
/* returns -1 if forbidden, 0 if no tcpwrap check, or 1 if explicitely allowed
/* Returns -1 if forbidden, 0 if no tcpwrap check, or 1 if explicitly allowed
*/
int xio_tcpwrap_check(
struct single *sfd,

View file

@ -501,7 +501,7 @@ int xiotermios_spec(int fd, int optcode) {
#if HAVE_CFMAKERAW
cfmakeraw(&_xiotermios_data.termarg);
#else
/* these setting follow the Linux documenation of cfmakeraw */
/* These settings follow the Linux documentation of cfmakeraw */
_xiotermios_data.termarg.c_iflag &=
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
_xiotermios_data.termarg.c_oflag &= ~(OPOST);

View file

@ -120,7 +120,7 @@ static int xioopen_tun(
if (retropt_bool(opts, OPT_IFF_NO_PI, &no_pi) == 0) {
if (no_pi) {
ifr.ifr_flags |= IFF_NO_PI;
#if 0 /* not neccessary for now */
#if 0 /* not necessary for now */
} else {
ifr.ifr_flags &= ~IFF_NO_PI;
#endif
@ -139,7 +139,7 @@ static int xioopen_tun(
/* we seem to need a socket for manipulating the interface */
if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
sockfd = sfd->fd; /* desparate fallback attempt */
sockfd = sfd->fd; /* desperate fallback attempt */
}
/*--------------------- setting interface address and netmask ------------*/

View file

@ -85,7 +85,7 @@ int _xioopen_ipdgram_listen(struct single *sfd,
return STAT_NORETRY;
}
#if WITH_IP4 /*|| WITH_IP6*/
#if WITH_IP4 || WITH_IP6
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, pf, &sfd->para.socket.range,
sfd->para.socket.ip.ai_flags)
@ -277,8 +277,10 @@ int xioopen_ipdgram_listen(
int pf = addrdesc->arg1;
int ipproto = addrdesc->arg2;
union sockaddr_union us;
int bind_rc;
int socktype = SOCK_DGRAM;
socklen_t uslen;
int result;
if (argc != 2) {
xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
@ -295,12 +297,31 @@ int xioopen_ipdgram_listen(
applyopts(sfd, -1, opts, PH_INIT);
uslen = socket_init(pf, &us);
retropt_bind(opts, pf, socktype, ipproto,
bind_rc = retropt_bind(opts, pf, socktype, ipproto,
(struct sockaddr *)&us, &uslen, 1,
xfd->stream.para.socket.ip.ai_flags);
if (bind_rc == STAT_NORETRY)
return STAT_NORETRY;
if (pf == PF_UNSPEC && bind_rc == STAT_OK)
pf = us.soa.sa_family;
if (false) {
;
#if WITH_IP4 || WITH_IP6
} else if (pf == PF_UNSPEC && bind_rc == STAT_NOACTION) {
int ai_flags[2];
ai_flags[0] = sfd->para.socket.ip.ai_flags[0];
ai_flags[1] = sfd->para.socket.ip.ai_flags[1];
if (!(ai_flags[1] & AI_PASSIVE))
ai_flags[0] |= AI_PASSIVE;
result =
xioresolve(NULL, portname, pf, socktype, ipproto, &us, &uslen, ai_flags);
if (result != STAT_OK) {
Error("error resolving bind option");
return STAT_NORETRY;
}
pf = us.soa.sa_family;
#endif /* WITH_IP4 || WITH_IP6*/
#if WITH_IP4
} else if (pf == PF_INET) {
us.ip4.sin_port = parseport(portname, ipproto);
@ -349,7 +370,7 @@ int xioopen_udp_sendto(
applies and consumes the following option:
PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
OFUNC_OFFSET
OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_O_CLOEXEC
*/
int _xioopen_udp_sendto(const char *hostname, const char *servname,
struct opt *opts,
@ -529,7 +550,7 @@ int xioopen_udp_recvfrom(
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_NONE;
/* Set AI_PASSIVE, except when it is explicitely disabled */
/* Set AI_PASSIVE, except when it is explicitly disabled */
ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0];
ai_flags2[1] = xfd->stream.para.socket.ip.ai_flags[1];
if (!(ai_flags2[1] & AI_PASSIVE))
@ -605,7 +626,7 @@ int xioopen_udp_recv(
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf);
/* Set AI_PASSIVE, except when it is explicitely disabled */
/* Set AI_PASSIVE, except when it is explicitly disabled */
ai_flags2[0] = xfd->stream.para.socket.ip.ai_flags[0];
ai_flags2[1] = xfd->stream.para.socket.ip.ai_flags[1];
if (!(ai_flags2[1] & AI_PASSIVE))
@ -646,7 +667,7 @@ int xioopen_udp_recv(
}
#endif
#if WITH_IP4 /*|| WITH_IP6*/
#if WITH_IP4 || WITH_IP6
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
if (xioparserange(rangename, pf, &xfd->stream.para.socket.range,
xfd->stream.para.socket.ip.ai_flags)

View file

@ -15,7 +15,7 @@
#if WITH_UNIX
/* to avoid unneccessary runtime if () conditionals when no abstract support is
/* To avoid unnecessary 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
@ -33,7 +33,7 @@ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, i
/* the first free parameter is 0 for "normal" unix domain sockets, or 1 for
abstract unix sockets (Linux); the second and third free parameter are
unsused */
unused */
const struct addrdesc xioaddr_unix_connect = { "UNIX-CONNECT", 1+XIO_RDWR, xioopen_unix_connect, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
#if WITH_LISTEN
const struct addrdesc xioaddr_unix_listen = { "UNIX-LISTEN", 1+XIO_RDWR, xioopen_unix_listen, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<filename>") };
@ -123,6 +123,7 @@ static int xioopen_unix_listen(
/* we expect the form: filename */
const char *name;
xiosingle_t *sfd = &xxfd->stream;
char *bindstring = NULL;
int pf = PF_UNIX;
int socktype = SOCK_STREAM;
int protocol = 0;
@ -140,6 +141,12 @@ static int xioopen_unix_listen(
}
name = argv[1];
if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
Error2("%s:%s: binds implicitly, bind option not allowed",
addrdesc->defname, argv[1]);
free(bindstring);
}
sfd->para.socket.un.tight = UNIX_TIGHTSOCKLEN;
retropt_socket_pf(opts, &pf);
if (sfd->howtoend == END_UNSPEC)
@ -257,7 +264,12 @@ static int xioopen_unix_connect(
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
(addrdesc->arg1/*abstract*/<<1)|sfd->para.socket.un.tight,
sfd->para.socket.ip.ai_flags)
#if WITH_TCP
sfd->para.socket.ip.ai_flags
#else
0
#endif /* WITH_TCP */
)
== STAT_OK) {
needbind = true;
}
@ -426,7 +438,12 @@ static int xioopen_unix_sendto(
if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen,
(addrdesc->arg1/*abstract*/<<1)| sfd->para.socket.un.tight,
sfd->para.socket.ip.ai_flags)
#if WITH_TCP
sfd->para.socket.ip.ai_flags
#else
0
#endif /* WITH_TCP */
)
== STAT_OK) {
needbind = true;
}
@ -665,7 +682,7 @@ static int xioopen_unix_client(
PH_CONNECTED, PH_LATE, ?PH_CONNECT
OFUNC_OFFSET,
OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND,
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_O_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK,
*/
int
_xioopen_unix_client(
@ -709,7 +726,12 @@ _xioopen_unix_client(
if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen,
(abstract<<1)|sfd->para.socket.un.tight,
sfd->para.socket.ip.ai_flags)
#if WITH_TCP
sfd->para.socket.ip.ai_flags
#else
0
#endif /* WITH_TCP */
)
!= STAT_NOACTION) {
needbind = true;
}
@ -773,7 +795,7 @@ _xioopen_unix_client(
opts, pf, SOCK_SEQPACKET, protocol,
needtemp, E_INFO)) == 0)
break;
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/
if (errno != EPROTOTYPE && errno != EPROTONOSUPPORT/*AIX*/ && errno != ESOCKTNOSUPPORT/*Debian3*/
#if WITH_ABSTRACT_UNIXSOCKET
&& !(abstract && errno == ECONNREFUSED)
#endif

View file

@ -98,7 +98,7 @@ static int xioopen_vsock_connect(
ret = retropt_bind(opts, pf, socktype, protocol,
(struct sockaddr *)&sa_local, &sa_len, 3,
sfd->para.socket.ip.ai_flags);
NULL);
if (ret == STAT_NORETRY)
return ret;
if (ret == STAT_OK)

3
xio.h
View file

@ -120,12 +120,13 @@ typedef struct xioparms {
const char *sniffleft_name; /* file name with -r */
const char *sniffright_name; /* file name with -R */
size_t bufsiz;
struct timeval total_timeout;/* when nothing happens, die after seconds */
} xioparms_t;
/* pack the description of a lock file */
typedef struct {
const char *lockfile; /* name of lockfile; NULL if no locking */
bool waitlock; /* dont't exit when already locked */
bool waitlock; /* don't exit when already locked */
struct timespec intervall; /* polling intervall */
} xiolock_t;

View file

@ -16,7 +16,13 @@
# define WITH_OPEN 1
#endif
#if WITH_OPEN || WITH_PIPE || WITH_UNIX || WITH_PTY
#if WITH_INTERFACE || WITH_TUN
# define _WITH_INTERFACE 1
#else
# define _WITH_INTERFACE 0
#endif
#if WITH_OPEN || WITH_PIPE || WITH_UNIX || WITH_PTY || _WITH_INTERFACE
# define WITH_NAMED 1
#endif
@ -34,7 +40,7 @@
with IP6 */
#endif
#if WITH_OPENSSL
#if WITH_OPENSSL || WITH_SOCKS5
# define WITH_TCP 1
# define WITH_IP4 1
#endif
@ -57,7 +63,7 @@
# define _WITH_UDP 1
#endif
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_RAWIP || WITH_GENERICSOCKET
#if WITH_UNIX || WITH_IP4 || WITH_IP6 || WITH_SOCKS4 || WITH_SOCKS5 || WITH_RAWIP || WITH_GENERICSOCKET || WITH_SOCKETPAIR || WITH_VSOCK
# define _WITH_SOCKET 1
#else
# undef _WITH_SOCKET
@ -71,10 +77,8 @@
# undef WITH_LIBWRAP
#endif
#if WITH_INTERFACE || WITH_TUN
# define _WITH_INTERFACE 1
#else
# define _WITH_INTERFACE 0
#if WITH_SOCKETPAIR || WITH_EXEC || WITH_SYSTEM || WITH_SHELL
# define _WITH_SOCKETPAIR 1
#endif
#if WITH_GENERICSOCKET || _WITH_INTERFACE

View file

@ -53,7 +53,7 @@ static const char *addressgroupnames[] = {
/* keep consistent with xioopts.h:enum ephase ! */
static char *optionphasenames[] = {
"ALL", "INIT", "EARLY",
"ALL", "OFFSET", "INIT", "EARLY",
"PREOPEN", "OPEN", "PASTOPEN",
"PRESOCKET", "SOCKET", "PASTSOCKET",
"PREBIGEN", "BIGEN", "PASTBIGEN",
@ -87,6 +87,8 @@ static int xiohelp_option(FILE *of, const struct optname *on, const char *name)
groups = on->desc->group;
occurred = false;
chars = 7;
if (groups == 0)
fputs("(all)", of);
for (j = 0; j < 8*sizeof(groups_t); ++j) {
if (groups & 1) {
if (occurred) {
@ -150,8 +152,9 @@ int xioopenhelp(FILE *of,
i = (40 - chars + 7) / 8;
for (; i > 0; --i) { fputc('\t', of); }
fputs("\tgroups=", of);
groups = an->desc->groups; occurred = false;
for (j = 0; j < 32; ++j) {
groups = an->desc->groups;
occurred = false;
for (j = 0; j < sizeof(groups_t)*8; ++j) {
if (groups & 1) {
if (occurred) { fputc(',', of); }
fprintf(of, "%s", addressgroupnames[j]);

View file

@ -175,8 +175,8 @@ static int xio_nokill(xiofile_t *sock) {
return result;
}
/* call this function immediately after fork() in child process */
/* it performs some neccessary actions
/* Call this function immediately after fork() in child process */
/* It performs some necessary actions
returns 0 on success or != 0 if an error occurred */
int xio_forked_inchild(void) {
int result = 0;

View file

@ -48,7 +48,8 @@ int xio_chdir(
free(tmp_dir);
return -1;
}
*orig_dir = Realloc(*orig_dir, strlen(*orig_dir)+1);
/*0 *orig_dir = Realloc(*orig_dir, strlen(*orig_dir)+1); */
*orig_dir = Realloc3(*orig_dir, strlen(*orig_dir)+1, PATH_MAX);
if (Chdir(tmp_dir) < 0) {
Error2("chdir(\"%s\"): %s", tmp_dir, strerror(errno));

View file

@ -52,7 +52,7 @@ int xiogetlock(const char *lockfile) {
pid = Getpid();
bytes = sprintf(pidbuf, F_pid"\n", pid);
if (writefull(fd, pidbuf, bytes) < 0) {
if (writefull(fd, pidbuf, bytes, NULL) < 0) {
Error4("write(%d, %p, "F_Zu"): %s", fd, pidbuf, bytes, strerror(errno));
return -1;
}

View file

@ -177,11 +177,13 @@ const struct addrname addressnames[] = {
{ "PIPE", &xioaddr_pipe },
#endif
#if WITH_POSIXMQ
{ "POSIXMQ", &xioaddr_posixmq_bidir },
{ "POSIXMQ-BIDIRECTIONAL", &xioaddr_posixmq_bidir },
{ "POSIXMQ-READ", &xioaddr_posixmq_read },
{ "POSIXMQ-RECEIVE", &xioaddr_posixmq_receive },
{ "POSIXMQ-RECV", &xioaddr_posixmq_receive },
{ "POSIXMQ-SEND", &xioaddr_posixmq_send },
{ "POSIXMQ-WRITE", &xioaddr_posixmq_write },
#endif
#if WITH_PROXY
{ "PROXY", &xioaddr_proxy_connect },
@ -471,14 +473,14 @@ static xiofile_t *xioallocfd(void) {
fd->stream.escape = -1;
/* fd->stream.para.exec.pid = 0; */
fd->stream.lineterm = LINETERM_RAW;
#if WITH_RESOLVE
#if ( _WITH_IP4 || _WITH_IP6 ) && WITH_RESOLVE
#if HAVE_RES_RETRANS
fd->stream.para.socket.ip.res.retrans = -1;
#endif
#if HAVE_RES_RETRY
fd->stream.para.socket.ip.res.retry = -1;
#endif
#endif /* WITH_RESOLVE */
#endif /* ( _WITH_IP4 || _WITH_IP6 ) && WITH_RESOLVE */
return fd;
}
@ -701,10 +703,10 @@ int xioopen_single(xiofile_t *xfd, int xioflags) {
mode_t orig_umask, tmp_umask;
int result;
/* Values to be saved until xioopen() is finished */
#if WITH_RESOLVE && HAVE_RESOLV_H
#if ( _WITH_IP4 || _WITH_IP6 ) && WITH_RESOLVE && HAVE_RESOLV_H
int do_res;
struct __res_state save_res;
#endif /* WITH_RESOLVE && HAVE_RESOLV_H */
#endif
#if WITH_NAMESPACES
int save_netfd = -1;
#endif
@ -730,15 +732,15 @@ int xioopen_single(xiofile_t *xfd, int xioflags) {
if (applyopts_single(sfd, sfd->opts, PH_OFFSET) < 0)
return -1;
#if WITH_NAMESPACES
#if WITH_NAMESPACES /* netns */
if ((save_netfd = xio_apply_namespace(sfd->opts)) < 0)
return -1;
#endif /* WITH_NAMESPACES */
#if WITH_RESOLVE && HAVE_RESOLV_H
#if ( _WITH_IP4 || _WITH_IP6 ) && WITH_RESOLVE && HAVE_RESOLV_H
if ((do_res = xio_res_init(sfd, &save_res)) < 0)
return STAT_NORETRY;
#endif /* WITH_RESOLVE && HAVE_RESOLV_H */
#endif
if (xio_chdir(sfd->opts, &orig_dir) < 0)
return STAT_NORETRY;
@ -769,10 +771,10 @@ int xioopen_single(xiofile_t *xfd, int xioflags) {
free(orig_dir);
}
#if WITH_RESOLVE && HAVE_RESOLV_H
#if ( _WITH_IP4 || _WITH_IP6 ) && WITH_RESOLVE && HAVE_RESOLV_H
if (do_res)
xio_res_restore(&save_res);
#endif /* WITH_RESOLVE && HAVE_RESOLV_H */
#endif
#if WITH_NAMESPACES
if (save_netfd > 0) {

121
xioopts.c
View file

@ -177,7 +177,7 @@ static int applyopt(struct single *sfd, int fd, struct opt *opt);
binary search! */
/* NULL terminated */
const struct optname optionnames[] = {
#if HAVE_RESOLV_H && WITH_RES_AAONLY
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H && WITH_RES_AAONLY
IF_RESOLVE("aaonly", &opt_res_aaonly)
#endif
#ifdef TCP_ABORT_THRESHOLD /* HP_UX */
@ -352,7 +352,7 @@ const struct optname optionnames[] = {
#endif /* SO_CKSUMRECV */
/*IF_NAMED ("cleanup", &opt_cleanup)*/
IF_TERMIOS("clocal", &opt_clocal)
IF_ANY ("cloexec", &opt_cloexec)
IF_ANY ("cloexec", &opt_cloexec)
IF_ANY ("close", &opt_end_close)
IF_OPENSSL("cn", &opt_openssl_commonname)
IF_OPENSSL("commonname", &opt_openssl_commonname)
@ -390,8 +390,8 @@ const struct optname optionnames[] = {
# endif
#endif /* defined(CRDLY) */
IF_TERMIOS("cread", &opt_cread)
IF_OPEN ("creat", &opt_o_create)
IF_OPEN ("create", &opt_o_create)
IF_OPEN ("creat", &opt_o_creat)
IF_OPEN ("create", &opt_o_creat)
IF_ANY ("crlf", &opt_crnl)
IF_ANY ("crnl", &opt_crnl)
IF_TERMIOS("crterase", &opt_echoe)
@ -421,7 +421,7 @@ const struct optname optionnames[] = {
#ifdef TCP_DEFER_ACCEPT /* Linux 2.4.0 */
IF_TCP ("defer-accept", &opt_tcp_defer_accept)
#endif
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("defnames", &opt_res_defnames)
#endif /* HAVE_RESOLV_H */
#ifdef O_DELAY
@ -454,10 +454,10 @@ const struct optname optionnames[] = {
#ifdef VDISCARD
IF_TERMIOS("discard", &opt_vdiscard)
#endif
#if WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
#if (WITH_IP4 || WITH_IP6) && WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
IF_IP ("dns", &opt_res_nsaddr)
#endif
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("dnsrch", &opt_res_dnsrch)
#endif /* HAVE_RESOLV_H */
#ifdef SO_DONTLINGER
@ -721,7 +721,7 @@ const struct optname optionnames[] = {
IF_ANY ("ignoreeof", &opt_ignoreeof)
IF_ANY ("ignoreof", &opt_ignoreeof)
IF_TERMIOS("ignpar", &opt_ignpar)
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("igntc", &opt_res_igntc)
#endif /* HAVE_RESOLV_H */
IF_TERMIOS("imaxbel", &opt_imaxbel)
@ -1032,7 +1032,10 @@ const struct optname optionnames[] = {
#endif
IF_ANY ("mode", &opt_perm)
#if WITH_POSIXMQ
IF_ANY ("mq-prio", &opt_posixmq_priority)
IF_ANY ("mq-flush", &opt_posixmq_flush)
IF_ANY ("mq-maxmsg", &opt_posixmq_maxmsg)
IF_ANY ("mq-msgsize", &opt_posixmq_msgsize)
IF_ANY ("mq-prio", &opt_posixmq_priority)
#endif
#ifdef TCP_MAXSEG
IF_TCP ("mss", &opt_tcp_maxseg)
@ -1050,7 +1053,7 @@ const struct optname optionnames[] = {
IF_IP ("multicast-ttl", &opt_ip_multicast_ttl)
IF_IP ("multicastloop", &opt_ip_multicast_loop)
IF_IP ("multicastttl", &opt_ip_multicast_ttl)
#if WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
#if (WITH_IP4 || WITH_IP6) && WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
IF_IP ("nameserver", &opt_res_nsaddr)
#endif
#if defined(O_NDELAY) && (!defined(O_NONBLOCK) || O_NDELAY != O_NONBLOCK)
@ -1118,7 +1121,7 @@ const struct optname optionnames[] = {
IF_OPENSSL("nosni", &opt_openssl_no_sni)
#endif
IF_INTERFACE("notrailers", &opt_iff_notrailers)
#if WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
#if (WITH_IP4 || WITH_IP6) && WITH_RESOLVE && HAVE_RESOLV_H && HAVE_RES_NSADDR_LIST
IF_IP ("nsaddr", &opt_res_nsaddr)
#endif
#ifdef O_NSHARE
@ -1132,8 +1135,8 @@ const struct optname optionnames[] = {
#ifdef O_BINARY
IF_OPEN ("o-binary", &opt_o_binary)
#endif
IF_OPEN ("o-creat", &opt_o_create)
IF_OPEN ("o-create", &opt_o_create)
IF_OPEN ("o-creat", &opt_o_creat)
IF_OPEN ("o-create", &opt_o_creat)
#ifdef O_DEFER
IF_OPEN ("o-defer", &opt_o_defer)
#endif
@ -1191,7 +1194,8 @@ const struct optname optionnames[] = {
#endif
IF_OPEN ("o-trunc", &opt_o_trunc)
IF_OPEN ("o-wronly", &opt_o_wronly)
IF_OPEN ("o_create", &opt_o_create)
IF_OPEN ("o_creat", &opt_o_creat)
IF_OPEN ("o_create", &opt_o_creat)
#ifdef O_DEFER
IF_OPEN ("o_defer", &opt_o_defer)
#endif
@ -1348,9 +1352,12 @@ const struct optname optionnames[] = {
IF_INTERFACE("portsel", &opt_iff_portsel)
#endif
#if WITH_POSIXMQ
IF_ANY ("posixmq-flush", &opt_posixmq_flush)
IF_ANY ("posixmq-maxmsg", &opt_posixmq_maxmsg)
IF_ANY ("posixmq-msgsize", &opt_posixmq_msgsize)
IF_ANY ("posixmq-priority", &opt_posixmq_priority)
#endif
#if HAVE_RESOLV_H && WITH_RES_PRIMARY
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H && WITH_RES_PRIMARY
IF_RESOLVE("primary", &opt_res_primary)
#endif
#ifdef SO_PRIORITY
@ -1411,7 +1418,7 @@ const struct optname optionnames[] = {
IF_OPEN ("rdonly", &opt_o_rdonly)
IF_OPEN ("rdwr", &opt_o_rdwr)
IF_ANY ("readbytes", &opt_readbytes)
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("recurse", &opt_res_recurse)
#endif /* HAVE_RESOLV_H */
#ifdef IP_RECVDSTADDR
@ -1451,7 +1458,7 @@ const struct optname optionnames[] = {
#ifdef VREPRINT
IF_TERMIOS("reprint", &opt_vreprint)
#endif
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
# if WITH_AA_ONLY
IF_RESOLVE("res-aaonly", &opt_res_aaonly)
# endif
@ -1480,15 +1487,15 @@ const struct optname optionnames[] = {
# endif
IF_RESOLVE("res-stayopen", &opt_res_stayopen)
IF_RESOLVE("res-usevc", &opt_res_usevc)
#endif /* HAVE_RESOLV_H */
#endif /* (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H */
IF_PROXY ("resolv", &opt_proxy_resolve)
IF_PROXY ("resolve", &opt_proxy_resolve)
#ifdef IP_RETOPTS
IF_IP ("retopts", &opt_ip_retopts)
#endif
# if HAVE_RES_RETRANS
#if (WITH_IP4 || WITH_IP6) && HAVE_RES_RETRANS
IF_RESOLVE("retrans", &opt_res_retrans)
# endif
#endif
#if WITH_INTERFACE && defined(PACKET_AUXDATA)
IF_SOCKET ("retrieve-vlan", &opt_retrieve_vlan)
#endif
@ -1576,8 +1583,10 @@ const struct optname optionnames[] = {
#endif
IF_SOCKET ("setsockopt", &opt_setsockopt)
IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("setsockopt-connected", &opt_setsockopt_connected)
IF_SOCKET ("setsockopt-int", &opt_setsockopt_int)
IF_SOCKET ("setsockopt-listen", &opt_setsockopt_listen)
IF_SOCKET ("setsockopt-socket", &opt_setsockopt_socket)
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
IF_ANY ("setuid", &opt_setuid)
IF_ANY ("setuid-early", &opt_setuid_early)
@ -1712,8 +1721,10 @@ const struct optname optionnames[] = {
#endif /* SO_USELOOPBACK */
IF_SOCKET ("sockopt", &opt_setsockopt)
IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("sockopt-conn", &opt_setsockopt_connected)
IF_SOCKET ("sockopt-int", &opt_setsockopt_int)
IF_SOCKET ("sockopt-listen", &opt_setsockopt_listen)
IF_SOCKET ("sockopt-sock", &opt_setsockopt_socket)
IF_SOCKET ("sockopt-string", &opt_setsockopt_string)
IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser)
@ -1724,7 +1735,7 @@ const struct optname optionnames[] = {
IF_IPAPP ("sourceport", &opt_sourceport)
IF_IPAPP ("sp", &opt_sourceport)
IF_TERMIOS("start", &opt_vstart)
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("stayopen", &opt_res_stayopen)
#endif /* HAVE_RESOLV_H */
IF_EXEC ("stderr", &opt_stderr)
@ -1930,7 +1941,7 @@ const struct optname optionnames[] = {
IF_ANY ("user", &opt_user)
IF_NAMED ("user-early", &opt_user_early)
IF_ANY ("user-late", &opt_user_late)
#if HAVE_RESOLV_H
#if (WITH_IP4 || WITH_IP6) && HAVE_RESOLV_H
IF_RESOLVE("usevc", &opt_res_usevc)
#endif /* HAVE_RESOLV_H */
#if defined(AI_V4MAPPED)
@ -2654,13 +2665,13 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts,
(*opts)[i].value3.u_string);
break;
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
#if (WITH_IP4 || WITH_IP6) && ( defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) )
case TYPE_IP_MREQN:
xiotype_ip_add_membership(token, ent, opt);
break;
#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
#endif /* WITH_IP && defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) ) */
#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
#if _WITH_IP4 && defined(HAVE_STRUCT_IP_MREQ_SOURCE)
case TYPE_IP_MREQ_SOURCE:
xiotype_ip_add_source_membership(token, ent, opt);
break;
@ -2768,7 +2779,8 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts,
++i;
if ((i % 8) == 0) {
*opts = Realloc(*opts, (i+8) * sizeof(struct opt));
/*0 *opts = Realloc(*opts, (i+8) * sizeof(struct opt)); */
*opts = Realloc3(*opts, (i+8) * sizeof(struct opt), i * sizeof(struct opt));
if (*opts == NULL) {
return -1;
}
@ -2904,7 +2916,6 @@ int showleft(const struct opt *opts) {
return 0;
}
/* determines the address group from mode_t */
/* does not set GROUP_FD; cannot determine GROUP_TERMIOS ! */
groups_t _groupbits(mode_t mode) {
@ -3100,7 +3111,7 @@ int retropt_int(struct opt *opts, int optcode, int *result) {
/* Looks for the first option of type <optcode>. If the option is found,
this function stores its int value in *result, "consumes" the
option, and returns 0.
If the option is not found, *result is not modified, and -1 is returned. */
If the option is not found, values are not modified, and -1 is returned. */
int retropt_2integrals(struct opt *opts, int optcode,
union integral *value1, union integral *value2)
{
@ -3250,7 +3261,8 @@ int retropt_bind(struct opt *opts,
int ipproto,
struct sockaddr *sa,
socklen_t *salen,
int feats, /* TCP etc: 1..address allowed,
int feats, /* -1..generic addr spec
TCP etc: 1..address allowed,
3..address and port allowed
UNIX (or'd): 1..tight
2..abstract
@ -3274,10 +3286,13 @@ int retropt_bind(struct opt *opts,
}
bindp = bindname;
switch (af) {
#if WITH_IP4 && WITH_IP6
/* Try to derive address family from string */
if (af == AF_UNSPEC && bindname[0] == '[')
af = AF_INET6;
#endif /* WITH_IP4 && WITH_IP6 */
case AF_UNSPEC:
{
if (feats == -1) {
size_t p = 0;
dalan(bindname, (uint8_t *)sa->sa_data, &p, *salen-sizeof(sa->sa_family), 'i');
*salen = p + sizeof(sa->sa_family);
@ -3289,10 +3304,13 @@ int retropt_bind(struct opt *opts,
#if HAVE_STRUCT_SOCKADDR_SALEN
sa->sa_len = *salen;
#endif
}
break;
return STAT_OK;
}
switch (af) {
#if WITH_IP4 || WITH_IP6 || WITH_VSOCK
case AF_UNSPEC:
#if WITH_VSOCK
case AF_VSOCK:
#endif
@ -3323,11 +3341,12 @@ int retropt_bind(struct opt *opts,
}
}
/* Set AI_PASSIVE, except when it is explicitely disabled */
# if WITH_IP4 || WITH_IP6
/* Set AI_PASSIVE, except when it is explicitly disabled */
ai_flags2[0] = ai_flags[0];
ai_flags2[1] = ai_flags[1];
if (!(ai_flags2[1] & AI_PASSIVE))
ai_flags2[0] |= AI_PASSIVE;
ai_flags2[0] |= AI_PASSIVE;
if ((result =
xioresolve(hostname[0]!='\0'?hostname:NULL, portp,
@ -3337,6 +3356,8 @@ int retropt_bind(struct opt *opts,
Error("error resolving bind option");
return STAT_NORETRY;
}
/*# else */
# endif /* WITH_IP4 || WITH_IP6 */
break;
#endif /* WITH_IP4 || WITH_IP6 || WITH_VSOCK */
@ -3567,6 +3588,8 @@ int applyopt_ioctl_generic(
return 0;
}
#if _WITH_SOCKET
int applyopt_sockopt(
int fd,
struct opt *opt)
@ -3695,7 +3718,7 @@ int applyopt_sockopt(
}
break;
#endif /* HAVE_STRUCT_LINGER */
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
#if (WITH_IP4 || WITH_IP6) && ( defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) )
case TYPE_IP_MREQN:
/* handled in applyopts_single */
break;
@ -3815,6 +3838,9 @@ int applyopt_sockopt_generic(
return 0;
}
#endif /* _WITH_SOCKET */
#if HAVE_FLOCK
int applyopt_flock(
int fd,
struct opt *opt)
@ -3826,6 +3852,7 @@ int applyopt_flock(
}
return 0;
}
#endif /* defined(HAVE_FLOCK) */
/* Applies an option that needs handling specific to its OPT_* setting.
Does not overwrite the option instance with ODESC_DONE or ODESC_ERROR,
@ -3921,8 +3948,12 @@ int applyopt_spec(
{
struct passwd *pwd;
if ((pwd = getpwuid(opt->value.u_uidt)) == NULL) {
Error1("getpwuid("F_uid"): no such user",
opt->value.u_uidt);
if (errno != 0)
Error2("getpwuid("F_uid"): %s",
opt->value.u_uidt, strerror(errno));
else
Error1("getpwuid("F_uid"): no such user",
opt->value.u_uidt);
return -1;
}
if (Initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
@ -4216,7 +4247,7 @@ int applyopts_cloexec(int fd, struct opt *opts) {
if (!opts) return 0;
retropt_bool(opts, OPT_CLOEXEC, &docloexec);
retropt_bool(opts, OPT_O_CLOEXEC, &docloexec);
if (docloexec) {
if (Fcntl_l(fd, F_SETFD, FD_CLOEXEC) < 0) {
Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd, strerror(errno));
@ -4272,6 +4303,7 @@ static int applyopt_offset(struct single *sfd, struct opt *opt) {
case TYPE_CONST:
*(int *)ptr = opt->desc->minor;
break;
#if WITH_IP4
case TYPE_IP4NAME:
memset(ptr, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in *)ptr)->sin_addr = opt->value.u_ip4addr;
@ -4281,6 +4313,7 @@ static int applyopt_offset(struct single *sfd, struct opt *opt) {
memset(ptr, 0, sizeof(struct sockaddr_in));
*(struct sockaddr_in *)ptr = opt->value.u_ip4sock;
break;
#endif /* WITH_IP4 */
default:
Error2("applyopt_offset(opt:%s): type %s not implemented",
opt->desc->defname, xiohelp_opttypename(opt->desc->type));
@ -4664,3 +4697,11 @@ int dumpopts(struct opt *opts)
}
return 0;
}
/* Better with type specific free function */
void freeopts(
struct opt *opts)
{
free(opts);
return;
}

View file

@ -72,7 +72,7 @@ enum e_types {
#if HAVE_STRUCT_LINGER
TYPE_LINGER, /* struct linger */
#endif /* HAVE_STRUCT_LINGER */
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
#if (WITH_IP4 || WITH_IP6) && ( defined(HAVE_STRUCT_IP_MREQ) || defined(HAVE_STRUCT_IP_MREQN) )
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif
#if HAVE_STRUCT_IP_MREQ_SOURCE
@ -150,7 +150,7 @@ enum e_func {
#define GROUP_NONE 0x00000000
#define GROUP_ADDR 0x00000000 /* options that apply to all addresses */
#define GROUP_FD 0x00000001 /* everything applyable to a fd */
#define GROUP_FD 0x00000001 /* everything applicable to a fd */
#define GROUP_FIFO 0x00000002
#define GROUP_CHR 0x00000004 /* not yet used? */
#define GROUP_BLK 0x00000008
@ -272,7 +272,6 @@ enum e_optcode {
OPT_CHROOT_EARLY, /* chroot() before file system access */
/*OPT_CIBAUD,*/ /* termios.c_cflag */
OPT_CLOCAL, /* termios.c_cflag */
OPT_CLOEXEC,
OPT_CONNECT_TIMEOUT, /* socket connect */
OPT_COOL_WRITE,
OPT_CR, /* customized */
@ -482,6 +481,9 @@ enum e_optcode {
OPT_LOWPORT,
OPT_MAX_CHILDREN,
#if WITH_POSIXMQ
OPT_POSIXMQ_FLUSH,
OPT_POSIXMQ_MAXMSG,
OPT_POSIXMQ_MSGSIZE,
OPT_POSIXMQ_PRIORITY,
#endif
#ifdef NLDLY
@ -552,7 +554,8 @@ enum e_optcode {
OPT_O_ASYNC,
#endif
OPT_O_BINARY, /* Cygwin */
OPT_O_CREATE,
OPT_O_CLOEXEC,
OPT_O_CREAT,
#ifdef O_DEFER
OPT_O_DEFER,
#endif
@ -660,8 +663,10 @@ enum e_optcode {
OPT_SETPGID,
OPT_SETSID,
OPT_SETSOCKOPT_BIN,
OPT_SETSOCKOPT_CONNECTED,
OPT_SETSOCKOPT_INT,
OPT_SETSOCKOPT_LISTEN,
OPT_SETSOCKOPT_SOCKET,
OPT_SETSOCKOPT_STRING,
OPT_SETUID,
OPT_SETUID_EARLY,
@ -1028,6 +1033,7 @@ extern groups_t _groupbits(mode_t mode);
extern int dropopts(struct opt *opts, unsigned int phase);
extern int dropopts2(struct opt *opts, unsigned int from, unsigned int to);
extern int dumpopts(struct opt *opts);
extern void freeopts(struct opt *opts);
#if HAVE_BASIC_UID_T==1
# define retropt_uid(o,c,r) retropt_short(o,c,r)

View file

@ -10,6 +10,7 @@
#include "xio-openssl.h"
static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
static void signal_kill_pid(int dummy) {
@ -51,6 +52,7 @@ int xioshutdown(xiofile_t *sock, int how) {
sock->stream.fd, strerror(errno));
}
return 0;
#if _WITH_SOCKET
case XIOSHUT_DOWN:
result = Shutdown(sock->stream.fd, how);
if (result < 0) {
@ -70,7 +72,6 @@ int xioshutdown(xiofile_t *sock, int how) {
return -1;
}
return 0;
#if _WITH_SOCKET
case XIOSHUT_NULL:
writenull = '\0'; /* assign something to make gcc happy */
/* send an empty packet; only useful on datagram sockets? */

View file

@ -50,7 +50,7 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
switch (pipe->dtype & XIODATA_WRITEMASK) {
case XIOWRITE_STREAM:
writt = writefull(pipe->fd, buff, bytes);
writt = writefull(pipe->fd, buff, bytes, NULL);
if (writt < 0) {
_errno = errno;
switch (_errno) {
@ -116,8 +116,10 @@ ssize_t xiowrite(xiofile_t *file, const void *buff, size_t bytes) {
case XIOWRITE_PIPE:
if (pipe->para.bipipe.socktype == SOCK_STREAM) {
writt = Write(pipe->para.bipipe.fdout, buff, bytes);
#if _WITH_SOCKET
} else {
writt = Send(pipe->para.bipipe.fdout, buff, bytes, 0);
#endif /* _WITH_SOCKET */
}
_errno = errno;
if (writt < 0) {