1
0
Fork 0
mirror of https://repo.or.cz/socat.git synced 2025-07-27 21:15:37 +00:00

Compare commits

...

85 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
Gerhard Rieger
4ee1f31cf8 Version 1.8.0.2 - CVE-2024-54661: Arbitrary file overwrite in readline.sh 2024-12-06 11:42:09 +01:00
Gerhard Rieger
6ff391324d Version 1.8.0.1 2024-08-24 14:23:11 +02:00
Gerhard Rieger
47b98aed7a Print CRL warning only once 2024-08-24 14:23:04 +02:00
Gerhard Rieger
c4f569e367 Socks5 with 3 args and option socksport 2024-08-24 14:22:49 +02:00
Gerhard Rieger
0454c4fa43 Fixed SO_PROTOCOL on new Illumos 2024-08-24 14:22:05 +02:00
Gerhard Rieger
642b729622 More docu fixes 2024-08-24 14:21:55 +02:00
Gerhard Rieger
689b133817 Fixed a lot of typos in docu 2024-08-24 14:21:42 +02:00
Gerhard Rieger
ec0e1ca20c Reworked domain name resolution, centralized IPv4/IPv6 sorting 2024-08-24 14:21:35 +02:00
Gerhard Rieger
127280088c SENDTO addresses now prefer IPv4 over IPv6 name resolution 2024-08-24 14:21:19 +02:00
Gerhard Rieger
868998eb60 Mitigated regressions of 1.8.0.0 with TCP-LISTEN e.a. by making -4 the default 2024-08-24 14:20:32 +02:00
Gerhard Rieger
bd727963a0 IP-SENDTO with pf=ip4 failed with "trailing garbage" 2024-08-21 09:17:16 +02:00
Gerhard Rieger
602a54420e Added the optional DEVTESTS feature for developer tests with controlled name resolution to both IPv4 and IPV6 addresses 2024-08-20 12:02:25 +02:00
Gerhard Rieger
a86376cd1e Fixed possible buffer overrun with long log lines 2024-08-05 17:51:46 +02:00
Gerhard Rieger
0cfe39a413 Fixed IP-SENDTO with option pf with protocol name 2024-08-05 08:57:39 +02:00
Gerhard Rieger
50b6301bda For isastream() include stropts.h instead of sys/stropts.h 2024-08-05 08:57:28 +02:00
Gerhard Rieger
b96fd064cb test.sh: Fixed ss determination; more DEFS 2024-08-05 08:50:51 +02:00
Gerhard Rieger
93e6685766 Added option ai-all 2024-08-05 08:50:40 +02:00
Gerhard Rieger
a6c8c3ad89 socat-mux.sh and socat-broker.sh use low ports when run as root 2024-08-05 08:50:29 +02:00
Gerhard Rieger
1241600b81 socat-chain.sh, socat-mux.sh, and socat-broker.sh work with older Socat versions 2024-08-05 08:50:18 +02:00
Gerhard Rieger
9fe8206b52 Options ipv6-join-group and ipv6-join-source-group failed 2024-08-05 08:50:06 +02:00
Gerhard Rieger
4c0786dcdf Fixed FD leak of RECVFROM with fork 2024-08-05 08:49:35 +02:00
Gerhard Rieger
ab2b17dfc5 Fixed loop of RECVFROM with fork when second address failed 2024-08-05 08:48:48 +02:00
Gerhard Rieger
fdddba24b8 Fixed hanging of OpenSSL due to nested xioclose() 2024-07-28 12:59:24 +02:00
Gerhard Rieger
d16f1fe125 Guard applyopts_termios_value() 2024-07-28 12:59:14 +02:00
Gerhard Rieger
64dc8b2941 Makefile.in: Fixed srcdir/; and CC with spaces 2024-07-28 12:59:03 +02:00
Gerhard Rieger
efc654f85a Missing NETDB_INTERNAL now falls back to -1 2024-07-28 12:58:48 +02:00
Gerhard Rieger
54cbb0bb09 Changes for new Linux distributions: grep -E, -F 2024-07-28 12:58:32 +02:00
Gerhard Rieger
2ab4b232fc Again ported to NetBSD 2024-07-28 12:58:16 +02:00
Gerhard Rieger
b5b9ee0031 test.sh: -D for output defs/vars; many corrections and improvements 2024-07-28 12:57:45 +02:00
Gerhard Rieger
74d03b37da test.sh: speed up by tuned sleep values 2024-06-29 09:25:30 +02:00
Gerhard Rieger
42e20ed278 -T 0 now means 0.0s instead of no timeout 2024-06-29 09:20:47 +02:00
Gerhard Rieger
335fca16c4 test.sh: gather listOK 2024-06-29 09:19:38 +02:00
Gerhard Rieger
e4bf2b4d0e test.sh: fixed hanging on OpenBSD-4 2024-06-29 09:13:25 +02:00
Gerhard Rieger
f123013881 test.sh: Always use ss when available 2024-06-29 09:06:11 +02:00
96 changed files with 7409 additions and 6257 deletions

380
CHANGES
View file

@ -1,5 +1,326 @@

####################### V 1.8.0.0
####################### 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:
Socat security advisory 9
CVE-2024-54661: Arbitrary file overwrite
Socat 1.6.0.0 through 1.8.0.1 and version 2 distributions contain a
wrapper script "readline.sh" that uses a predictable temporary
directory, allowing unprivileged users to overwrite arbitrary files
belonging to the scripts caller.
This is fixed in Version 1.8.0.2
Mitigating factors: readline.sh is usually neither installed in a bin
directory nor is it documented. Major Linux distributions install it in
examples/ or doc/; however it is invoked by test.sh script.
Thanks to Wolfgang Frisch from SuSE for finding and reporting this
issue.
Test: READLINE_SH_OVERWRITE
####################### V 1.8.0.1:
Corrections:
When no IP version was preferred by environment, option -4/-6, or
address option pf, Socat version 1.8.0.0 address TCP-LISTEN did not
accept TCP4 connections under BSD family operating systems, but only
TCP6. To regain previous behaviour, preferring IP version 4 is now the
default. This also fixes some other issues with bind and range options.
Thanks to Mike Andrews for reporting this issue.
Tests: LISTEN_4 LISTEN_6 V1800_*_RANGE V1800_*_BIND
Added Socat option -0 to allow version 1.8.0.0 behaviour (no preferred
IP version).
UDP-SENDTO, UDPLITE-SENDTO, and IP-SENDTO addresses now select an IPv4
address in case the server name resolves to both IPv4 and IPv6
addresses.
Tests: V1800_*_SENDTO_RESOLV_6_4
Guard applyopts_termios_value() with WITH_TERMIOS.
Thanks to Kush Upadhyay from Amazon Bottlerocket team for providing the
patch.
In some situations xioclose() was called nested what could cause hanging
of OpenSSL in pthread_rwlock_wrlock()
socat 1.8.0.0 with addresses of type RECVFROM and option fork, where
the second address failed to connect/open in the child process, entered
a fork loop that was only stopped by FD exhaustion caused by FD leak.
Test: RECVFROM_FORK_LOOP
socat 1.8.0.0 had an FD leak with addresses of type RECVFROM with fork.
Test: RECVFROM_FORK_LEAK
With version 1.8.0.0, options ipv6-join-group and ipv6-join-source-group
did not work.
Thanks to Linus Luessing for reporting this bug.
IP-SENDTO and option pf (protocol-family) with protocol name (vs.numeric
argument) failed with message:
E retropts_int(): trailing garbage in numerical arg of option "protocol-family"
Test: IP_SENDTO_PF
Fixed a possible buffer overrun with long log lines. In fact it does
not write beyond end of buffer but lets pass excessive data to the
write() function.
Thanks to Heinrich Schuchardt from Canonical for reporting and sending
a patch.
Reworked domain name resolution, centralized IPv4/IPv6 sorting.
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.
Changed socat-chain.sh, socat-mux.sh, and socat-broker.sh to work with
older Socat versions.
socat-mux.sh and socat-broker.sh, when run as root, now internally use
low (512..1023) UDP ports to increase security.
Added option ai-all (sets AI_ALL flag of getaddrinfo() resolver)
Socks5 now also allows syntax without socks port, and supports option
socksport.
Porting:
Changes for building and testing on NetBSD
New Linux distributions dislike egrep, fgrep
When NETDB_INTERNAL is not available it should be set to -1.
Thanks to Baruch Siach for sending a patch.
On OpenSolaris/Illumos, isastream() is declared only in stropts.h, not
in sys/stropts.h
Thanks to Andy Fiddaman for sending a patch.
On latest Illumos, compilation failed due to new unexpected SO_PROTOCOL
implementation.
Thanks to Andy Fiddaman for sending a patch.
Building:
Makefile.in: procan.o build requires srcdir prefix for explicit source
file.
Thanks to Hongxu Jia and Andrew Schoolman for providing patches.
Makefile.in: the CC define for procan.o build failed when CC had more
than one word.
Thanks to Hongxu Jia for providing an inital patch.
Testing:
Added the optional DEVTESTS feature for developer tests with controlled
name resolution to both IPv4 and IPV6 addresses: configure Socat with
--enable-devtests, this provides internal resolution of domain
dest-unreach.net with host names: localhost-4, localhost-6,
localhost-4-6, and localhost-6-4
test.sh: lots of corrections and improvements
test.sh: many hardcoded sleep values were replaced by much shorter
values tuned to performance of the platform.
test.sh -D for output of platform/system specific defines (variables)
test.sh: fixed ss determination; more DEFS
Documentation:
Fixed a lot of typos.
Thanks to Solomon Victorino for sending the patch.
####################### V 1.8.0.0:
Security:
Socats OpenSSL addresses do not (and never did) check certificate
@ -106,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.
@ -303,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.
@ -323,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
@ -367,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.
@ -398,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
@ -520,12 +841,12 @@ Porting:
Fixed ancillary messages on Solaris.
Filan: Solaris has the open file path infos in /proc/<pid>/path/
Thanks to Andy Fiddaman to directing me to the patch.
Thanks to Andy Fiddaman for directing me to the patch.
Filan now recognizes and prints Solaris doors and event ports.
Solaris derivatives no longer need librt for clock_gettime()
Thanks to Andy Fiddaman to directing me to the patch.
Thanks to Andy Fiddaman for directing me to the patch.
LibreSSL does not have OPENSSL_INIT_new(). This function is now
guarded. Socat might build with LibreSSL.
@ -697,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.
@ -731,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.
@ -835,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
@ -848,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
@ -1049,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:
@ -1091,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
@ -1244,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
@ -1279,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
@ -1286,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.
@ -1300,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()
@ -1388,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.
@ -1401,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.
@ -1522,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:
@ -1576,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
@ -1809,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,
@ -1882,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)
@ -2308,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:
@ -2584,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
@ -109,8 +109,8 @@ depend: $(CFILES) $(HFILES)
socat: socat.o libxio.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ socat.o libxio.a $(CLIBS)
procan.o: procan.c
$(CC) $(CFLAGS) -c -D CC=\"$(CC)\" -o $@ procan.c
procan.o: $(srcdir)/procan.c
$(CC) $(CFLAGS) -c -D CC="\"$(CC)\"" -o $@ $(srcdir)/procan.c
PROCAN_OBJS=procan_main.o procan.o procan-cdefs.o hostan.o error.o sycls.o sysutils.o utils.o vsnprintf_r.o snprinterr.o
procan: $(PROCAN_OBJS)

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,

19
README
View file

@ -45,7 +45,7 @@ distributions.
platforms
---------
socat 1.8.0 was compiled and more or less successfully tested under the
socat 1.8.0 has been compiled and more or less successfully tested under the
following operating systems:
Debian 4 on x86_64
@ -53,23 +53,30 @@ FreeBSD 10 on amd64
OpenBSD 7.2 on amd64
OpenIndiana 2021-04 on i386 with gcc
Ubuntu 10.04 on i386
Ubuntu 12..22
Ubuntu 12..24
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.0
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.0"
"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"
@ -851,6 +855,8 @@ typedef unsigned long T_sigset;
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
# define NETDB_INTERNAL h_NETDB_INTERNAL
#elif !defined(NETDB_INTERNAL)
# define NETDB_INTERNAL (-1)
#endif
#ifndef INET_ADDRSTRLEN

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
@ -315,8 +324,8 @@
/* Define if you have the <libutil.h> header file. (FreeBSD: openpty()) */
#undef HAVE_LIBUTIL_H
/* Define if you have the <sys/stropts.h> header file. (stream opts on SunOS)*/
#undef HAVE_SYS_STROPTS_H
/* Define if you have the <stropts.h> header file. (stream opts on SunOS)*/
#undef HAVE_STROPTS_H
/* Define if you have the <regex.h> header file. */
#undef HAVE_REGEX_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
@ -748,10 +760,10 @@
#undef WITH_LIBWRAP
#undef HAVE_TCPD_H
#undef HAVE_LIBWRAP
#undef WITH_SYCLS
#undef WITH_FILAN
#undef WITH_RETRY
#undef WITH_DEVTESTS
#undef WITH_MSGLEVEL

View file

@ -10,7 +10,7 @@ AC_CONFIG_HEADER(config.h)
if test -f /usr/xpg4/bin/fgrep; then
FGREP=/usr/xpg4/bin/fgrep # Solaris
else
FGREP=fgrep
FGREP="grep -F"
fi
# find out which defines gcc passes to cpp, so makedepend does not run into
@ -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()
@ -86,7 +86,7 @@ AC_CHECK_HEADERS(linux/types.h)
AC_CHECK_HEADER(linux/errqueue.h, AC_DEFINE(HAVE_LINUX_ERRQUEUE_H), [], [#include <sys/time.h>
#include <linux/types.h>])
AC_CHECK_HEADERS(sys/utsname.h sys/select.h sys/file.h)
AC_CHECK_HEADERS(util.h bsd/libutil.h libutil.h sys/stropts.h regex.h)
AC_CHECK_HEADERS(util.h bsd/libutil.h libutil.h stropts.h regex.h)
AC_CHECK_HEADERS(linux/fs.h linux/ext2_fs.h)
dnl Checks for setgrent, getgrent and endgrent.
@ -305,6 +305,16 @@ if test "$ac_cv_apple_use_rfc_2292" = yes; then
fi
AC_MSG_RESULT($ac_cv_apple_use_rfc_2292)
AC_MSG_CHECKING(if including netinet/in.h suffices)
AC_TRY_COMPILE([#include <sys/types.h>
#include <netinet/in.h>],
[struct sockaddr_in6 s;],
[ AC_MSG_RESULT(yes); WITH_IP6=1],
[ AC_MSG_RESULT(no); WITH_IP6=])
if test "$WITH_IP6"; then
AC_DEFINE(WITH_IP6)
fi
fi
AC_MSG_CHECKING(whether to include raw IP support)
@ -399,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)
@ -479,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)
@ -642,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)
@ -932,6 +954,15 @@ AC_ARG_ENABLE(retry, [ --disable-retry disable retry support],
esac],
[AC_DEFINE(WITH_RETRY) AC_MSG_RESULT(yes)])
AC_MSG_CHECKING(whether to include devtests support)
AC_ARG_ENABLE(devtests, [ --enable-devtests enable devtests support],
[case "$enableval" in
yes) AC_DEFINE(WITH_DEVTESTS) AC_MSG_RESULT(yes);;
*) AC_MSG_RESULT(no) ;;
esac],
[AC_MSG_RESULT(no)])
AC_MSG_CHECKING(included message level)
AC_ARG_ENABLE(msglevel, [ --enable-msglevel=N set max verbosity to debug,info,notice,warn,error,fatal],
[case "$enableval" in
@ -948,12 +979,14 @@ AC_ARG_ENABLE(msglevel, [ --enable-msglevel=N set max verbosity to debug,in
AC_MSG_CHECKING(default IP version)
AC_ARG_ENABLE(default-ipv, [ --enable-default-ipv=N set default/preferred IP version to "0" (none), "4", "6"],
[case "$enableval" in
"") AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0");;
"") AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("0");;
0) AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("4");;
4) AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("4");;
6) AC_DEFINE(WITH_DEFAULT_IPV, '6') AC_MSG_RESULT("6");;
*) AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0");;
*) AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("0");;
esac],
[AC_DEFINE(WITH_DEFAULT_IPV, '0') AC_MSG_RESULT("0")])
[AC_DEFINE(WITH_DEFAULT_IPV, '4') AC_MSG_RESULT("0")])
#AC_SUBST(V_INCL)
@ -1701,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),
@ -2227,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],
@ -2282,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

@ -40,7 +40,7 @@ requirements.
<p>
All the following examples work bidirectionally except when otherwise noticed.
For "clients" we just use <tt>STDIO</tt>, and for "servers" we use <tt>EXEC:hostname</tt> which
ingores its input but shows us which host the reply comes from. Replace these
ignores its input but shows us which host the reply comes from. Replace these
socat addresses with what is appropriate for your needs (e.g. shell script
invocations). Port 6666 can be replaced with any other port (but for ports &lt;
1024 root privilege might be required).

View file

@ -32,7 +32,7 @@ In this docu we only use self signed certificates for the sake of simplicity.
</p>
<p>We assume that the server host is called <tt>server.domain.org</tt> and the
server process uses port 4433. To keep it simple, we use a very simple server
funtionality that just echos data (<tt>echo</tt>), and <tt>stdio</tt> on the
functionality that just echos data (<tt>echo</tt>), and <tt>stdio</tt> on the
client.</p>
<h3>Generate a server certificate</h3>
@ -77,7 +77,7 @@ server.</p>
<p>Instead of using a tcp-listen (tcp-l) address, we use openssl-listen (ssl-l)
for the server, <tt>cert=...</tt> tells the program to the file containing its
ceritificate and private key, and <tt>cafile=...</tt> points to the file
certificate and private key, and <tt>cafile=...</tt> points to the file
containing the certificate of the peer; we trust clients only if they can proof
that they have the related private key (OpenSSL handles this for us):<p>
<span class="shell">socat \

View file

@ -104,7 +104,7 @@ dit(bf(tt(-h | -?)))
types, and exit.
dit(bf(tt(-hh | -??)))
Like -h, plus a list of the short names of all available address options. Some options are
platform dependend, so this output is helpful for checking the particular
platform dependent, so this output is helpful for checking the particular
implementation.
dit(bf(tt(-hhh | -???)))
Like -hh, plus a list of all available address option names.
@ -123,7 +123,7 @@ dit(bf(tt(-D)))
Logs information about file descriptors before starting the transfer phase.
label(option_experimental)dit(bf(tt(--experimental)))
New features that are not well tested or are subject to change in the future
must me explicitely enabled using this option.
must be explicitly enabled using this option.
dit(bf(tt(-ly[<facility>])))
Writes messages to syslog instead of stderr; severity as defined with -d
option. With optional link(<facility>)(TYPE_FACILITY), the syslog type can
@ -197,9 +197,11 @@ label(option_t)dit(bf(tt(-t))tt(<timeout>))
the timeout interval the read part gives EOF, socat terminates without
awaiting the timeout.
label(option_T)dit(bf(tt(-T))tt(<timeout>))
Total inactivity timeout: when socat is already in the transfer loop and
Total inactivity timeout: when socat() is already in the transfer loop and
nothing has happened for <timeout> [link(timeval)(TYPE_TIMEVAL)] seconds
(no data arrived, no interrupt occurred...) then it terminates.
(no data arrived, no interrupt occurred...) then it terminates. Up to
version 1.8.0.0 "0" meant infinite"; since version 1.8.0.1 "0" means 0
and values <0 mean infinite.nl()
Useful with protocols like UDP that cannot transfer EOF.
label(option_u)dit(bf(tt(-u)))
Uses unidirectional mode. The first address is only used for reading, and the
@ -219,10 +221,13 @@ label(option_W)dit(bf(tt(-W))tt(<lockfile>))
creates it and continues, unlinks lockfile on exit.
label(option_4)dit(bf(tt(-4)))
Use IP version 4 in case the addresses do not implicitly or explicitly
specify a version. Since version 1.8.0 the default is no preference.
specify a version. Since version 1.8.0.1 this is the default.
label(option_6)dit(bf(tt(-6)))
Use IP version 6 in case the addresses do not implicitly or explicitly
specify a version.
label(option_0)dit(bf(tt(-0)))
Do not prefer a particular IP version; this lets passive addresses (LISTEN,
RECV, ...) serve both versions on some platforms (not BSD).
label(option_statistics)dit(bf(tt(--statistics)))
dit(bf(tt(-S)))
Logs transfer statistics (bytes and blocks counters for both directions)
@ -308,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),
@ -327,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()
@ -578,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),
@ -742,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),
@ -750,7 +756,7 @@ label(ADDRESS_NAMED_PIPE)dit(bf(tt(PIPE:<filename>)))
See also: link(unnamed pipe)(ADDRESS_UNNAMED_PIPE)
label(ADDRESS_UNNAMED_PIPE)dit(bf(tt(PIPE)))
Creates an unnamed pipe and uses it for reading and writing. It works as an
echo, because everything written to it appeares immediately as read
echo, because everything written to it appears immediately as read
data.nl()
Note: When socat tries to write more bytes than the pipe can queue (Linux
2.4: 2048 bytes), socat might block. Consider, e.g., using
@ -759,7 +765,7 @@ label(ADDRESS_UNNAMED_PIPE)dit(bf(tt(PIPE)))
See also: link(named pipe)(ADDRESS_NAMED_PIPE), link(SOCKETPAIR)(ADDRESS_SOCKETPAIR)
label(ADDRESS_SOCKETPAIR)dit(bf(tt(SOCKETPAIR)))
Creates a socketpair and uses it for reading and writing. It works as an
echo, because everything written to it appeares immediately as read
echo, because everything written to it appears immediately as read
data. The default socket type is datagram, so it keeps packet boundaries.
nl()
Option groups: link(FD)(GROUP_FD) nl()
@ -768,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
@ -877,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()
@ -1098,13 +1119,14 @@ 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),
link(sourceport)(OPTION_SOURCEPORT),
link(pf)(OPTION_PROTOCOL_FAMILY),
link(retry)(OPTION_RETRY)nl()
@ -1116,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),
@ -1227,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),
@ -1284,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
@ -1412,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),
@ -1450,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),
@ -1833,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
@ -1846,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.
@ -1981,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.
@ -2102,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()
@ -2130,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
@ -2158,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()
@ -2183,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))
@ -2362,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)))
@ -2388,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()
@ -2519,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
@ -2564,8 +2599,11 @@ label(OPTION_AI_V4MAPPED)
dit(bf(tt(ai-v4mapped[=0|1]))) dit(bf(tt(v4mapped[=0|1])))
Sets or unsets the AI_V4MAPPED flag for code(getaddrinfo()). With socat()
addresses requiring IPv6 addresses, this resolves IPv4 addresses to the
approriate IPv6 address [::ffff:*:*]. For IPv6 Socat addresses, the default
is 1.
appropriate IPv6 address [::ffff:*:*]. For IPv6 socat() addresses, the
default is 1.
label(OPTION_AI_ALL)
dit(bf(tt(ai-all[=0|1])))
Sets or unsets the AI_ALL flag for code(getaddrinfo()).
label(OPTION_RES_DEBUG)dit(bf(tt(res-debug)))
label(OPTION_RES_AAONLY)dit(bf(tt(res-aaonly)))
@ -2826,7 +2864,7 @@ label(OPTION_PROXYPORT)dit(bf(tt(proxyport=<TCP service>)))
label(OPTION_IGNORECR)dit(bf(tt(ignorecr)))
The HTTP protocol requires the use of CR+NL as line terminator. When a proxy
server violates this standard, socat might not understand its answer.
This option directs socat to interprete NL as line terminator and
This option directs socat to interpret NL as line terminator and
to ignore CR in the answer. Nevertheless, socat sends CR+NL to the proxy.
label(OPTION_PROXY_AUTHORIZATION)dit(bf(tt(proxy-authorization=<username>:<password>)))
Provide "basic" authentication to the proxy server. The argument to the
@ -2967,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
@ -3055,7 +3095,7 @@ label(OPTION_TERMIOS_RAWER)dit(bf(tt(rawer)))
label(OPTION_TERMIOS_CFMAKERAW)dit(bf(tt(cfmakeraw)))
Sets raw mode by invoking tt(cfmakeraw()) or by simulating this call. This option implicitly turns off echo.
label(OPTION_IGNBRK)dit(bf(tt(ignbrk[=<bool>])))
Ignores or interpretes the BREAK character (e.g., ^C)
Ignores or interprets the BREAK character (e.g., ^C)
label(OPTION_BRKINT)dit(bf(tt(brkint[=<bool>])))
label(OPTION_BS0)dit(bf(tt(bs0)))
label(OPTION_BS1)dit(bf(tt(bs1)))
@ -3274,7 +3314,7 @@ label(OPTION_OPENSSL_METHOD)dit(bf(tt(method=<ssl-method>)))
dit(tt(TLS1)) Select TLS protocol version 1.
dit(tt(TLS1.1)) Select TLS protocol version 1.1.
dit(tt(TLS1.2)) Select TLS protocol version 1.2.
When this option is not provided OpenSSL negotiates the mothod with its
When this option is not provided OpenSSL negotiates the method with its
peer.
enddit()
label(OPTION_OPENSSL_MIN_PROTO_VERSION)dit(bf(tt(min-proto-version)))
@ -3336,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
@ -3481,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()
@ -3503,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()
@ -3519,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.
@ -3572,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)
@ -3963,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 \\)
@ -4436,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>)
@ -4455,19 +4505,19 @@ 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:"robot.sh"\fP)
SYSTEM:"worker.sh"\fP)
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:"robot.sh"</div>)
SYSTEM:"worker.sh"</div>)
Receives messages (packets) from POSIX message queue and, for each messages,
Receives messages (packets) from POSIX message queue and, for each message,
forks a sub process that reads and processes the message. At most 3 sub
processes are allowed at the same time.

View file

@ -404,6 +404,7 @@ void msg2(
if (bufp < buff+MSGLEN)
*bufp++ = ' ';
strncpy(bufp, text, MSGLEN-(bufp-buff));
bufp[MSGLEN-(bufp-buff)] = 0;
bufp = strchr(bufp, '\0');
strcpy(bufp, "\n");
_msg(level, buff, syslp);

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

@ -39,13 +39,13 @@ done
# read and parse HTTP request
read l
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/[1-3].[0-9]$' >/dev/null
if ! echo "$l" |grep -E '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/[1-3].[0-9]$' >/dev/null
then
echo "HTTP/1.0${SPACES}500 Bad Request"
echo
exit
fi
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/'"$REQVER"'$' >/dev/null
if ! echo "$l" |grep -E '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/'"$REQVER"'$' >/dev/null
then
echo "HTTP/1.0${SPACES}426 Upgrade Required"
echo

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="$@"
@ -22,9 +26,21 @@ if [ "$withhistfile" ]; then
else
HISTOPT=
fi
mkdir -p /tmp/$USER || exit 1
#
#
exec socat -d readline"$HISTOPT",noecho='[Pp]assword:' exec:"$PROGRAM",sigint,pty,setsid,ctty,raw,echo=0,stderr 2>/tmp/$USER/stderr2
#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
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

View file

@ -4,15 +4,15 @@
# Shell script to perform group communications, sometimes called brokering.
# It starts a Socat instance that forks a child process for each
# connected client; the clients communicate via IPv4 broadcast
# connected client; the child processes communicate via IPv4 broadcast
# Examples:
# socat-broker.sh TCP-L:1234
# Now connect with an arbitrary number of clients like TCP:<server>:1234
# Now connect with any number of clients like TCP:<server>:1234
# socat-broker.sh SSL-L:1234,cert=server.pem,cafile=clients.crt
# Now connect with an arbitrary number of clients like SSL:<server>:1234,cafile=server.cert=clients.pem
# Now connect with an arbitrary number of clients like SSL:<server>:1234,cafile=server,cert=clients.pem
ECHO="echo -e"
@ -21,7 +21,7 @@ usage () {
$ECHO " <listener> is a passive address like TCP4-L or SSL-L"
$ECHO " <options>:"
$ECHO " -d* -S -t <timeout> -T <timeout> are passed to socat"
$ECHO " -V prints the socat command before starting it"
$ECHO " -V Shows executed Socat commands and some infos"
$ECHO "For example:"
$ECHO " $0 \\"
$ECHO " TCP4-L:1234"
@ -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
@ -60,16 +61,44 @@ if ! [[ "$LISTENER" =~ .*,fork ]] || [[ "$LISTENER" =~ .*,fork, ]]; then
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
*/*) if [ -x ${0%/*}/socat ]; then SOCAT=${0%/*}/socat; fi ;;
esac
if [ -z "$SOCAT" ]; then SOCAT=socat; fi
[ "$VERBOSE" ] && echo "# $0: Using executable $SOCAT" >&2
PORT=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
if [ -z "$PORT" ]; then
echo "$0: Failed to determine free UDP port" >&2
exit 1
# When run as root we try low ports
LOWPORT=
PATTERN=bound
if [ "$(id -u)" = 0 ]; then
LOWPORT="lowport"
PATTERN="successfully prepared local socket"
fi
# We need a free UDP port (on loopback)
if [ -z "$LOWPORT" ]; then
PORT=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
fi
if [ -z "$PORT" ]; then
# Probably old Socat version, use a different approach
if type ss >/dev/null 2>&1; then
:
elif type netstat >/dev/null 2>&1; then
alias ss=netstat
else
echo "$0: Failed to determine free UDP port (old Socat version, no ss, no netstat?)" >&2
exit 1
fi
PORT=
while [ -z "$PORT" ] || ss -aun |grep -e ":$PORT\>" >/dev/null; do
if [ -z "$LOWPORT" ]; then
PORT=$((16384+RANDOM))
else
PORT=$((512+(RANDOM>>6) ))
fi
done
fi
[ "$VERBOSE" ] && echo "# $0: Using UDP port $PORT" >&2
BCADDR=127.255.255.255
if [ "$VERBOSE" ]; then

View file

@ -56,7 +56,7 @@ usage () {
$ECHO " <address3> is typically a client address with protocol like OPENSSL"
$ECHO " <options>:"
$ECHO " -d* -S <sigmask> -t <timeout> -T <timeout> are passed to socat"
$ECHO " -V prints the socat commands before starting them"
$ECHO " -V Shows executed Socat commands and some infos"
$ECHO "Example to drive SOCKS over TLS:"
$ECHO " $0 \\"
$ECHO " TCP4-L:1234,reuseaddr,fork \\"
@ -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
@ -130,10 +131,12 @@ else
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
*/*) if [ -x ${0%/*}/socat ]; then SOCAT=${0%/*}/socat; fi ;;
esac
if [ -z "$SOCAT" ]; then SOCAT=socat; fi
[ "$VERBOSE" ] && echo "# $0: Using executable $SOCAT" >&2
# We need a free TCP port (on loopback)
PORT=$($SOCAT -d -d TCP4-L:0,accept-timeout=0.000001 /dev/null 2>&1 |grep listening |sed 's/.*:\([1-9][0-9]*\)$/\1/')
if [ -z "$PORT" ]; then
echo "$0: Failed to determine free TCP port" >&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.
@ -28,7 +28,7 @@ usage () {
$ECHO "data provided by 10.2.3.4 is sent to ALL clients"
$ECHO " <options>:"
$ECHO "\t-h\tShow this help text and exit"
$ECHO "\t-V\tShow Socat commands"
$ECHO "\t-V\tShows executed Socat commands and some infos"
$ECHO "\t-q\tSuppress most messages"
$ECHO "\t-d*\tOptions beginning with -d are passed to Socat processes"
$ECHO "\t-l*\tOptions beginning with -l are passed to Socat processes"
@ -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
@ -67,19 +68,46 @@ if ! [[ "$LISTENER" =~ .*,fork ]] || [[ "$LISTENER" =~ .*,fork, ]]; then
fi
case "$0" in
*/*) SOCAT=${0%/*}/socat ;;
*) SOCAT=socat ;;
*/*) if [ -x ${0%/*}/socat ]; then SOCAT=${0%/*}/socat; fi ;;
esac
if [ -z "$SOCAT" ]; then SOCAT=socat; fi
[ "$VERBOSE" ] && echo "# $0: Using executable $SOCAT" >&2
PORT1=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
PORT2=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep bound |sed 's/.*:\([1-9][0-9]*\)$/\1/')
# When run as root we try low ports
LOWPORT=
PATTERN=bound
if [ "$(id -u)" = 0 ]; then
LOWPORT="lowport"
PATTERN="successfully prepared local socket"
fi
# We need two free UDP ports (on loopback)
if [ -z "$LOWPORT" ]; then
PORT1=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep "$PATTERN" |sed 's/.*:\([1-9][0-9]*\)$/\1/')
PORT2=$($SOCAT -d -d -T 0.000001 UDP4-RECV:0 /dev/null 2>&1 |grep "$PATTERN" |sed 's/.*:\([1-9][0-9]*\)$/\1/')
fi
if [ -z "$PORT1" -o -z "$PORT2" ]; then
echo "$0: Failed to determine free UDP ports" >&2
exit 1
fi
if [ "$PORT1" = "$PORT2" ]; then # seen on etch
PORT2=$((PORT1+1))
# Probably old Socat version, use a different approach
if type ss >/dev/null 2>&1; then
:
elif type netstat >/dev/null 2>&1; then
alias ss=netstat
else
echo "$0: Failed to determine free UDP ports (old Socat version, no ss, no netstat?)" >&2
exit 1
fi
PORT1= PORT2=
while [ -z "$PORT1" -o -z "$PORT2" -o "$PORT1" = "$PORT2" ] || ss -aun |grep -e ":$PORT1\>" -e ":$PORT2\>" >/dev/null; do
if [ -z "$LOWPORT" ]; then
PORT1=$((16384+RANDOM))
PORT2=$((16384+RANDOM))
else
PORT1=$((512+(RANDOM>>6) ))
PORT2=$((512+(RANDOM>>6) ))
fi
done
fi
[ "$VERBOSE" ] && echo "# $0: Using UDP ports $PORT1, $PORT2" >&2
IFADDR=127.0.0.1
BCADDR=127.255.255.255

67
socat.c
View file

@ -45,7 +45,7 @@ struct socat_opts {
false, /* verbhex */
{1,0}, /* pollintv */
{0,500000}, /* closwait */
{0,0}, /* total_timeout */
{0,1000000}, /* total_timeout (this invalid default means no timeout)*/
0, /* debug */
0, /* strictopts */
's', /* logopt */
@ -274,9 +274,16 @@ int main(int argc, const char *argv[]) {
}
}
rto = Strtod(a, (char **)&a, "-T");
socat_opts.total_timeout.tv_sec = rto;
socat_opts.total_timeout.tv_usec =
(rto-socat_opts.total_timeout.tv_sec) * 1000000;
if (rto < 0) {
socat_opts.total_timeout.tv_sec = 0; /* infinite */
socat_opts.total_timeout.tv_usec = 1000000; /* by invalid */
} else {
socat_opts.total_timeout.tv_sec = rto;
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;
@ -313,6 +320,7 @@ int main(int argc, const char *argv[]) {
socat_opts.lock.intervall.tv_nsec = 0;
break;
#if WITH_IP4 || WITH_IP6
case '0':
#if WITH_IP4
case '4':
#endif
@ -427,6 +435,13 @@ int main(int argc, const char *argv[]) {
}
#endif /* WITH_STATS */
/* Display important info, values may be set by:
./configure --enable-default-ipv=0|4|6
env SOCAT_PREFERRED_RESOLVE_IP, SOCAT_DEFAULT_LISTEN_IP
options -0 -4 -6 */
Info1("default listen IP version is %c", xioparms.default_ip);
Info1("preferred resolve IP version is %c", xioparms.preferred_ip);
result = socat(arg1[0], arg1[1]);
if (result == EXIT_SUCCESS && engine_result != EXIT_SUCCESS) {
result = engine_result; /* a signal handler reports failure */
@ -476,6 +491,9 @@ void socat_usage(FILE *fd) {
fputs(" -g do not check option groups\n", fd);
fputs(" -L <lockfile> try to obtain lock, or fail\n", fd);
fputs(" -W <lockfile> try to obtain lock, or wait\n", fd);
#if WITH_IP4 || WITH_IP6
fputs(" -0 do not prefer an IP version\n", fd);
#endif
#if WITH_IP4
fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
#endif
@ -709,6 +727,11 @@ void socat_version(FILE *fd) {
#else
fputs(" #undef WITH_RETRY\n", fd);
#endif
#ifdef WITH_DEVTESTS
fprintf(fd, " #define WITH_DEVTESTS %d\n", WITH_DEVTESTS);
#else
fputs(" #undef WITH_DEVTESTS\n", fd);
#endif
#ifdef WITH_MSGLEVEL
fprintf(fd, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL,
&"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL<<3]);
@ -762,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]);
@ -805,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]);
@ -842,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);
@ -854,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;
@ -992,8 +1016,7 @@ int _socat(void) {
/* for ignoreeof */
if (polling) {
if (!wasaction) {
if (socat_opts.total_timeout.tv_sec != 0 ||
socat_opts.total_timeout.tv_usec != 0) {
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;
@ -1017,8 +1040,7 @@ int _socat(void) {
/* there is a ignoreeof poll timeout, use it */
timeout = socat_opts.pollintv;
to = &timeout;
} else if (socat_opts.total_timeout.tv_sec != 0 ||
socat_opts.total_timeout.tv_usec != 0) {
} else if (socat_opts.total_timeout.tv_usec < 1000000) {
/* there might occur a total inactivity timeout */
timeout = socat_opts.total_timeout;
to = &timeout;
@ -1112,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));
@ -1134,8 +1156,7 @@ int _socat(void) {
} else if (polling && wasaction) {
wasaction = 0;
} else if (socat_opts.total_timeout.tv_sec != 0 ||
socat_opts.total_timeout.tv_usec != 0) {
} else if (socat_opts.total_timeout.tv_usec < 1000000) {
/* there was a total inactivity timeout */
Notice("inactivity timeout triggered");
free(buff);
@ -1318,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
@ -1346,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.0
%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
@ -167,8 +170,8 @@
#elif HAVE_LIBUTIL_H
#include <libutil.h> /* FreeBSD openpty() */
#endif
#if HAVE_SYS_STROPTS_H
#include <sys/stropts.h> /* SunOS I_PUSH ... */
#if HAVE_STROPTS_H
#include <stropts.h> /* SunOS I_PUSH ... */
#endif
#if HAVE_REGEX_H
#include <regex.h>
@ -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;
}
}
@ -346,7 +378,7 @@ int sockaddr_vm_parse(struct sockaddr_vm *sa, const char *cid_str,
return 0;
}
#endif /* WITH_IP4 */
#endif /* WITH_VSOCK */
#if !HAVE_INET_NTOP
/* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */
@ -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);

7403
test.sh

File diff suppressed because it is too large Load diff

17
utils.c
View file

@ -38,6 +38,23 @@ void *memdup(const void *src, size_t n) {
return dest;
}
#if !HAVE_PROTOTYPE_LIB_strndup
char *strndup(
const char *s,
size_t n)
{
char *m;
m = malloc(n+1);
if (m == NULL) {
return m;
}
strncpy(m, s, n);
m[n] = '\0';
return m;
}
#endif /* !HAVE_PROTOTYPE_LIB_strndup */
/* search the keyword-table for a match of the leading part of name. */
/* returns the pointer to the matching field of the keyword or NULL if no
keyword was found. */

View file

@ -15,6 +15,9 @@ struct wordent {
extern void *memrchr(const void *s, int c, size_t n);
#endif
extern void *memdup(const void *src, size_t n);
#if !HAVE_PROTOTYPE_LIB_strndup
extern char *strndup(const char *s, size_t n);
#endif
#if !HAVE_SETENV
extern int setenv(const char *name, const char *value, int overwrite);
#endif /* !HAVE_SETENV */

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:

593
xio-ip.c
View file

@ -68,11 +68,11 @@ 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)
const struct optdesc opt_ip_add_source_membership = { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQ_SOURCE, OFUNC_SOCKOPT, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP };
const struct optdesc opt_ip_add_source_membership = { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQ_SOURCE, OFUNC_SPEC, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP };
#endif
#ifdef IP_RECVDSTADDR
const struct optdesc opt_ip_recvdstaddr = { "ip-recvdstaddr", "recvdstaddr",OPT_IP_RECVDSTADDR, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IP, IP_RECVDSTADDR };
@ -84,6 +84,9 @@ const struct optdesc opt_ip_recvif = { "ip-recvif", "recvdstaddrif",OPT_IP_RECVI
#ifdef AI_ADDRCONFIG
const struct optdesc opt_ai_addrconfig = { "ai-addrconfig", "addrconfig", OPT_AI_ADDRCONFIG, GROUP_SOCK_IP, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.ai_flags), XIO_SIZEOF(para.socket.ip.ai_flags), AI_ADDRCONFIG };
#endif
#ifdef AI_ALL
const struct optdesc opt_ai_all = { "ai-all", NULL, OPT_AI_ALL, GROUP_SOCK_IP, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.ai_flags), XIO_SIZEOF(para.socket.ip.ai_flags), AI_ALL };
#endif
#ifdef AI_V4MAPPED
const struct optdesc opt_ai_v4mapped = { "ai-v4mapped", "v4mapped", OPT_AI_V4MAPPED, GROUP_SOCK_IP, PH_OFFSET, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.socket.ip.ai_flags), XIO_SIZEOF(para.socket.ip.ai_flags), AI_V4MAPPED };
#endif
@ -129,15 +132,17 @@ int xioinit_ip(
char ipv)
{
if (*pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (ipv) {
case '0': *pf = PF_UNSPEC; break;
#if WITH_IP4
case '4': *pf = PF_INET; break;
#endif
#if WITH_IP6
case '6': *pf = PF_INET6; break;
#endif
default: break; /* includes \0 */
}
#elif WITH_IP6
*pf = PF_INET6;
#else
*pf = PF_INET;
#endif
}
return 0;
}
@ -156,7 +161,282 @@ int Res_init(void) {
#endif /* HAVE_RESOLV_H */
/* the ultimate(?) socat resolver function
/* 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
needed */
static bool devtests_inited = false;
static struct sockaddr_in sockaddr_localhost_4 = {
#if HAVE_STRUCT_SOCKADDR_SALEN
sizeof(struct sockaddr_in),
#endif
AF_INET, /*htons*/0, { 0 }
};
static struct sockaddr_in6 sockaddr_localhost_6 = {
#if HAVE_STRUCT_SOCKADDR_SALEN
sizeof(struct sockaddr_in6),
#endif
AF_INET6, /*htons*/0, 0, { { { 0 } } }, 0
};
static struct addrinfo addrinfo_localhost_4 = {
0, AF_INET, 0, 0,
sizeof(struct sockaddr_in),
(struct sockaddr *)&sockaddr_localhost_4,
NULL,
NULL
} ;
static struct addrinfo addrinfo_localhost_6 = {
0, AF_INET6, 0, 0,
sizeof(struct sockaddr_in6),
(struct sockaddr *)&sockaddr_localhost_6,
NULL,
NULL
} ;
static struct addrinfo addrinfo_localhost_4_6[2] =
{
{
0, AF_INET, 0, 0,
sizeof(sockaddr_localhost_4),
NULL, /* memdup(sockaddr_localhost_4) */
NULL,
NULL /* &addrinfo_localhost_4_6[1] */
},
{
0, AF_INET6, 0, 0,
sizeof(sockaddr_localhost_6),
NULL, /* memdup(sockaddr_localhost_6) */
NULL,
NULL
},
} ;
static struct addrinfo addrinfo_localhost_6_4[2] =
{
{
0, AF_INET6, 0, 0,
sizeof(sockaddr_localhost_6),
NULL, /* memdup(sockaddr_localhost_6) */
NULL,
NULL, /* &addrinfo_localhost_6_4[1] */
},
{
0, AF_INET, 0, 0,
sizeof(sockaddr_localhost_4),
NULL, /* memdup(sockaddr_localhost_4) */
NULL,
NULL },
} ;
/* We keep track of the copied records because they must not be paaed to
freeaddrinfo() */
#define MAX_HARDCODED_RECORDS 16
static struct addrinfo *keep_hardcoded_records[MAX_HARDCODED_RECORDS];
static int count_hardcoded_records;
/* returns 0 on success, EAI_NODATA when no matching af, or
EAI_NONAME when node did not match the special names */
static int xioip_getaddrinfo_devtests(
const char *node,
const char *service,
int family,
int socktype,
int protocol,
struct addrinfo **res,
const int ai_flags[2])
{
if (!devtests_inited) {
devtests_inited = true;
sockaddr_localhost_4.sin_addr.s_addr = htonl((127<<24)+1); /* 127.0.0.1 */
#if WITH_IP6
xioip6_pton("::1", &sockaddr_localhost_6.sin6_addr, 0);
#endif
}
if (node == NULL) {
;
#if WITH_IP4
} else if (!strcmp(node, "localhost-4")
|| !strcmp(node, "localhost-4-6") && family == AF_INET
|| !strcmp(node, "localhost-6-4") && family == AF_INET
#if !WITH_IP6
|| !strcmp(node, "localhost-4-6")
|| !strcmp(node, "localhost-6-4")
#endif /* !WITH_IP6 */
) {
if (family == AF_INET6)
return EAI_NODATA;
*res = memdup(&addrinfo_localhost_4, sizeof(addrinfo_localhost_4));
(*res)->ai_socktype = socktype;
(*res)->ai_protocol = protocol;
(*res)->ai_addr = memdup(&sockaddr_localhost_4, sizeof(sockaddr_localhost_4));
((struct sockaddr_in *)((*res)->ai_addr))->sin_port = (service?htons(atoi(service)):0);
keep_hardcoded_records[count_hardcoded_records++] = *res;
return 0;
#endif /* WITH_IP4 */
#if WITH_IP6
} else if (!strcmp(node, "localhost-6")
|| !strcmp(node, "localhost-4-6") && family == AF_INET6
|| !strcmp(node, "localhost-6-4") && family == AF_INET6
#if !WITH_IP4
|| !strcmp(node, "localhost-4-6")
|| !strcmp(node, "localhost-6-4")
#endif /* !WITH_IP4 */
) {
if (family == AF_INET)
return EAI_NODATA;
*res = memdup(&addrinfo_localhost_6, sizeof(addrinfo_localhost_6));
(*res)->ai_socktype = socktype;
(*res)->ai_protocol = protocol;
(*res)->ai_addr = memdup(&sockaddr_localhost_6, sizeof(sockaddr_localhost_6));
((struct sockaddr_in6 *)((*res)->ai_addr))->sin6_port =
(service?htons(atoi(service)):0);
keep_hardcoded_records[count_hardcoded_records++] = *res;
return 0;
#endif /* !WITH_IP6 */
#if WITH_IP4 && WITH_IP6
} else if (!strcmp(node, "localhost-4-6")) {
/* here we come only when both WITH_IP4,WITH_IP6, and family not 4 or 6 */
*res = memdup(&addrinfo_localhost_4_6, sizeof(addrinfo_localhost_4_6));
(*res)[0].ai_socktype = socktype;
(*res)[0].ai_protocol = protocol;
(*res)[0].ai_addr = memdup(&sockaddr_localhost_4, sizeof(sockaddr_localhost_4));
((struct sockaddr_in *)((*res)[0].ai_addr))->sin_port =
(service?htons(atoi(service)):0);
(*res)[0].ai_next = &(*res)[1];
(*res)[1].ai_socktype = socktype;
(*res)[1].ai_protocol = protocol;
(*res)[1].ai_addr = memdup(&sockaddr_localhost_6, sizeof(sockaddr_localhost_6));
((struct sockaddr_in6 *)((*res)[1].ai_addr))->sin6_port =
(service?htons(atoi(service)):0);
keep_hardcoded_records[count_hardcoded_records++] = *res;
return 0;
#endif /* WITH_IP4 && WITH_IP6 */
#if WITH_IP4 && WITH_IP6
} else if (!strcmp(node, "localhost-6-4")) {
/* here we come only when both WITH_IP4,WITH_IP6, and family not 4,6 */
*res = memdup(&addrinfo_localhost_6_4, sizeof(addrinfo_localhost_6_4));
(*res)[0].ai_socktype = socktype;
(*res)[0].ai_protocol = protocol;
(*res)[0].ai_addr = memdup(&sockaddr_localhost_6, sizeof(sockaddr_localhost_6));
((struct sockaddr_in6 *)((*res)[0].ai_addr))->sin6_port =
(service?htons(atoi(service)):0);
(*res)[0].ai_next = &(*res)[1];
(*res)[1].ai_socktype = socktype;
(*res)[1].ai_protocol = protocol;
(*res)[1].ai_addr = memdup(&sockaddr_localhost_4, sizeof(sockaddr_localhost_4));
((struct sockaddr_in *)((*res)[1].ai_addr))->sin_port =
service?htons(atoi(service)):0;
keep_hardcoded_records[count_hardcoded_records++] = *res;
return 0;
#endif /* WITH_IP4 && WITH_IP6 */
}
if (count_hardcoded_records == MAX_HARDCODED_RECORDS)
--count_hardcoded_records; /* more records will leak memory */
return EAI_NONAME;
}
/* Checks if res is a devtests construct, returns 0 if so,
or 1 otherwise */
static int xioip_freeaddrinfo_devtests(
struct addrinfo *res)
{
int i;
for (i=0; i<16; ++i) {
if (res == keep_hardcoded_records[i]) {
free(res);
keep_hardcoded_records[i] = NULL;
return 0;
}
}
return 1;
}
#endif /* WITH_DEVTESTS */
/* A socat resolver function
node: the address to be resolved; supported forms:
1.2.3.4 (IPv4 address)
[::2] (IPv6 address)
@ -166,10 +446,10 @@ int Res_init(void) {
family: PF_INET, PF_INET6, or PF_UNSPEC permitting both
socktype: SOCK_STREAM, SOCK_DGRAM, ...
protocol: IPPROTO_UDP, IPPROTO_TCP
sau: an uninitialized storage for the resulting socket address
res: a pointer to an uninitialized ptr var for the resulting socket address
returns: STAT_OK, STAT_RETRYLATER, STAT_NORETRY, prints message
*/
int xiogetaddrinfo(const char *node, const char *service,
int _xiogetaddrinfo(const char *node, const char *service,
int family, int socktype, int protocol,
struct addrinfo **res, const int ai_flags[2]) {
char *numnode = NULL;
@ -179,24 +459,72 @@ 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",
node?node:"NULL", service?service:"NULL", family, socktype, protocol,
ai_flags?ai_flags[0]:0, ai_flags?ai_flags[1]:0, res);
if (service && service[0]=='\0') {
Error("empty port/service");
Error("_xiogetaddrinfo(): empty port and service");
return EAI_NONAME;
}
#if LATER
#ifdef WITH_VSOCK
if (family == AF_VSOCK) {
error_num = sockaddr_vm_parse(&sau->vm, node, service);
if (error_num < 0)
return STAT_NORETRY;
return STAT_OK;
if (error_num < 0) {
errno = EINVAL;
return EAI_SYSTEM;
}
return 0;
}
#endif /* WITH_VSOCK */
#endif /* LATER */
#if WITH_DEVTESTS
if (node != NULL && strchr(node, '.') &&
(!strcmp(strchr(node, '.'), ".dest-unreach.net") ||
!strcmp(strchr(node, '.'), ".dest-unreach.net."))) {
char *hname = strdup(node);
Info("dest-unreach.net domain handled specially");
if (hname == NULL)
return EAI_MEMORY;
if (hname[strlen(hname)-1] == '.')
hname[strlen(hname)-1] = '\0';
*strchr(hname, '.') = '\0';
error_num =
xioip_getaddrinfo_devtests(hname, service, family, socktype, protocol,
res, ai_flags);
if (error_num == EAI_NONAME) {
Warn("dest-unreach.net domain name does not resolve specially");
/* Pass through to libc resolver */
} else if (error_num != 0) {
Error7("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 == EAI_SYSTEM)?
strerror(errno):gai_strerror(error_num));
return error_num;
} else { /* ok */
#if WITH_MSGLEVEL <= E_DEBUG
struct addrinfo *record;
record = *res;
while (record) {
char buff[256/*!*/];
sockaddr_info(record->ai_addr, record->ai_addrlen, buff, sizeof(buff));
Debug5("getaddrinfo() -> flags=0x%02x family=%d socktype=%d protocol=%d addr=%s", record->ai_flags, record->ai_family, record->ai_socktype, record->ai_protocol, buff);
record = record->ai_next;
}
#endif /* WITH_MSGLEVEL <= E_DEBUG */
return error_num;
}
}
#endif /* WITH_DEVTESTS */
/* the resolver functions might handle numeric forms of node names by
reverse lookup, that's not what we want.
So we detect these and handle them specially */
@ -205,7 +533,7 @@ int xiogetaddrinfo(const char *node, const char *service,
#if WITH_IP6
} else if (node && node[0] == '[' && node[(nodelen=strlen(node))-1]==']') {
if ((numnode = Malloc(nodelen-1)) == NULL)
return STAT_NORETRY;
return EAI_MEMORY;
strncpy(numnode, node+1, nodelen-2); /* ok */
numnode[nodelen-2] = '\0';
@ -216,9 +544,11 @@ int xiogetaddrinfo(const char *node, const char *service,
if (family == PF_UNSPEC) family = PF_INET6;
#endif /* WITH_IP6 */
}
#if HAVE_GETADDRINFO
#ifdef AI_ADDRCONFIG
if (family == 0)
hints.ai_flags |= AI_ADDRCONFIG;
#if HAVE_GETADDRINFO
#endif
if (node != NULL || service != NULL) {
struct addrinfo *record;
@ -253,25 +583,23 @@ int xiogetaddrinfo(const char *node, const char *service,
freeaddrinfo(*res);
if (numnode)
free(numnode);
return STAT_NORETRY;
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) {
Error7("getaddrinfo(\"%s\", \"%s\", {0x%02x,%d,%d,%d}, {}): %s",
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 == EAI_SYSTEM)?
strerror(errno):gai_strerror(error_num));
if (*res != NULL)
freeaddrinfo(*res);
gai_strerror(error_num));
if (numnode)
free(numnode);
return STAT_RETRYLATER;
return error_num;
}
} while (1);
service = NULL; /* do not resolve later again */
@ -287,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) {
@ -339,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
@ -367,7 +703,7 @@ int xiogetaddrinfo(const char *node, const char *service,
return STAT_RETRYLATER;
}
if (host->h_addrtype != family) {
Error2("xiogetaddrinfo(): \"%s\" does not resolve to %s",
Error2("_xiogetaddrinfo(): \"%s\" does not resolve to %s",
node, family==PF_INET?"IP4":"IP6");
} else {
switch (family) {
@ -389,14 +725,113 @@ int xiogetaddrinfo(const char *node, const char *service,
}
}
#else
Error("no resolver function available");
errno = ENOSYS;
return EAI_SYSTEM;
#endif
if (numnode) free(numnode);
return STAT_OK;
return 0;
}
void xiofreeaddrinfo(struct addrinfo *res) {
/* Sort the records of an addrinfo list themp (as returned by getaddrinfo),
return the sorted list in the array ai_sorted (takes at most n entries
including the terminating NULL)
Returns 0 on success. */
int _xio_sort_ip_addresses(
struct addrinfo *themlist,
struct addrinfo **ai_sorted)
{
struct addrinfo *themp;
int i;
int ipv[3];
int ipi = 0;
/* Make a simple array of IP version preferences */
switch (xioparms.preferred_ip) {
case '0':
ipv[0] = PF_UNSPEC;
ipv[1] = -1;
break;
case '4':
ipv[0] = PF_INET;
ipv[1] = PF_INET6;
ipv[2] = -1;
break;
case '6':
ipv[0] = PF_INET6;
ipv[1] = PF_INET;
ipv[2] = -1;
break;
default:
Error("INTERNAL: undefined preferred_ip value");
return -1;
}
/* Create the sorted list */
ipi = 0;
i = 0;
while (ipv[ipi] >= 0) {
themp = themlist;
while (themp != NULL) {
if (ipv[ipi] == PF_UNSPEC) {
ai_sorted[i] = themp;
++i;
} else if (ipv[ipi] == themp->ai_family) {
ai_sorted[i] = themp;
++i;
}
themp = themp->ai_next;
}
++ipi;
}
ai_sorted[i] = NULL;
return 0;
}
/* Wrapper around _xiogetaddrinfo() (which is a wrapper arount getaddrinfo())
that sorts the results according to xioparms.preferred_ip when family is
AF_UNSPEC; it returns an array of record pointers instead of a list! */
int xiogetaddrinfo(const char *node, const char *service,
int family, int socktype, int protocol,
struct addrinfo ***ai_sorted, const int ai_flags[2]) {
struct addrinfo *res;
struct addrinfo **_ai_sorted;
struct addrinfo *aip;
int ain;
int rc;
rc = _xiogetaddrinfo(node, service, family, socktype, protocol, &res,
ai_flags);
if (rc != 0)
return rc;
/* Sort results - first, count records for mem allocation */
aip = res;
ain = 0;
while (aip != NULL) {
++ain;
aip = aip->ai_next;
}
_ai_sorted = Calloc((ain+2), sizeof(struct addrinfo *));
if (_ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(res, _ai_sorted);
_ai_sorted[ain+1] = res; /* save list past NULL for later freeing */
*ai_sorted = _ai_sorted;
return 0;
}
void _xiofreeaddrinfo(struct addrinfo *res) {
#if WITH_DEVTESTS
if (!xioip_freeaddrinfo_devtests(res)) {
return;
}
#endif
#if HAVE_GETADDRINFO
freeaddrinfo(res);
#else
@ -404,42 +839,68 @@ void xiofreeaddrinfo(struct addrinfo *res) {
#endif
}
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)
++ain;
res = ai_sorted[ain+1];
_xiofreeaddrinfo(res);
free(ai_sorted);
}
/* A simple resolver interface that just returns one address,
the first found by calling xiogetaddrinfo().
family may be AF_INET, AF_INET6, or AF_UNSPEC;
Returns -1 when an error occurred or when no result found.
the first found by calling xiogetaddrinfo(), but ev.respects preferred_ip;
pf may be AF_INET, AF_INET6, or AF_UNSPEC;
on failure logs error message;
returns STAT_OK, STAT_RETRYLATER, STAT_NORETRY
*/
int xioresolve(const char *node, const char *service,
int family, int socktype, int protocol,
int pf, int socktype, int protocol,
union sockaddr_union *addr, socklen_t *addrlen,
const int ai_flags[2])
{
struct addrinfo *res = NULL;
struct addrinfo **res = NULL;
struct addrinfo *aip;
int rc;
rc = xiogetaddrinfo(node, service, family, socktype, protocol,
rc = xiogetaddrinfo(node, service, pf, socktype, protocol,
&res, ai_flags);
if (rc != 0) {
xiofreeaddrinfo(res);
return -1;
if (rc == EAI_AGAIN) {
Warn3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(rc));
return STAT_RETRYLATER;
} else if (rc != 0) {
Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf,
(rc == EAI_SYSTEM)?strerror(errno):gai_strerror(rc));
return STAT_NORETRY;
}
if (res == NULL) {
Warn1("xioresolve(node=\"%s\", ...): No result", node);
Error3("xioresolve(node=\"%s\", pf=%d, ...): %s",
node?node:"NULL", pf, gai_strerror(EAI_NODATA));
xiofreeaddrinfo(res);
return -1;
return STAT_NORETRY;
}
if (res->ai_addrlen > *addrlen) {
Warn3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required", node, *addrlen, res->ai_addrlen);
if ((*res)->ai_addrlen > *addrlen) {
Error3("xioresolve(node=\"%s\", addrlen="F_socklen", ...): "F_socklen" bytes required",
node, *addrlen, (*res)->ai_addrlen);
xiofreeaddrinfo(res);
return -1;
return STAT_NORETRY;
}
if (res->ai_next != NULL) {
if ((*res)->ai_next != NULL) {
Info4("xioresolve(node=\"%s\", service=%s%s%s, ...): More than one address found", node?node:"NULL", service?"\"":"", service?service:"NULL", service?"\"":"");
}
aip = res;
if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && family == PF_UNSPEC) {
aip = *res;
if (ai_flags != NULL && ai_flags[0] & AI_PASSIVE && pf == PF_UNSPEC) {
/* We select the first IPv6 address, if available,
because this might accept IPv4 connections too */
while (aip != NULL) {
@ -448,17 +909,27 @@ int xioresolve(const char *node, const char *service,
aip = aip->ai_next;
}
if (aip == NULL)
aip = res;
aip = *res;
} else if (pf == PF_UNSPEC && xioparms.preferred_ip != '0') {
int prefip = PF_UNSPEC;
xioinit_ip(&prefip, xioparms.preferred_ip);
while (aip != NULL) {
if (aip->ai_family == prefip)
break;
aip = aip->ai_next;
}
if (aip == NULL)
aip = *res;
}
memcpy(addr, aip->ai_addr, aip->ai_addrlen);
*addrlen = aip->ai_addrlen;
xiofreeaddrinfo(res);
return 0;
return STAT_OK;
}
#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
@ -517,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 */
@ -616,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:
@ -727,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*/,
@ -743,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,
@ -967,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);
@ -976,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);
@ -1001,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

@ -30,6 +30,7 @@ extern const struct optdesc opt_ip_recvif;
extern const struct optdesc opt_ip_transparent;
extern const struct optdesc opt_ai_addrconfig;
extern const struct optdesc opt_ai_all;
extern const struct optdesc opt_ai_passive;
extern const struct optdesc opt_ai_v4mapped;
@ -48,8 +49,10 @@ extern const struct optdesc opt_res_nsaddr;
extern int xioinit_ip(int *pf, char ipv);
extern int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, struct addrinfo **res, const int ai_flags[2]);
extern void xiofreeaddrinfo(struct addrinfo *res);
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);
extern int xioresolve(const char *node, const char *service, int family, int socktype, int protocol, union sockaddr_union *addr, socklen_t *addrlen, const int ai_flags[2]);
extern int xiolog_ancillary_ip(struct single *sfd, struct cmsghdr *cmsg, int *num, char *typbuff, int typlen, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen);
extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt);

View file

@ -23,11 +23,11 @@ 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
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_SOCKOPT, SOL_IPV6, 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
const struct optdesc opt_ipv6_join_source_group = { "ipv6-join-source-group", "join-source-group", OPT_IPV6_JOIN_SOURCE_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_GROUP_SOURCE_REQ, OFUNC_SOCKOPT, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP };
const struct optdesc opt_ipv6_join_source_group = { "ipv6-join-source-group", "join-source-group", OPT_IPV6_JOIN_SOURCE_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_GROUP_SOURCE_REQ, OFUNC_SPEC, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP };
#endif
#ifdef IPV6_PKTINFO
const struct optdesc opt_ipv6_pktinfo = { "ipv6-pktinfo", "pktinfo", OPT_IPV6_PKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_PKTINFO };
@ -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,21 +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 *themlist, *themp;
char infobuff[256];
struct addrinfo **bindarr = NULL;
struct addrinfo **themarr = NULL;
uint16_t bindport = 0;
bool needbind = false;
bool lowport = false;
int level;
struct addrinfo **ai_sorted;
int i;
int level = E_ERROR;
int result;
if (argc != 3) {
@ -53,109 +51,84 @@ int xioopen_ipapp_connect(
return STAT_NORETRY;
}
xioinit_ip(&pf, xioparms.default_ip);
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,
&themlist, 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");
}
/* Count addrinfo entries */
themp = themlist;
i = 0;
while (themp != NULL) {
++i;
themp = themp->ai_next;
}
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
if (ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(themlist, ai_sorted);
do { /* loop over retries, and forks */
/* Loop over themlist - no, over ai_sorted */
result = STAT_RETRYLATER;
i = 0;
themp = ai_sorted[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 || ai_sorted[i] != NULL) {
level = E_INFO;
} 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 = ai_sorted[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 */
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
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:
free(ai_sorted);
free(opts0);free(opts);
Error4("%s:%s:%s: %s", argv[0], argv[1], argv[2],
_errno?strerror(_errno):"(See above)");
freeopts(opts);
freeopts(opts0);
return result;
}
@ -168,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;
}
free(ai_sorted);
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;
}
@ -189,102 +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) */
free(ai_sorted);
xiofreeaddrinfo(themlist);
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_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 **themlist,
union sockaddr_union *us,
socklen_t *uslen,
bool *needbind,
bool *lowport,
int socktype) {
uint16_t port;
int result;
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 (hostname != NULL || portname != NULL) {
if ((result =
xiogetaddrinfo(hostname, portname,
*pf, socktype, protocol,
themlist, ai_flags))
!= STAT_OK) {
return STAT_NORETRY; /*! STAT_RETRYLATER? */
}
if (dofork) {
xiosetchilddied(); /* set SIGCHLD handler */
}
applyopts(NULL, -1, opts, PH_EARLY);
/* 3 means: IP address AND port accepted */
if (retropt_bind(opts, (*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family,
socktype, protocol, (struct sockaddr *)us, uslen, 3,
ai_flags)
!= STAT_NOACTION) {
*needbind = true;
if (xioparms.logopt == 'm') {
Info("starting connect loop, switching to syslog");
diag_set('y', xioparms.syslogfac);
xioparms.logopt = 'y';
} else {
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->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");
}
Info("starting connect loop");
}
if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
switch ((*pf!=PF_UNSPEC)?*pf:(*themlist)->ai_family) {
#if WITH_IP4
case PF_INET: us->ip4.sin_port = htons(port); break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6: us->ip6.sin6_port = htons(port); break;
#endif /* WITH_IP6 */
default: Error("unsupported protocol family");
}
*needbind = true;
}
retropt_bool(opts, OPT_LOWPORT, lowport);
*opts0 = copyopts(opts, GROUP_ALL);
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_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;
*opts = copyopts(opts0, GROUP_ALL);
if (hostname != NULL || portname != NULL) {
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));
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));
errno = 0; /* unspecified */
return STAT_NORETRY; /*! STAT_RETRYLATER? */
}
}
applyopts(NULL, -1, *opts, PH_EARLY);
/* 3 means: IP address AND port accepted */
if (retropt_bind_ip(*opts, pf, socktype, protocol, bindarr, 3, ai_flags)
!= STAT_NOACTION) {
*needbind = true;
}
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: ((struct sockaddr_in *)(*bindp)->ai_addr)->sin_port = htons(port); break;
#endif /* WITH_IP4 */
#if WITH_IP6
case PF_INET6: ((struct sockaddr_in6 *)(*bindp)->ai_addr)->sin6_port = htons(port); break;
#endif /* WITH_IP6 */
default:
Error("unsupported protocol family");
errno = EPROTONOSUPPORT;
return STAT_NORETRY;
}
} else {
*bindport = port;
}
*needbind = true;
}
retropt_bool(*opts, OPT_LOWPORT, lowport);
return STAT_OK;
}
#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
@ -311,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))
@ -390,62 +532,6 @@ int xioopen_ipapp_listen(
return result;
return 0;
}
#endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
#endif /* WITH_TCP && WITH_LISTEN */
/* Sort the records of an addrinfo list themp (as returned by getaddrinfo),
return the sorted list in the array ai_sorted (takes at most n entries
including the terminating NULL)
Returns 0 on success. */
int _xio_sort_ip_addresses(
struct addrinfo *themlist,
struct addrinfo **ai_sorted)
{
struct addrinfo *themp;
int i;
int ipv[3];
int ipi = 0;
/* Make a simple array of IP version preferences */
switch (xioparms.preferred_ip) {
case '0':
ipv[0] = PF_UNSPEC;
ipv[1] = -1;
break;
case '4':
ipv[0] = PF_INET;
ipv[1] = PF_INET6;
ipv[2] = -1;
break;
case '6':
ipv[0] = PF_INET6;
ipv[1] = PF_INET;
ipv[2] = -1;
break;
default:
Error("INTERNAL: undefined preferred_ip value");
return -1;
}
/* Create the sorted list */
ipi = 0;
i = 0;
while (ipv[ipi] >= 0) {
themp = themlist;
while (themp != NULL) {
if (ipv[ipi] == PF_UNSPEC) {
ai_sorted[i] = themp;
++i;
} else if (ipv[ipi] == themp->ai_family) {
ai_sorted[i] = themp;
++i;
}
themp = themp->ai_next;
}
++ipi;
}
ai_sorted[i] = NULL;
return 0;
}
#endif /* WITH_TCP || WITH_UDP */
#endif /* WITH_TCP || WITH_UDP || WITH_SCTP || WITH_DCCP || WITH_UDPLITE */

View file

@ -15,13 +15,10 @@ 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 **res, 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);
extern int _xio_sort_ip_addresses(struct addrinfo *themlist, struct addrinfo **ai_sorted);
#endif /* !defined(__xio_ipapp_h_included) */

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,14 +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 *themlist, *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;
struct addrinfo **ai_sorted;
int i;
SSL_CTX* ctx;
bool opt_ver = true; /* verify peer certificate */
char *opt_cert = NULL; /* file name of client certificate */
@ -256,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;
@ -268,21 +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;
}
xioinit_ip(&pf, xioparms.default_ip);
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)
@ -318,86 +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,
&themlist, 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;
/* Count addrinfo entries */
themp = themlist;
i = 0;
while (themp != NULL) {
++i;
themp = themp->ai_next;
}
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
if (ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(themlist, ai_sorted);
Notice2("opening OpenSSL connection to %s:%s", hostname, portname);
do { /* loop over failed connect and SSL handshake attempts */
/* Loop over ai_sorted list */
i = 0;
themp = ai_sorted[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 || ai_sorted[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 = ai_sorted[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;
}
free(ai_sorted);
return STAT_NORETRY;
#endif /* WITH_RETRY */
default:
free(ai_sorted);
return result;
}
/*! isn't this too early? */
if ((result = _xio_openlate(sfd, opts)) < 0) {
free(ai_sorted);
Error4("%s:%s:%s: %s", argv[0], hostname, portname,
_errno?strerror(_errno):"(See above)");
freeopts(opts0);
freeopts(opts);
return result;
}
@ -408,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(themlist);
return STAT_NORETRY;
freeopts(opts);
freeopts(opts0);
return result;
}
if (dofork) {
@ -435,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(themlist);
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;
}
@ -453,22 +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 */
free(ai_sorted);
xiofreeaddrinfo(themlist);
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;
}
@ -718,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;
@ -780,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));*/
@ -809,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)
@ -1121,7 +1118,7 @@ int
#elif HAVE_DTLSv1_client_method
method = sycDTLSv1_client_method();
#else
# error "OpenSSL does not seem to provide DTLS client methods"
# warning "OpenSSL does not seem to provide DTLS client methods"
#endif
*use_dtls = true;
}
@ -1192,12 +1189,17 @@ int
#elif HAVE_DTLSv1_server_method
method = sycDTLSv1_server_method();
#else
# error "OpenSSL does not seem to provide DTLS server methods"
# warning "OpenSSL does not seem to provide DTLS server methods"
#endif
*use_dtls = true;
}
}
if (method == NULL) {
Error("no OpenSSL method available");
return STAT_NORETRY;
}
if (opt_egd) {
#if !defined(OPENSSL_NO_EGD) && HAVE_RAND_egd
sycRAND_egd(opt_egd);
@ -1467,7 +1469,10 @@ cont_out:
sycSSL_CTX_set_verify(ctx,
SSL_VERIFY_PEER| SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
Warn("OpenSSL: Warning: this implementation does not check CRLs");
if (first_child) {
/* The first forked off process, print the warning only once */
Warn("OpenSSL: Warning: this implementation does not check CRLs");
}
} else {
sycSSL_CTX_set_verify(ctx,
SSL_VERIFY_NONE,
@ -1984,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) {
@ -2013,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));
}
}
@ -2045,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;
@ -2080,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));
}
}
@ -2106,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;
@ -2139,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
@ -56,7 +57,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
struct opt *popts = NULL; /* parent options */
struct opt *copts; /* child options */
int numleft;
int d, sv[2], rdpip[2], wrpip[2];
int sv[2], rdpip[2], wrpip[2];
int rw = (xioflags & XIO_ACCMODE);
bool usepipes = false;
#if HAVE_PTY
@ -355,10 +356,11 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
/* end withfork, use_pipes */
} else {
/* withfork, socketpair */
int pf;
d = AF_UNIX;
retropt_int(opts, OPT_PROTOCOL_FAMILY, &d);
result = xiosocketpair(opts, d, SOCK_STREAM, 0, sv);
pf = AF_UNIX;
retropt_socket_pf(opts, &pf);
result = xiosocketpair(opts, pf, SOCK_STREAM, 0, sv);
if (result < 0) {
return -1;
}
@ -622,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,19 +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 *themlist, *themp;
struct addrinfo **ai_sorted;
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;
@ -113,104 +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,
&themlist, us, &uslen,
&needbind, &lowport, socktype);
result =
_xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
/* Count addrinfo entries */
themp = themlist;
i = 0;
while (themp != NULL) {
++i;
themp = themp->ai_next;
}
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
if (ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(themlist, ai_sorted);
result = _xioopen_proxy_init(proxyvars, opts, targetname, targetport);
if (result != STAT_OK)
return result;
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;
/* Loop over themlist */
i = 0;
themp = ai_sorted[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 || ai_sorted[i] != NULL) {
level = E_INFO;
} 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_TCP, lowport, level);
if (result == STAT_OK)
break;
themp = ai_sorted[i++];
if (themp == NULL) {
result = STAT_RETRYLATER;
}
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:
free(ai_sorted);
xiofreeaddrinfo(themlist);
/* FALLTHROUGH */
case STAT_NORETRY:
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
}
xiofreeaddrinfo(themlist);
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) {
@ -219,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;
}
@ -240,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 */
@ -263,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);
@ -331,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
@ -340,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) {
@ -352,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));
@ -391,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) {
@ -421,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) {
@ -434,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

@ -66,7 +66,6 @@ static int xioopen_rawip_sendto(
return STAT_NORETRY;
}
xioinit_ip(&pf, xioparms.preferred_ip);
if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
addrdesc->groups, &pf)) != STAT_OK) {
return result;
@ -108,7 +107,7 @@ int _xioopen_rawip_sendto(const char *hostname, const char *protname,
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_SHUTDOWN;
retropt_int(opts, OPT_PROTOCOL_FAMILY, pf);
retropt_socket_pf(opts, pf);
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
applyopts(sfd, -1, opts, PH_INIT);
@ -159,7 +158,6 @@ static int xioopen_rawip_datagram(
return STAT_NORETRY;
}
xioinit_ip(&pf, xioparms.preferred_ip);
if ((result =
_xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
addrdesc->groups, &pf)) != STAT_OK) {

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);
@ -1362,6 +1394,7 @@ int _xioopen_dgram_recvfrom(struct single *sfd, int xioflags,
char buf[1];
while (Read(trigger[0], buf, 1) < 0 && errno == EINTR) ;
}
Close(trigger[0]);
Info("continue listening");
} else {
@ -1423,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)
@ -1433,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);
@ -1448,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;
@ -1459,15 +1497,13 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
} else if (!strcasecmp("inet", pfname) ||
!strcasecmp("inet4", pfname) ||
!strcasecmp("ip4", pfname) ||
!strcasecmp("ipv4", pfname) ||
!strcasecmp("2", pfname)) {
!strcasecmp("ipv4", pfname)) {
*pf = PF_INET;
#endif /* WITH_IP4 */
#if WITH_IP6
} else if (!strcasecmp("inet6", pfname) ||
!strcasecmp("ip6", pfname) ||
!strcasecmp("ipv6", pfname) ||
!strcasecmp("10", pfname)) {
!strcasecmp("ipv6", pfname)) {
*pf = PF_INET6;
#endif /* WITH_IP6 */
} else {
@ -1479,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.
@ -1652,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) {
@ -1737,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
@ -1958,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:
@ -2056,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);
@ -2081,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
@ -2107,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,
@ -2143,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));
@ -2168,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 {
@ -2182,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);
@ -2207,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);
@ -2253,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 {
@ -2267,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);
@ -2279,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.
*/
@ -2304,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) {
@ -2325,3 +2368,6 @@ int xiosock_reuseaddr(int fd, int ipproto, struct opt *opts)
}
return 0;
}
#endif /* _WITH_SOCKET */

View file

@ -6,14 +6,19 @@
#define __xio_socket_h_included 1
/* SO_PROTOTYPE is defined on Solaris, HP-UX
SO_PROTOCOL in Linux, is the better name, but came much later */
SO_PROTOCOL in Linux, is the better name, but came much later, now
standardised in POSIX 2024
illumos defines both, with SO_PROTOCOL as an alias of SO_PROTOTYPE */
#ifdef SO_PROTOCOL
# undef SO_PROTOTYPE
# ifndef SO_PROTOTYPE
# define SO_PROTOTYPE SO_PROTOCOL
# endif
#else
# ifdef SO_PROTOTYPE
# define SO_PROTOCOL SO_PROTOTYPE
# else
/* Even when SO_PROTOCOL is not available for setsockopt() Socat uses it
internally as option for 3rd arg of socket() e.a. */
# define SO_PROTOCOL 0x9999
# define SO_PROTOTYPE SO_PROTOCOL
# endif
@ -78,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
@ -130,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

@ -7,6 +7,7 @@
#include "xiosysincludes.h"
#include "xioopen.h"
#include "xio-socket.h"
#include "xio-named.h"
#include "xio-socketpair.h"
@ -44,7 +45,7 @@ static int xioopen_socketpair(
sfd->para.bipipe.socktype = SOCK_DGRAM;
if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
applyopts(sfd, -1, opts, PH_INIT);
retropt_int(opts, OPT_PROTOCOL_FAMILY, &pf);
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_TYPE, &sfd->para.bipipe.socktype);
retropt_int(opts, OPT_SO_PROTOTYPE, &protocol);
@ -94,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,17 +26,16 @@ 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);
const struct optdesc opt_socksport = { "socksport", NULL, OPT_SOCKSPORT, GROUP_IP_SOCKS4, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_socksuser = { "socksuser", NULL, OPT_SOCKSUSER, GROUP_IP_SOCKS4, PH_LATE, TYPE_NAME, OFUNC_SPEC };
const struct optdesc opt_socksport = { "socksport", NULL, OPT_SOCKSPORT, GROUP_IP_SOCKS, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_socksuser = { "socksuser", NULL, OPT_SOCKSUSER, GROUP_IP_SOCKS, PH_LATE, TYPE_NAME, OFUNC_SPEC };
const struct addrdesc xioaddr_socks4_connect = { "SOCKS4", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") };
const struct addrdesc xioaddr_socks4_connect = { "SOCKS4", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<socks-server>:<host>:<port>") };
const struct addrdesc xioaddr_socks4a_connect = { "SOCKS4A", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS4|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") };
const struct addrdesc xioaddr_socks4a_connect = { "SOCKS4A", 3, xioopen_socks4_connect, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_IP_TCP|GROUP_IP_SOCKS|GROUP_CHILD|GROUP_RETRY, 1, 0, 0 HELP(":<socks-server>:<host>:<port>") };
static int xioopen_socks4_connect(
int argc,
@ -53,14 +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 *themlist, *themp;
struct addrinfo **ai_sorted;
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);
@ -76,54 +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,
&themlist, us, &uslen,
&needbind, &lowport, socktype);
/* Count addrinfo entries */
themp = themlist;
i = 0;
while (themp != NULL) {
++i;
themp = themp->ai_next;
}
ai_sorted = Calloc((i+1), sizeof(struct addrinfo *));
if (ai_sorted == NULL)
return STAT_RETRYLATER;
/* Generate a list of addresses sorted by preferred ip version */
_xio_sort_ip_addresses(themlist, ai_sorted);
/* 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
@ -132,61 +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 themlist */
i = 0;
themp = ai_sorted[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 || ai_sorted[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 = ai_sorted[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:
free(ai_sorted);
xiofreeaddrinfo(themlist);
if (bindarr != NULL) xiofreeaddrinfo(bindarr);
xiofreeaddrinfo(themarr);
freeopts(opts);
freeopts(opts0);
return result;
}
xiofreeaddrinfo(themlist);
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) {
@ -195,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;
}
@ -216,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;
}
@ -231,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 */
@ -241,12 +259,54 @@ static int xioopen_socks4_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:%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,
char **socksport)
{
struct servent *se;
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) {
return STAT_NORETRY;
}
sprintf(*socksport, "%u", ntohs(se->s_port));
} else {
Debug1("cannot resolve service \"socks/tcp\", using %s", SOCKSPORT);
if ((*socksport = strdup(SOCKSPORT)) == NULL) {
return STAT_NORETRY;
}
}
}
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) {
struct servent *se;
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 */
@ -254,20 +314,8 @@ int _xioopen_socks4_prepare(const char *targetport, struct opt *opts, char **soc
sockhead->action = 1;
sockhead->port = parseport(targetport, IPPROTO_TCP); /* network byte
order */
if (retropt_string(opts, OPT_SOCKSPORT, socksport) < 0) {
if ((se = getservbyname("socks", "tcp")) != NULL) {
Debug1("\"socks/tcp\" resolves to %u", ntohs(se->s_port));
if ((*socksport = Malloc(6)) == NULL) {
return -1;
}
sprintf(*socksport, "%u", ntohs(se->s_port));
} else {
Debug1("cannot resolve service \"socks/tcp\", using %s", SOCKSPORT);
if ((*socksport = strdup(SOCKSPORT)) == NULL) {
errno = ENOMEM; return -1;
}
}
if (_xioopen_opt_socksport(opts, socksport) < 0) {
return STAT_NORETRY;
}
if (retropt_string(opts, OPT_SOCKSUSER, &userid) < 0) {
@ -284,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) {
@ -368,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) {
@ -433,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;
@ -20,15 +20,9 @@ extern const struct optdesc opt_socksuser;
extern const struct addrdesc xioaddr_socks4_connect;
extern const struct addrdesc xioaddr_socks4a_connect;
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_opt_socksport(struct opt *opts, char **socksport);
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

@ -19,6 +19,7 @@
#include "xio-socket.h"
#include "xio-ip.h"
#include "xio-ipapp.h"
#include "xio-socks.h" /* _xioopen_opt_socksport() */
#include "xio-socks5.h"
@ -50,9 +51,9 @@
static int xioopen_socks5(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, const struct addrdesc *addrdesc);
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_CHILD|GROUP_RETRY, SOCKS5_COMMAND_CONNECT, 0, 0 HELP(":<socks-server>:<socks-port>:<target-host>:<target-port>") };
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)
{
@ -135,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));
@ -187,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);
@ -331,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
@ -417,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) {
@ -503,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;
@ -510,91 +520,137 @@ 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 *themlist, *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 != 5) {
if (argc < 4 || argc > 5) {
xio_syntax(argv[0], 4, argc-1, addrdesc->syntax);
return STAT_NORETRY;
}
socks_server = argv[1];
socks_port = argv[2];
target_name = argv[3];
target_port = argv[4];
if (argc == 5) {
socks_port = argv[2];
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);
/* Apply and retrieve some options */
result = _xioopen_ipapp_init(sfd, xioflags, opts,
&dofork, &maxchildren,
&pf, &socktype, &ipproto);
if (result != STAT_OK)
return result;
retropt_int(opts, OPT_SO_TYPE, &socktype);
retropt_bool(opts, OPT_FORK, &dofork);
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,
&themlist, 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 themlist */
themp = themlist;
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:
xiofreeaddrinfo(themlist);
return result;
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;
}
}
xiofreeaddrinfo(themlist);
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;
}
@ -606,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;
}
@ -626,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;
@ -640,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);
@ -286,21 +288,8 @@ int xioopen_ipdgram_listen(
}
xioinit_ip(&pf, xioparms.default_ip);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
retropt_socket_pf(opts, &pf);
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
if (applyopts_single(sfd, opts, PH_INIT) < 0)
@ -308,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);
@ -362,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,
@ -460,6 +468,7 @@ int xioopen_udp_datagram(
sfd->para.socket.ip.dosourceport = true;
}
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf);
result =
@ -535,25 +544,13 @@ int xioopen_udp_recvfrom(
}
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf);
sfd->howtoend = END_NONE;
if (sfd->howtoend == END_UNSPEC)
sfd->howtoend = END_NONE;
retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
/* 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))
@ -626,22 +623,10 @@ int xioopen_udp_recv(
return STAT_NORETRY;
}
xioinit_ip(&pf, xioparms.default_ip);
retropt_socket_pf(opts, &pf);
if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
switch (xioparms.default_ip) {
case '4': pf = PF_INET; break;
case '6': pf = PF_INET6; break;
default: break; /* includes \0 */
}
#elif WITH_IP6
pf = PF_INET6;
#else
pf = PF_INET;
#endif
}
/* 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))
@ -682,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)

4
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;
@ -471,6 +472,7 @@ extern const char *PIPESEP;
extern xiofile_t *sock[XIO_MAXSOCK];
extern int num_child;
extern bool first_child;
/* return values of xioopensingle */
#define STAT_OK 0

View file

@ -23,6 +23,21 @@ int xioclose1(struct single *pipe) {
return -1;
}
if (pipe->tag == XIO_TAG_CLOSED) {
return 0;
}
pipe->tag |= XIO_TAG_CLOSED;
if (pipe->dtype & XIOREAD_RECV_ONESHOT) {
if (pipe->triggerfd >= 0) {
char r[1];
Info("consuming packet to prevent loop in parent");
Read(pipe->fd, r, sizeof(r));
Close(pipe->triggerfd);
pipe->triggerfd = -1;
}
}
#if WITH_READLINE
if ((pipe->dtype & XIODATA_MASK) == XIODATA_READLINE) {
Write_history(pipe->para.readline.history_file);
@ -112,7 +127,6 @@ int xioclose1(struct single *pipe) {
free(pipe->unlink_close);
}
pipe->tag |= XIO_TAG_CLOSED;
return 0; /*! */
}
@ -126,11 +140,14 @@ int xioclose(xiofile_t *file) {
errno = EINVAL;
return -1;
}
if (file->tag == XIO_TAG_CLOSED) {
return 0;
}
if (file->tag == XIO_TAG_DUAL) {
file->tag |= XIO_TAG_CLOSED;
result = xioclose1(file->dual.stream[0]);
result |= xioclose1(file->dual.stream[1]);
file->tag |= XIO_TAG_CLOSED;
} else {
result = xioclose1(&file->stream);
}

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

@ -46,14 +46,14 @@ static const char *addressgroupnames[] = {
"LISTEN", "SHELL", "CHILD", "RETRY",
"TERMIOS", "RANGE", "PTY", "PARENT",
"UNIX", "IP4", "IP6", "INTERFACE",
"UDP", "TCP", "SOCKS4", "OPENSSL",
"UDP", "TCP", "SOCKS", "OPENSSL",
"PROCESS", "APPL", "HTTP", "undef",
"POSIXMQ", "SCTP", "DCCP", "UDPLITE"
} ;
/* 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

@ -15,7 +15,8 @@ static int xioinitialized;
xiofile_t *sock[XIO_MAXSOCK];
int (*xiohook_newchild)(void); /* xio calls this function from a new child
process */
int num_child = 0;
int num_child = 0; /* actual number of "general" child processes */
bool first_child = true; /* only first child shall print general warnings */
/* returns 0 on success or != if an error occurred */
int xioinitialize(void) {
@ -174,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;
@ -255,9 +256,12 @@ pid_t xio_fork(bool subchild,
return 0;
}
num_child++;
Info1("number of children increased to %d", num_child);
/* parent process */
if (!subchild) {
++num_child;
first_child = false;
}
Info1("number of children increased to %d", num_child);
Notice1("forked off child process "F_pid, pid);
/* gdb recommends to have env controlled sleep after fork */
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {

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) {

177
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 */
@ -199,6 +199,9 @@ const struct optname optionnames[] = {
#if defined(AI_ADDRCONFIG)
IF_IP ("ai-addrconfig", &opt_ai_addrconfig)
#endif
#if defined(AI_ALL)
IF_IP ("ai-all", &opt_ai_all)
#endif
#if defined(AI_PASSIVE )
IF_IP ("ai-passive", &opt_ai_passive)
#endif
@ -349,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)
@ -387,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)
@ -418,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
@ -451,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
@ -718,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)
@ -1029,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)
@ -1047,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)
@ -1115,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
@ -1129,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
@ -1188,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
@ -1345,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
@ -1408,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
@ -1448,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
@ -1477,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
@ -1573,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)
@ -1709,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)
@ -1721,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)
@ -1927,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)
@ -2651,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;
@ -2765,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;
}
@ -2901,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) {
@ -3097,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)
{
@ -3247,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
@ -3271,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);
@ -3286,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
@ -3320,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,
@ -3334,8 +3356,10 @@ 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 */
#endif /* WITH_IP4 || WITH_IP6 || WITH_VSOCK */
#if WITH_UNIX
case AF_UNIX:
@ -3364,6 +3388,52 @@ int retropt_bind(struct opt *opts,
}
return STAT_OK;
}
#if 0
#if _WITH_IP4 || _WITH_IP6
/* Looks for a bind option and, if found, calls xiogetaddrinfo and provides the
results list in bindlist.
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_gai(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])
{
if (retropt_string(opts, OPT_BIND, &bindname) < 0) {
return STAT_NOACTION;
}
bindp = bindname;
switch (af) {
#if WITH_IP4 || WITH_IP6
case AF_UNSPEC:
#if WITH_IP4
case AF_INET:
#endif
#if WITH_IP6
case AF_INET6:
#endif /*WITH_IP6 */
break;
#endif /* WITH_IP4 || WITH_IP6 */
default:
Error1("bind: unknown address family %d", af);
return STAT_NORETRY;
}
return STAT_OK;
}
#endif /* _WITH_IP4 || _WITH_IP6 */
#endif /* 0 */
#endif /* _WITH_SOCKET */
@ -3518,6 +3588,8 @@ int applyopt_ioctl_generic(
return 0;
}
#if _WITH_SOCKET
int applyopt_sockopt(
int fd,
struct opt *opt)
@ -3646,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;
@ -3766,6 +3838,9 @@ int applyopt_sockopt_generic(
return 0;
}
#endif /* _WITH_SOCKET */
#if HAVE_FLOCK
int applyopt_flock(
int fd,
struct opt *opt)
@ -3777,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,
@ -3872,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) {
@ -4041,6 +4121,7 @@ int applyopt_spec(
return 0;
}
#if WITH_TERMIOS
int applyopts_termios_value(
int fd,
struct opt *opt)
@ -4057,6 +4138,7 @@ int applyopts_termios_value(
}
return 0;
}
#endif /* WITH_TERMIOS */
/* Note: not all options can be applied this way (e.g. OFUNC_SPEC with PH_OPEN)
implemented are: OFUNC_FCNTL, OFUNC_SOCKOPT (probably not all types),
@ -4165,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));
@ -4191,7 +4273,8 @@ int applyopts_fchown(int fd, struct opt *opts) {
return 0;
}
/* caller must make sure that option is not yet consumed */
/* Offset means a position in the sfd record where value is written.
Caller must make sure that option is not yet consumed */
static int applyopt_offset(struct single *sfd, struct opt *opt) {
unsigned char *ptr;
@ -4220,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;
@ -4229,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));
@ -4612,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
@ -182,7 +182,7 @@ enum e_func {
#define GROUP_IP_UDP 0x01000000 /* not yet used? */
#define GROUP_IP_TCP 0x02000000
#define GROUP_IP_SOCKS4 0x04000000
#define GROUP_IP_SOCKS 0x04000000 /* for socks4(a), socks5 */
#define GROUP_OPENSSL 0x08000000
#define GROUP_PROCESS 0x10000000 /* a process related option */
@ -216,6 +216,7 @@ enum e_func {
enum e_optcode {
OPT_ADDRESS_FAMILY = 1,
OPT_AI_ADDRCONFIG, /* getaddrinfo() */
OPT_AI_ALL, /* getaddrinfo() */
OPT_AI_PASSIVE, /* getaddrinfo() */
OPT_AI_V4MAPPED, /* getaddrinfo() */
/* these are not alphabetically, I know... */
@ -271,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 */
@ -481,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
@ -551,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
@ -659,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,
@ -1027,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

@ -113,7 +113,7 @@ void childdied(int signum) {
}
/*! indent */
if (num_child) {
num_child--;
--num_child;
Info1("number of children decreased to %d", num_child);
}
/* check if it was a registered child process */

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) {